From 8f631da7634fc7b3d4a1cd95935d85ed01829f6d Mon Sep 17 00:00:00 2001 From: zTz01 <1773266173@qq.com> Date: Wed, 8 Jul 2026 10:59:46 +0800 Subject: [PATCH 01/10] feat(kv): add Fluxon KV integration for SGLang --- ...06\346\210\220\350\256\276\350\256\241.md" | 381 ++ fluxon_py/kvclient/fluxon.py | 898 ++++- fluxon_py/kvclient/kvclient_interface.py | 148 +- .../src/facade/transfer_engine.rs | 18 +- .../src/lib.rs | 53 +- fluxon_rs/fluxon_fs/src/agent.rs | 19 +- .../src/agent_service/transfer_agent.rs | 1662 +++++---- fluxon_rs/fluxon_fs/src/cache_controller.rs | 2 +- fluxon_rs/fluxon_fs_s3_gateway/src/lib.rs | 5 +- .../fluxon_kv/src/client_kv_api/delete.rs | 100 +- .../src/client_kv_api/external_api.rs | 2110 ++++++++++- fluxon_rs/fluxon_kv/src/client_kv_api/get.rs | 791 +++- .../client_kv_api/local_reserve_rebalance.rs | 308 ++ fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs | 1407 ++++++- .../fluxon_kv/src/client_kv_api/msg_pack.rs | 413 +- fluxon_rs/fluxon_kv/src/client_kv_api/put.rs | 1666 ++++++++- .../fluxon_kv/src/client_seg_pool/mod.rs | 19 +- fluxon_rs/fluxon_kv/src/config.rs | 73 +- .../fluxon_kv/src/external_client_api/mod.rs | 1776 +++++++-- fluxon_rs/fluxon_kv/src/kv_test.rs | 36 +- fluxon_rs/fluxon_kv/src/lib.rs | 56 +- .../fluxon_kv/src/master_kv_router/delete.rs | 5 +- .../fluxon_kv/src/master_kv_router/get.rs | 254 +- .../fluxon_kv/src/master_kv_router/mod.rs | 699 +++- .../src/master_kv_router/msg_pack.rs | 477 ++- .../src/master_kv_router/placement.rs | 6 +- .../fluxon_kv/src/master_kv_router/put.rs | 1397 ++++++- .../lease_manager_test.rs | 82 +- fluxon_rs/fluxon_kv/src/memholder/lifetime.rs | 22 +- fluxon_rs/fluxon_kv/src/memholder/mod.rs | 112 +- fluxon_rs/fluxon_kv/src/metrics.rs | 195 +- fluxon_rs/fluxon_kv/src/observe_kvope.rs | 1 + .../rpcresp_kvresult_convert/msg_and_error.rs | 33 + .../rpcresp_kvresult_convert.rs | 251 +- fluxon_rs/fluxon_ops/build.rs | 20 +- fluxon_rs/fluxon_ops/src/lib.rs | 433 ++- fluxon_rs/fluxon_pyo3/src/error.rs | 25 +- fluxon_rs/fluxon_pyo3/src/lib.rs | 3316 ++++++++++++++++- fluxon_rs/fluxon_util/src/dev_config.rs | 2 +- fluxon_rs/fluxon_util/src/lib.rs | 14 +- fluxon_rs/fluxon_util/src/log.rs | 46 +- fluxon_rs/fluxon_util/tests/log_mgmt.rs | 12 +- 42 files changed, 17235 insertions(+), 2108 deletions(-) create mode 100644 "fluxon_doc_cn/design/sglang_fluxon_kv\351\233\206\346\210\220\350\256\276\350\256\241.md" create mode 100644 fluxon_rs/fluxon_kv/src/client_kv_api/local_reserve_rebalance.rs diff --git "a/fluxon_doc_cn/design/sglang_fluxon_kv\351\233\206\346\210\220\350\256\276\350\256\241.md" "b/fluxon_doc_cn/design/sglang_fluxon_kv\351\233\206\346\210\220\350\256\276\350\256\241.md" new file mode 100644 index 0000000..8a0dc6d --- /dev/null +++ "b/fluxon_doc_cn/design/sglang_fluxon_kv\351\233\206\346\210\220\350\256\276\350\256\241.md" @@ -0,0 +1,381 @@ +# SGLang Fluxon KV 集成设计 + +## 设计目标 + +本文说明开源仓库中 SGLang HiCache 接入 Fluxon KV 的 hostless 实现设计,聚焦接口契约、状态归属和生命周期边界。本文不是通用 `FlatDict` KV API 的完整说明。 + +当前调用链主要分为三条主线: + +- 写入侧:`local_fast_put_start -> SGLang native write -> local_fast_put_commit`。 +- 读取侧:`get_start -> get_transfer -> SGLang native restore -> release_views`。 +- 放弃读取侧 restore 时:`cancel_get_transfer` 释放 `get_start` 持有的资源。 + +Fluxon 仍然按 key 保存 opaque value bytes。SGLang 负责 page key、page layout、MHA/MLA/Mamba value 内部格式、GPU KV cache index 和 native kernel 调度;Fluxon 负责 key-version 路由、put 准入与 reservation、owner-local reserve、host value 地址、holder 生命周期和跨 owner 数据面。 + +这个集成把 SGLang 逻辑上的 L2/L3 缓存落到 Fluxon 统一管理的本机/远端 KV 层中。这样可以用同一套 owner、holder、commit/release 语义管理 KV page,减少传统 L2 host cache 与 L3 backend 分属不同系统时产生的同机重复缓存和生命周期割裂。 + +常见部署下,一台机器启动一个 Fluxon owner;同机多个 GPU 对应的多个 SGLang worker 进程通过 external/client attach 到同一个 owner shared segment。相比一个 SGLang 进程一个后端 segment、进程间不共享后端 segment 的形态,Fluxon 把同机 host/shared memory、owner local reserve slots 和 holder 生命周期放到同一个 owner 生命周期模型里。这样多个 SGLang worker 可以通过同一个 owner segment 获得本机快速可见性和受控的本地可写内存供给,减少各进程为了各自安全边界重复持有 KV、固定预留 segment 或独立维护 pin/release 状态带来的浪费。 + +## 范围边界 + +| 范围 | 当前结论 | +| --- | --- | +| SGLang hostless 写入 | 已接入。SGLang 通过 `local_fast_put_start` 取得一批可写 host value 地址,native kernel 写入后再调用 `local_fast_put_commit` 提交。 | +| SGLang hostless 读取 | 使用 `get_start/get_transfer/release_views`。`get_start` 先计算连续可恢复前缀,`get_transfer` 再把可恢复前缀转换成 readable `plan_ptr`。 | +| Fluxon value layout | Fluxon 不理解 KV page 内部布局;只按 `key + value_len` 管理连续字节。 | +| SGLang node 状态 | SGLang 的 `storage_*` 字段是调度层状态,不等同于 Fluxon master route;跨节点复用以 Fluxon commit future 成功为准。 | + +## 总体架构 + +```mermaid +flowchart LR + A["SGLang HiCache radix node"] --> B["HiCacheFluxon backend"] + B --> C["FluxonKVCacheStore"] + C --> D["fluxon_pyo3::KvClient"] + D --> E["Fluxon external / owner"] + E --> F["Fluxon master"] + + B --> G["sgl-kernel kvcacheio"] + D --> H["plan_ptr blob
magic/count/value_ptrs"] + H --> G + G --> I["GPU KV cache"] + E --> J["owner shared segment
local reserve slots / MemHolder"] + J --> H +``` + +这里有两个层次: + +- KV 语义层:SGLang 传入 page key,Fluxon 对外保存 `key -> value`。 +- hostless 数据层:Fluxon 返回 `plan_ptr`,SGLang native kernel 根据 blob 里的 `value_ptrs[]` 直接执行 GPU/host 数据传输。 + +从缓存物理层级看,Fluxon 把传统 L2/L3 逻辑抽象落到 local side / remote side:local side 覆盖本机 GPU KV、owner shared segment、owner local reserve slots 和 `MemHolder`;remote side 覆盖跨 owner 或跨机器的数据面。多个 SGLang worker attach 到同一个 owner segment 时,同机 KV bytes 不需要按 worker 进程重复保存在多个后端 segment 中。 + +`plan_ptr` 只是一轮 backup 或 restore 的短生命周期 carrier。它不能作为 key、缓存地址、跨进程句柄或长期状态保存。 + +## 公共契约 + +本节只列 SGLang HiCache hostless 接入 Fluxon KV 时直接依赖的接口。 + +| 接口 | 层级 | 契约 | +| --- | --- | --- | +| `wait_local_segments_ready()` | Fluxon + SGLang 集成 | 返回当前进程可见的 local segment mapping,供 SGLang 做 CUDA host registration。 | +| `local_fast_put_start(keys, value_len, opts)` | SGLang hostless 写入 | 为一批等长 values 准备可写地址,返回 put `plan_ptr`。 | +| `local_fast_put_commit(plan_ptr)` | SGLang hostless 写入 | 在 SGLang native kernel 写完 `value_ptrs[]` 后消费 put plan,把对应 slots 提交为 Fluxon KV route,返回 `KvFuture`。 | +| `put_abort(plan_ptr)` | SGLang hostless 写入 | 在 commit 前释放 put plan、key reservation 和 local reserve slot lease。 | +| `GetStartResult` | SGLang hostless 读取 | 描述连续命中前缀、可传输长度、atomic group 命中数和第一个 miss 位置。 | +| `GetStartHandle` | SGLang hostless 读取 | 持有一次 get-start 结果和 backend handle;必须被 `get_transfer` 消费或被 `cancel_get_transfer` 取消。 | +| `get_start(keys, prefix_best_effort, atomic_group_lens)` | SGLang hostless 读取 | 按 key 顺序计算连续命中的 prefix,并返回 `GetStartHandle`。 | +| `get_transfer(handle)` | SGLang hostless 读取 | 消费 handle 的可传输前缀,执行必要 transfer,并返回 readable `plan_ptr`。 | +| `cancel_get_transfer(handle)` | SGLang hostless 读取 | 放弃未 transfer 的 `GetStartHandle`,释放 get-start 期间持有的 owner/external 资源。 | +| `release_views(plan_ptr)` | SGLang hostless 读取 | 释放 get-transfer 产生的 readable plan,丢弃其持有的 holder 引用。 | + +`PutOptionalArgs` 在 SGLang hostless 写入路径中的语义如下: + +| 字段 | SGLang 使用方式 | +| --- | --- | +| `reject_if_inflight_same_key` | 固定开启,避免同一 page key 并发写回造成重复 inflight put。 | +| `reject_if_exist_same_key` | 固定开启,SGLang 把重复 key 当作已写回或冲突重试处理。 | +| `write_through` | 当前配置决定提交策略;调用方显式传入时 Fluxon 必须按字段语义执行。 | +| `lease_id` | 当前 SGLang hostless 主线不依赖 lease。 | + +## Key 与组件命名 + +SGLang 传给 Fluxon 的 key 必须先经过 backend namespace 处理: + +```text +storage_key = key_prefix + ":" + logical_key +logical_key = page_hash + optional_component_suffix + config_suffix + optional_extra_backend_tag +``` + +规则: + +- page hash 是 SGLang prefix 复用和 Fluxon KV 存取的共同语义 ID。 +- `PoolName.KV` 使用默认 component;Mamba 等额外 component 通过 suffix 区分。 +- `config_suffix` 编入模型名、TP/PP 等会影响 page layout 的维度,避免不同运行配置复用同一批 physical values。 +- `extra_backend_tag` 用于同一集群内隔离实验或实例,不改变 Fluxon KV 的值格式。 + +Fluxon 只看最终 `storage_key`。page 内部如何拆成 K/V layer、MLA tensor 或 Mamba state,由 SGLang kernel 参数解释。 + +## Segment Registration + +hostless 读写依赖 SGLang 进程可访问的 Fluxon owner segment 已经完成 CUDA host registration。 + +常见部署中,同一台机器上的多个 SGLang worker 连接同一个 Fluxon owner,并映射同一个 owner shared segment。每个 SGLang 进程仍需要在自己的 CUDA context 中完成 host registration;底层内存归属、holder 引用和回收由 owner 统一管理。 + +```mermaid +sequenceDiagram + participant S as SGLang HiCache + participant B as HiCacheFluxon + participant P as Fluxon Python store + participant R as fluxon_pyo3 + participant O as owner segment mapping + participant C as CUDA runtime + + S->>B: register_mem_pool_host / register_mem_host_pool_v2 + B->>P: wait_local_segments_ready() + P->>R: wait_local_segments_ready() + R->>O: wait mapped range + O-->>R: segment_label, write_ptr, read_ptr, len, generation + R-->>P: segment list + P-->>B: dict list + B->>C: cudaHostRegister(write_ptr/read_ptr, len) +``` + +`wait_local_segments_ready()` 返回的 item 至少包含: + +| 字段 | 含义 | +| --- | --- | +| `segment_label` | owner 本地一般为 `cpu:0`;external attach owner 时为 `external_owner:0`。 | +| `write_ptr` | 当前进程可写映射地址。 | +| `read_ptr` | 当前进程可读映射地址,存在时也可注册。 | +| `len` | 映射长度。 | +| `generation` | owner 启动代际,用于拒绝过期 holder 或 mapping。 | +| `node_id` | segment 所属 Fluxon node。 | + +SGLang external-client 模式要求看到 `external_owner:*` segment。注册失败时必须同步报错,不能退回到未注册 host memory 的 direct H2D path。 + +## Plan Blob ABI + +`plan_ptr` 是 Fluxon 返回给 SGLang 的临时句柄,本质上是一段 plan blob 的首地址。SGLang native kernel 通过 `plan_ptr` 找到 blob,再从 blob 里读取本次 batch 对应的 value 地址表。 + +plan blob 是 Fluxon 在 `local_fast_put_start(...)` 或 `get_transfer(...)` 时创建的一段连续 host memory,格式固定: + +```c +uint64_t magic; // 固定校验值,确认 plan_ptr 指向 Fluxon plan blob +uint64_t count; // value_ptrs 的数量,也就是本次 batch 的 page 数 +uint64_t value_ptrs[count]; // 每个 page 对应的 Fluxon value 起始地址 +``` + +如果 SGLang 一次写入或恢复 10 个 page,Fluxon 会创建一个 blob,并返回一个 `plan_ptr`: + +```text +plan_ptr -> blob 起始地址 + +blob[0] = magic +blob[1] = 10 +blob[2] = value_ptr_0 +blob[3] = value_ptr_1 +... +blob[11] = value_ptr_9 +``` + +`magic` 不是 KV value 地址,只是固定校验值;`value_ptr_0 ... value_ptr_9` 才是 Fluxon 为这些 page 准备的 value 起始地址。它们是当前进程可访问的绝对地址,不是偏移量。 + +`value_len` 不写入 blob。Fluxon 只负责按 `value_len` 分配每个 value 的连续字节区间,并把起始地址放进 `value_ptrs[]`;每个 value 内部如何切成 K/V、layer、MLA 或 Mamba state,由 SGLang 调用 write/restore kernel 时显式传入 layout 参数。 + +`plan_ptr` 只在当前进程、当前 batch 生命周期内有效。`local_fast_put_commit(plan_ptr)`、`put_abort(plan_ptr)` 或 `release_views(plan_ptr)` 后,Fluxon 会清理对应 plan,SGLang 不能继续使用这个 `plan_ptr`。 + +## Backup 时序 + +hostless backup 的核心约束是:Fluxon 负责 GPU KV cache 之下的本机/远端 KV 层的地址分配、route 提交和生命周期管理,但真正的 KV bytes 由 SGLang native kernel 从 GPU KV cache 写入。因此 Fluxon 不能在收到 key 后立刻发布 KV route;它必须先完成 key reservation、put id 分配和 owner-local reserve slot claim,把稳定可写的 `value_ptrs[]` 通过 `plan_ptr` 返回给 SGLang。SGLang native kernel 写完这些地址后,`local_fast_put_commit` 才能把这些 slots 提交为 resident values,并发布 Fluxon KV route。 + +这条写路径拆成两个 Fluxon API 阶段: + +1. `local_fast_put_start(keys, value_len)`:只做写入准入、key reservation、put id 分配和可写 value 地址准备,返回 `plan_ptr(value_ptrs)`;此时 value bytes 还没有写完,不能作为可读 KV route 暴露。 +2. `local_fast_put_commit(plan_ptr)`:在 SGLang native kernel 完成写入后消费 put plan,提交 slot / transfer / route,并返回 `KvFuture`;只有 future 成功后,SGLang 才能把 node 标记为 `storage_backed`。 + +写入阶段的拆分主要是为了同时满足两个约束: + +- 数据面效率:SGLang 不需要先把 GPU KV page 包装成通用 KV payload 再交给后端,而是直接用 kernel 写入 Fluxon 返回的 value 地址。 +- 可见性安全:`put_start` 阶段只预留地址,不发布 route;避免其它 get 读到尚未写完或尚未 commit 的 value。 + +```mermaid +sequenceDiagram + participant U as UnifiedRadixCache + participant B as HiCacheFluxon + participant F as Fluxon store + participant K as sgl-kernel + participant O as Fluxon owner + participant M as Fluxon master + + U->>B: local_fast_put_start(missing_keys, value_len) + B->>F: local_fast_put_start(storage_keys, value_len, opts) + F->>O: claim local reserve slots / external owner offsets + O-->>F: plan_ptr(value_ptrs) + B-->>U: plan_ptr + U->>K: write_*_to_fluxon_values(plan_ptr, page_indices, layout ptrs) + K-->>U: writes queued on CUDA stream + U->>U: record local_ready_event + U->>B: local_fast_put_commit(plan_ptr) after event ready + B->>F: local_fast_put_commit(plan_ptr) + F->>O: record precommit visible / transfer_end or put_done + O->>M: commit route + F-->>B: KvFuture + U->>U: scheduler poll future +``` + +hostless backup 默认不依赖 put 前 exists 扫描。重复 key 或在途 key 由 `local_fast_put_start` 的 `reject_if_exist_same_key` 和 `reject_if_inflight_same_key` 准入语义处理;SGLang 上层按冲突错误做重试或跳过。 + +`local_fast_put_start(keys, value_len)` 的要求: + +- `keys` 不能为空。 +- `value_len` 必须大于 0,且同一批 keys 共享同一个 value size。 +- SGLang 必须在 `local_fast_put_commit` 前完成 native write;写入失败时必须调用 `put_abort`。 +- `local_fast_put_commit` 只能调用一次;调用后 plan 从 registry 清理,后续只能等待返回的 `KvFuture`。 + +commit 请求会带上 `len`、`src_offset` 和 target 信息。Fluxon 用这些字段判断本次 value 是否落在当前进程可访问的 owner segment 或 owner-local reserve slot 中;如果需要本地可见索引,`put_done` 会返回 owner 分配的 `local_cache_holder_id`。`MemoryInfo` 和 holder 生命周期在下文说明。 + +## Restore 时序 + +hostless restore 的核心约束是:SGLang 只能恢复有序 page keys 的连续前缀,并且不能切开一个 radix node 对应的 atomic group。Fluxon 需要先在本机/远端 KV 层里判断这批 keys 的可恢复边界,再把真正可恢复的部分转换成 SGLang kernel 可读取的 `plan_ptr(value_ptrs)`。因此 restore 被拆成 `get_start` 和 `get_transfer` 两个阶段。 + +`get_start(keys, prefix_best_effort, atomic_group_lens)` 只做恢复规划:按 key 顺序做 local visible check / owner get start,计算 page 级连续命中前缀 `raw_prefix_hit_len`,再按 `atomic_group_lens` 向下收敛成 `transferable_len`。这个阶段回答“本次最多能恢复多少”,但不要求 SGLang 立刻分配 GPU KV pages,也不暴露 readable plan。 + +`get_transfer(handle)` 在 SGLang 决定恢复后执行:它消费 `get_start` 返回的 handle,等待或完成必要 transfer,只 materialize `keys[..transferable_len]`,并返回持有 holder 引用的 readable `plan_ptr`。随后 SGLang native kernel 使用 `restore_*_from_fluxon_values(...)`,把 Fluxon value memory 拷回 GPU KV cache。 + +读取阶段拆成 planning 和 materialization 两步,主要是为了保证: + +- prefix 安全:中间 page miss 时,只恢复连续命中的完整前缀,不构造带洞的 GPU KV 状态。 +- atomic group 安全:`transferable_len` 不会切开 radix node group,避免恢复半个 node。 +- 资源效率:SGLang 在知道可恢复边界后再分配 GPU KV pages,避免先分配再发现 miss。 +- 生命周期安全:`get_transfer` 返回的 plan 持有 holder 引用,直到 `release_views(plan_ptr)` 后才释放,保证 kernel restore 期间 value 地址稳定。 + +```mermaid +sequenceDiagram + participant U as UnifiedRadixCache + participant B as HiCacheFluxon + participant F as Fluxon store + participant E as external client + participant O as Fluxon owner / external + participant K as sgl-kernel + + U->>B: get_start(page_keys, atomic_group_lens) + B->>F: get_start(storage_keys, prefix_best_effort, atomic_group_lens) + F->>E: batch_get_start(keys) + E->>O: ExternalBatchGetStartReq + O-->>E: handle + raw_prefix_hit_len + E-->>F: backend handle + raw_prefix_hit_len + F->>F: build GetStartResult(raw_prefix_hit_len, transferable_len, ...) + F-->>B: GetStartHandle + GetStartResult + B-->>U: transferable_len / prefix_hit_groups / first_miss_index + alt transferable_len > 0 and caller chooses restore + U->>B: get_transfer(handle) + B->>F: get_transfer(handle) + F->>E: batch_get_transfer(handle, transferable keys) + E->>O: ExternalBatchGetTransferReq + O-->>E: holders / transfer results + E-->>F: plan_ptr(value_ptrs, holders kept alive) + F-->>B: plan_ptr + B-->>U: plan_ptr + U->>K: restore_*_from_fluxon_values(plan_ptr, prefix page indices, layout ptrs) + K-->>U: H2D queued on CUDA stream + U->>B: release_views(plan_ptr) after restore finalizer + else caller gives up restore + U->>B: cancel_get_transfer(handle) + B->>F: cancel_get_transfer(handle) + F->>E: cancel_batch_get_start(handle) + end +``` + +`GetStartResult` 的关键字段如下: + +| 字段 | 含义 | +| --- | --- | +| `raw_prefix_hit_len` | 按 key 顺序连续命中的 page 数,未按 atomic group 收敛。 | +| `transferable_len` | 可以交给 `get_transfer` 的 page 数;它不会切开 atomic group。 | +| `prefix_hit_groups` | 完整命中的 atomic group 数。 | +| `first_miss_index` | 第一个 miss page 的 index;全部命中时为 `None`。 | +| `first_miss_group_index` | 第一个 miss 所在 atomic group;全部命中时为 `None`。 | +| `all_hit` | `transferable_len == len(keys)`。 | + +生命周期规则: + +- `get_start` 成功后,调用方必须二选一:`get_transfer(handle)` 或 `cancel_get_transfer(handle)`。 +- `get_transfer(handle)` 成功后,handle 已被消费;后续由 returned `plan_ptr` 和 `release_views(plan_ptr)` 管理。 +- `release_views(plan_ptr)` 必须在 native restore 完成后执行,即使 native restore 失败也要释放。 +- `get_start` 只命中部分前缀时,SGLang 只能恢复 `transferable_len` 覆盖的完整 atomic groups,不能构造半个 atomic group 的 GPU KV 状态。 +- `get_transfer` 返回 miss / KeyNotFound 时,SGLang 必须放弃本次 restore 并执行 rollback。 + +## Fluxon 本地可见索引与生命周期 + +Fluxon client/external 侧会维护当前进程可直接访问的 value 索引,以及 get/put plan 持有的 holder 引用。SGLang hostless 路径主要涉及下面几类状态: + +| 状态 | 创建入口 | 生命周期 | +| --- | --- | --- | +| precommit local visible | `local_fast_put_commit` 开始后,由 owner-local reserve slot 对应的 `MemoryInfo` 记录到 `precommit_local_visible_info` | 表示本次 put 的 value 已在当前进程可读,但后台 put commit 尚未最终完成;成功后转为 `get_cached_info` 中的 committed entry,失败或取消时移除。 | +| committed local visible info | put commit 成功后,由 SGLang 进程内的 Fluxon external/client 将 `MemoryInfo` 记录到 `get_cached_info` | 保存 key、put version、`holder_id`、`offset`、`len` 和 owner node;后续 `get_start/get_transfer` 可以复用这份 `MemoryInfo` 构造 readable plan。 | +| get-transfer holder | `get_transfer` 成功后绑定到 readable plan,并由 plan 持有引用 | `release_views(plan_ptr)` 后释放引用;plan 生命周期内 holder 保证对应 value 不被释放。 | + +收到 `local_cache_holder_id` 后,SGLang 进程内的 Fluxon external/client 使用 `holder_id`、`offset` 和 `len` 构造 `MemoryInfo`,并记录到自身 `get_cached_info`。`MemoryInfo` 记录当前进程访问该 value 所需的地址信息和释放动作;后续 `get_start` 命中 `get_cached_info` 时,可以直接把这份 `MemoryInfo` 纳入本次 get 结果,`get_transfer` 再把这些 value 地址写入 readable plan。底层内存的回收由 owner route、holder 引用和 owner-local reserve grant 生命周期共同约束。 + +`precommit_local_visible_info` 只覆盖 commit 进行中的短窗口。put commit 成功并确认 holder 后,会移除 precommit entry 并记录 committed entry;如果 commit 失败,precommit entry 必须被清理,不能作为后续 storage-backed 恢复来源。 + +## Owner 本地写入预留池 + +Owner 本地写入预留池是 owner segment 中为 SGLang hostless put 预先划分的 writable slots。`local_fast_put_start` 从这些 slots 中为本次 put 分配地址,并把地址写入 `plan_ptr(value_ptrs)` 返回给 SGLang native kernel。此时 slot 只处于 reserved/prepared 状态,还没有绑定为 Fluxon KV 的正式 `key -> value` route。 + +这个 pool 是共享 owner segment 上的弹性本地可写内存供给层。它让多个 SGLang worker 都能快速取得受 owner 生命周期管理的 `value_ptrs[]`,同时避免为每个 worker 固定切出长期独占的后端 segment。reserve slot 不足时可以按需求补充 grant,空闲后再按 cooldown 回收。 + +SGLang native kernel 写完 `value_ptrs[]` 后,`local_fast_put_commit` 才把这些 slots 提交为 resident values,并完成 Fluxon KV route commit。commit 前如果 native write 失败,`put_abort(plan_ptr)` 会释放这些 reserved slots。 + +这条路径把写入拆成两个阶段: + +1. `local_fast_put_start` 完成 key reservation、put id 分配和本地 slot claim,返回 `plan_ptr(value_ptrs)`。 +2. SGLang native kernel 写完 `value_ptrs[]` 后,`local_fast_put_commit` 再把这些 slot 转为 resident values,并完成 Fluxon KV 的 put 提交。 + +这里的 `local_fast_*` 是 Python/PyO3 public hostless plan API。真正的 value bytes 由 SGLang native kernel 写入 `value_ptrs[]` 指向的地址;Fluxon 在 commit 阶段只消费 put plan、处理必要 transfer 或 direct done,并完成 route commit。 + +对象含义: + +| 对象 | 含义 | +| --- | --- | +| grant | owner 侧一次申请的大块本地内存,当前固定为 `512 MiB`。 | +| slot | grant 内按 `slot_size` 切分的小块;一个 slot 承载一个 Fluxon value。 | +| slot lease | `local_fast_put_start` 为本次 batch 临时 claim 到的一组 slots;失败或 abort 时必须释放。 | +| value pointer | slot 的起始地址,会写入 plan blob 的 `value_ptrs[]`,供 SGLang kernel 直接写入。 | +| resident value | `local_fast_put_commit` 后由 slot 构造出的本地可读 value。 | +| route | master/owner 确认后的 key 到 value 位置映射;route 成功后该 value 才是全局可见的 KV replica。 | + +slot 生命周期: + +```text +Free + -> Prepared // local_fast_put_start claim slot + -> PendingLocalVisible // local_fast_put_commit 开始,本地 resident value 已记录为 pending visible + -> Committed // put_done 成功,route 引用该 slot + -> Free // route 和 holder 引用都释放后回收 +``` + +如果 native write 失败,调用方必须执行 `put_abort(plan_ptr)`,Prepared slots 会回到 Free。`local_fast_put_commit` 成功返回后,slot 是否能释放由 route 引用和 holder 引用共同决定;只要 master/owner route 或 `MemHolder` 仍引用该 slot,底层 grant 就不能释放。 + +当前容量策略: + +| 项 | 当前实现 | +| --- | --- | +| grant 物理粒度 | `OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES = 512 * 1024 * 1024` | +| 最小 slot size | `4 KiB` | +| slot size 计算 | `max(value_len, 4 KiB).next_power_of_two()` | +| slot 上限 | `slot_size <= 512 MiB` | +| refill 触发 | 当前 slot class free slots 不足时登记 pending demand 并唤醒 rebalance actor。 | +| 默认等待 | soft wait `10 ms`,hard timeout `1 s`。 | +| shrink 单位 | 整个 grant;不做 live grant compaction。 | + +底层物理释放收束在 grant 级别。单个 committed slot 只是 grant 内逻辑索引,不直接拥有释放整块 mmap/registered memory 的权力。 + +## SGLang Node Storage 状态 + +SGLang 侧的 node metadata 不等价于 Fluxon master route 状态。当前四个字段建议按下面语义解释: + +| 字段 | true 的含义 | 清理时机 | +| --- | --- | --- | +| `storage_staged` | 该 node 有一批 Fluxon hostless backup 正在 staged 路径中。 | `KvFuture` 完成或失败后清空。 | +| `storage_local_ready` | CUDA write 已完成,SGLang 已调用 `local_fast_put_commit`,但返回的 `KvFuture` 还未 ack;该状态只表示本次 hostless backup 已进入 Fluxon commit 流程,不表示 KV route 已经全局确认。 | async ack 结束后清空。 | +| `storage_pending` | Fluxon `KvFuture` 还没结束。 | future 成功或失败后清空。 | +| `storage_backed` | Fluxon 后台提交成功,KV route 已确认可作为 shared backing。 | 该 node 被删除或失效时清空。 | + +因此,SGLang 可以用 `storage_staged/storage_local_ready` 判断本次 hostless backup 已经推进到本地写入或 commit 阶段;但跨节点复用和长期共享必须等 `KvFuture` 成功,并以 `storage_backed` 为准。 + +TP 场景下,每个 rank 仍有各自的 radix tree 和恢复决策。`get_start` 的结果只描述当前 rank 这批 keys 的可恢复前缀;如果一个 rank miss、另一个 rank hit,上层必须按 SGLang 的 TP restore 约束处理一致性,不能把单 rank 的部分成功当作完整 request 已恢复。 + +## 失败处理 + +| 场景 | 必须动作 | +| --- | --- | +| `local_fast_put_start` 后 native write 失败 | 调用 `put_abort(plan_ptr)`,释放 key reservation 和 local reserve slot lease。 | +| `local_fast_put_commit` 返回 future 后后台失败 | SGLang 清理 `storage_staged/storage_pending/storage_local_ready`,必要时删除已 evicted 的 dead leaf。 | +| `get_start` 后放弃 restore | 调用 `cancel_get_transfer(handle)`,释放 get-start 持有的 owner/external 资源。 | +| `get_start` 只命中部分前缀 | 只允许恢复 `transferable_len` 覆盖的完整 atomic groups;后续 page 按 miss 处理。 | +| `get_transfer` 报 key miss | SGLang rollback 当前 restore,不继续构造半个 node 的 GPU 恢复。 | +| `get_transfer` 成功后 native restore 失败 | 先 `release_views(plan_ptr)`,再执行 SGLang rollback;此时 handle 已被消费。 | +| CUDA host registration 失败 | direct path 同步失败,不能降级为未注册 host memory。 | +| `plan_ptr` 类型用错 | `local_fast_put_commit`、`put_abort`、`release_views` 都按 registry entry 类型校验并 fail fast。 | diff --git a/fluxon_py/kvclient/fluxon.py b/fluxon_py/kvclient/fluxon.py index 1325e3d..ae9df9a 100644 --- a/fluxon_py/kvclient/fluxon.py +++ b/fluxon_py/kvclient/fluxon.py @@ -3,6 +3,7 @@ This module provides a concrete implementation using the PyO3 Rust bindings. """ +from dataclasses import dataclass from typing import Union, Optional, Callable, Any, Dict, List, Tuple import ctypes import os @@ -25,7 +26,7 @@ from .kvclient_interface import KvClient from .kvclient_interface import KvLeaseApi, KvRpcApi, PutOptionalArgs, FlatDict from .backend_fallback_close import unregister_store_from_cleanup -from .kvclient_interface import KvFuture, MemHolder +from .kvclient_interface import GetStartHandle, GetStartResult, KvFuture, MemHolder from .nonzerocopy_encode import ( DLPacked, INTERNAL_DLPACK_META_KEY, @@ -138,11 +139,114 @@ def _resolve_side_transfer_worker_python() -> str: return sys.executable +@dataclass(frozen=True) +class _RegisteredBufferDescriptor: + ptr: int + size: int + device_kind: str = "host" + device_id: str = "" + layout: str = "raw" + metadata: Optional[Dict[str, Any]] = None + + @property + def end(self) -> int: + return self.ptr + self.size + + def contains(self, ptr: int, size: int) -> bool: + req_end = ptr + size + return ptr >= self.ptr and req_end <= self.end + + def as_dict(self) -> Dict[str, Any]: + return { + "ptr": self.ptr, + "size": self.size, + "device_kind": self.device_kind, + "device_id": self.device_id, + "layout": self.layout, + "metadata": dict(self.metadata or {}), + } + + def _map_nospace_to_storagefull(err: ApiError) -> ApiError: """Normalize storage-capacity errors without depending on backend internals.""" return err +def _get_start_prefix_hit_groups( + raw_prefix_hit_len: int, + group_lens: Tuple[int, ...], +) -> int: + prefix_hit_groups = 0 + transferable_len = 0 + for group_len in group_lens: + next_transferable_len = transferable_len + group_len + if next_transferable_len > raw_prefix_hit_len: + break + transferable_len = next_transferable_len + prefix_hit_groups += 1 + return prefix_hit_groups + + +def _get_start_group_index_for_key_index( + group_lens: Tuple[int, ...], + key_index: int, +) -> Optional[int]: + cursor = 0 + for group_index, group_len in enumerate(group_lens): + cursor += group_len + if key_index < cursor: + return group_index + return None + + +def _build_get_start_result_from_backend_payload( + payload: Dict[str, Any], + keys: List[str], + prefix_best_effort: bool, + normalized_group_lens: Optional[List[int]], +) -> GetStartResult: + result_keys = tuple(keys) + group_lens = ( + (len(result_keys),) + if normalized_group_lens is None + else tuple(normalized_group_lens) + ) + raw_prefix_hit_len = int(payload["raw_prefix_hit_len"]) + if raw_prefix_hit_len < 0 or raw_prefix_hit_len > len(result_keys): + raise RuntimeError( + "get_start returned invalid raw_prefix_hit_len: " + f"raw_prefix_hit_len={raw_prefix_hit_len} keys={len(result_keys)}" + ) + prefix_hit_groups = _get_start_prefix_hit_groups( + raw_prefix_hit_len, + group_lens, + ) + if not prefix_best_effort and prefix_hit_groups != len(group_lens): + transferable_len = 0 + prefix_hit_groups = 0 + else: + transferable_len = sum(group_lens[:prefix_hit_groups]) + first_miss_index = ( + None if raw_prefix_hit_len == len(result_keys) else raw_prefix_hit_len + ) + first_miss_group_index = ( + None + if first_miss_index is None + else _get_start_group_index_for_key_index(group_lens, first_miss_index) + ) + return GetStartResult( + keys=result_keys, + raw_prefix_hit_len=raw_prefix_hit_len, + transferable_len=transferable_len, + prefix_hit_groups=prefix_hit_groups, + atomic_group_lens=tuple(normalized_group_lens) if normalized_group_lens is not None else None, + prefix_best_effort=prefix_best_effort, + first_miss_index=first_miss_index, + first_miss_group_index=first_miss_group_index, + all_hit=transferable_len == len(result_keys), + ) + + def _error_to_ret_code(err: ApiError) -> int: if hasattr(err, "code") and callable(err.code): try: @@ -299,7 +403,11 @@ def __init__(self, config: FluxonKvClientConfig): self._client: Optional[fluxon_pyo3.KvClient] = None self._config = config self._init_error: Optional[ApiError] = None + self._registered_buffer_descriptors: List[_RegisteredBufferDescriptor] = [] cluster_name = config.fluxonkv_spec_cluster_name + self._batch_concurrency = 128 + if self._batch_concurrency <= 0: + raise ValueError("batch_concurrency must be > 0") self._blocking_put_outer_total_log_window = _BlockingPutOuterTotalLogWindow( f"FluxonKVCacheStore[{cluster_name}]" ) @@ -368,11 +476,17 @@ def put( reject_if_inflight_same_key = ( bool(opts.reject_if_inflight_same_key) if opts is not None else False ) + reject_if_exist_same_key = ( + bool(opts.reject_if_exist_same_key) if opts is not None else False + ) + write_through = bool(opts.write_through) if opts is not None else True inner_res = self._client.put( key, ptrs, lease_id=lease_id, reject_if_inflight_same_key=reject_if_inflight_same_key, + reject_if_exist_same_key=reject_if_exist_same_key, + write_through=write_through, ) if not inner_res.is_ok(): err = inner_res.unwrap_error() @@ -416,11 +530,17 @@ def put_blocking( reject_if_inflight_same_key = ( bool(opts.reject_if_inflight_same_key) if opts is not None else False ) + reject_if_exist_same_key = ( + bool(opts.reject_if_exist_same_key) if opts is not None else False + ) + write_through = bool(opts.write_through) if opts is not None else True inner_res = self._client.put_blocking( key, ptrs, lease_id=lease_id, reject_if_inflight_same_key=reject_if_inflight_same_key, + reject_if_exist_same_key=reject_if_exist_same_key, + write_through=write_through, ) if not inner_res.is_ok(): return Result.new_error(inner_res.unwrap_error()) @@ -448,6 +568,199 @@ def get_blocking(self, key: str) -> Result[MemHolder, ApiError]: except ApiError as e: return Result.new_error(e) + @staticmethod + def _normalize_batch_result_list(batch_result: Any, expected_len: int, op_name: str) -> List[Any]: + if isinstance(batch_result, Result): + if not batch_result.is_ok(): + raise RuntimeError(f"{op_name} backend error: {batch_result.unwrap_error()}") + batch_result = batch_result.unwrap() + if not isinstance(batch_result, list): + raise RuntimeError(f"{op_name} returned non-list: {type(batch_result)}") + if len(batch_result) != expected_len: + raise RuntimeError( + f"{op_name} returned unexpected length: expected={expected_len} got={len(batch_result)}" + ) + return list(batch_result) + + def batch_put_blocking( + self, + keys: List[str], + values: List[FlatDict], + opts: Optional[PutOptionalArgs] = None, + concurrency: Optional[int] = None, + ) -> List[Result[OkNone, ApiError]]: + if len(keys) != len(values): + raise ValueError("batch_put_blocking requires keys and values to have the same length") + if len(keys) == 0: + return [] + if self._client is None: + err = GeneralError(message="Store not initialized when batch_put_blocking(). Call setup() first.") + return [Result.new_error(err) for _ in keys] + + lease_id: Optional[int] = opts.lease_id if opts is not None else None + reject_if_inflight_same_key = ( + bool(opts.reject_if_inflight_same_key) if opts is not None else False + ) + reject_if_exist_same_key = ( + bool(opts.reject_if_exist_same_key) if opts is not None else False + ) + write_through = bool(opts.write_through) if opts is not None else True + + keepalive_groups: List[List[bytes]] = [] + dlpack_groups: List[List[object]] = [] + ptr_groups: List[List[tuple[int, int, int, int, int, Optional[int]]]] = [] + try: + for value in values: + keepalive: List[bytes] = [] + dlpack_capsules: List[object] = [] + ptr_groups.append(build_flat_dict_ptrs(value, keepalive, dlpack_capsules)) + keepalive_groups.append(keepalive) + dlpack_groups.append(dlpack_capsules) + + inner_res = self._client.batch_put_blocking( + keys, + ptr_groups, + lease_id=lease_id, + reject_if_inflight_same_key=reject_if_inflight_same_key, + reject_if_exist_same_key=reject_if_exist_same_key, + write_through=write_through, + concurrency=concurrency if concurrency is not None else self._batch_concurrency, + ) + if not inner_res.is_ok(): + err = inner_res.unwrap_error() + return [Result.new_error(err) for _ in keys] + + batch_results = self._normalize_batch_result_list( + inner_res.unwrap(), len(keys), "batch_put_blocking" + ) + submit_out: List[Result[OkNone, ApiError]] = [] + for idx, item in enumerate(batch_results): + if isinstance(item, Result): + submit_out.append(item) + continue + if item is None: + submit_out.append(Result.new_ok(OkNone())) + continue + if isinstance(item, int) and item == 0: + submit_out.append(Result.new_ok(OkNone())) + continue + if isinstance(item, int): + submit_out.append( + Result.new_error( + GeneralError( + message=( + "batch_put_blocking returned backend code " + f"{item} for key {keys[idx]!r}" + ) + ) + ) + ) + continue + submit_out.append( + Result.new_error( + GeneralError( + message=f"unexpected batch_put result type: {type(item)}" + ) + ) + ) + return submit_out + except ApiError as e: + return [Result.new_error(e) for _ in keys] + except Exception as e: + return [Result.new_error(GeneralError(f"batch_put_blocking failed: {e}")) for _ in keys] + finally: + for keepalive in keepalive_groups: + keepalive.clear() + for dlpack_capsules in dlpack_groups: + dlpack_capsules.clear() + + def batch_get_blocking( + self, + keys: List[str], + concurrency: Optional[int] = None, + ) -> List[Result[Union[Any, MemHolder], ApiError]]: + if len(keys) == 0: + return [] + if self._client is None: + err = GeneralError(message="Store not initialized when batch_get_blocking(). Call setup() first.") + return [Result.new_error(err) for _ in keys] + + try: + inner_res = self._client.batch_get_blocking( + keys, + concurrency=concurrency if concurrency is not None else self._batch_concurrency, + ) + if not inner_res.is_ok(): + err = inner_res.unwrap_error() + return [Result.new_error(err) for _ in keys] + + batch_results = self._normalize_batch_result_list( + inner_res.unwrap(), len(keys), "batch_get_blocking" + ) + out: List[Result[Union[Any, MemHolder], ApiError]] = [] + for idx, item in enumerate(batch_results): + if isinstance(item, Result): + out.append(item) + continue + if item is None: + out.append( + Result.new_error( + GeneralError(message=f"batch_get_blocking returned None for key {keys[idx]!r}") + ) + ) + continue + out.append(Result.new_ok(item)) + return out + except ApiError as e: + return [Result.new_error(e) for _ in keys] + except Exception as e: + return [Result.new_error(GeneralError(f"batch_get_blocking failed: {e}")) for _ in keys] + + def put_payload_from_ptr( + self, + key: str, + payload_ptr: int, + payload_size: int, + opts: Optional[PutOptionalArgs] = None, + ) -> Result[KvFuture, ApiError]: + if self._client is None: + return Result.new_error( + GeneralError( + message="Store not initialized when put_payload_from_ptr(). Call setup() first." + ) + ) + + keepalive: List[bytes] = [] + try: + ptrs = _build_payload_field_ptrs(payload_ptr, payload_size, keepalive) + lease_id: Optional[int] = opts.lease_id if opts is not None else None + reject_if_inflight_same_key = ( + bool(opts.reject_if_inflight_same_key) if opts is not None else False + ) + reject_if_exist_same_key = ( + bool(opts.reject_if_exist_same_key) if opts is not None else False + ) + write_through = bool(opts.write_through) if opts is not None else True + inner_res = self._client.put( + key, + ptrs, + lease_id=lease_id, + reject_if_inflight_same_key=reject_if_inflight_same_key, + reject_if_exist_same_key=reject_if_exist_same_key, + write_through=write_through, + ) + if not inner_res.is_ok(): + return Result.new_error(_map_nospace_to_storagefull(inner_res.unwrap_error())) + inner_future = inner_res.unwrap() + assert inner_future is not None + outer_future = _FluxonPutFuture(inner_future, keepalive, []) + keepalive = [] + return Result.new_ok(outer_future) + except ApiError as e: + return Result.new_error(e) + finally: + keepalive.clear() + def put_payload_from_ptr_blocking( self, key: str, @@ -469,11 +782,17 @@ def put_payload_from_ptr_blocking( reject_if_inflight_same_key = ( bool(opts.reject_if_inflight_same_key) if opts is not None else False ) + reject_if_exist_same_key = ( + bool(opts.reject_if_exist_same_key) if opts is not None else False + ) + write_through = bool(opts.write_through) if opts is not None else True inner_res = self._client.put_blocking( key, ptrs, lease_id=lease_id, reject_if_inflight_same_key=reject_if_inflight_same_key, + reject_if_exist_same_key=reject_if_exist_same_key, + write_through=write_through, ) if not inner_res.is_ok(): return Result.new_error(inner_res.unwrap_error()) @@ -566,17 +885,297 @@ def get_payload_into_ptr_blocking( del holder return Result.new_ok(payload_size) + def register_buffer( + self, + ptr: int, + size: int, + device_kind: str = "host", + device_id: str = "", + layout: str = "raw", + metadata: Optional[Dict[str, Any]] = None, + ) -> Result[OkNone, ApiError]: + if self._client is None: + return Result.new_error( + GeneralError( + message="Store not initialized when register_buffer(). Call setup() first." + ) + ) + if not isinstance(ptr, int): + return Result.new_error( + InvalidArgumentError(message=f"ptr must be int; got {type(ptr)}") + ) + if not isinstance(size, int): + return Result.new_error( + InvalidArgumentError(message=f"size must be int; got {type(size)}") + ) + if ptr < 0: + return Result.new_error( + InvalidArgumentError(message=f"ptr must be >= 0; got {ptr}") + ) + if size < 0: + return Result.new_error( + InvalidArgumentError(message=f"size must be >= 0; got {size}") + ) + if not isinstance(device_kind, str): + return Result.new_error( + InvalidArgumentError( + message=f"device_kind must be str; got {type(device_kind)}" + ) + ) + if not isinstance(device_id, str): + return Result.new_error( + InvalidArgumentError( + message=f"device_id must be str; got {type(device_id)}" + ) + ) + if not isinstance(layout, str): + return Result.new_error( + InvalidArgumentError( + message=f"layout must be str; got {type(layout)}" + ) + ) + if metadata is not None and not isinstance(metadata, dict): + return Result.new_error( + InvalidArgumentError( + message=f"metadata must be dict or None; got {type(metadata)}" + ) + ) + try: + inner_res = self._client.register_buffer(ptr, size) + if not inner_res.is_ok(): + return Result.new_error(inner_res.unwrap_error()) + _ = inner_res.unwrap() + self._registered_buffer_descriptors.append( + _RegisteredBufferDescriptor( + ptr=int(ptr), + size=int(size), + device_kind=device_kind, + device_id=device_id, + layout=layout, + metadata=dict(metadata or {}), + ) + ) + return Result.new_ok(OkNone()) + except ApiError as e: + return Result.new_error(e) + + def batch_put_from( + self, + keys: List[str], + payload_ptrs: List[int], + payload_sizes: List[int], + opts: Optional[PutOptionalArgs] = None, + ) -> List[int]: + if len(keys) != len(payload_ptrs) or len(keys) != len(payload_sizes): + raise ValueError( + "batch_put_from requires keys, payload_ptrs, and payload_sizes to have the same length" + ) + if len(keys) == 0: + return [] + + if self._client is None: + code = _error_to_ret_code( + GeneralError( + message="Store not initialized when batch_put_from(). Call setup() first." + ) + ) + return [code] * len(keys) + + lease_id: Optional[int] = opts.lease_id if opts is not None else None + reject_if_inflight_same_key = ( + bool(opts.reject_if_inflight_same_key) if opts is not None else False + ) + reject_if_exist_same_key = ( + bool(opts.reject_if_exist_same_key) if opts is not None else False + ) + write_through = bool(opts.write_through) if opts is not None else True + + try: + inner_res = self._client.batch_put_from( + keys, + payload_ptrs, + payload_sizes, + lease_id=lease_id, + reject_if_inflight_same_key=reject_if_inflight_same_key, + reject_if_exist_same_key=reject_if_exist_same_key, + write_through=write_through, + ) + if inner_res.is_ok(): + submit_results = list(inner_res.unwrap()) + if len(submit_results) != len(keys): + raise RuntimeError( + "batch_put_from returned unexpected result length: " + f"expected={len(keys)} got={len(submit_results)}" + ) + return [int(item) for item in submit_results] + err = inner_res.unwrap_error() + code = _error_to_ret_code(err) + return [code] * len(keys) + except ApiError as e: + code = _error_to_ret_code(e) + return [code] * len(keys) + except Exception as e: + code = _error_to_ret_code(GeneralError(f"batch_put_from failed: {e}")) + return [code] * len(keys) + def get_size(self, key: str) -> Result[int, ApiError]: """Get the size of a stored value (non-blocking).""" return self._client.get_size(key) - def is_exist(self, key: str) -> Result[bool, ApiError]: + def is_exist(self, key: str, allow_local_snapshot: bool = False) -> Result[bool, ApiError]: """Check if a key exists in the store (non-blocking).""" try: - return self._client.is_exist(key) + if self._client is None: + return Result.new_error( + GeneralError( + message="Store not initialized when is_exist(). Call setup() first." + ) + ) + return self._client.is_exist(key, allow_local_snapshot=allow_local_snapshot) except Exception as e: return Result.new_error(GeneralError(f"Existence check failed: {str(e)}")) + def batch_get_into( + self, + keys: List[str], + payload_ptrs: List[int], + payload_capacities: List[int], + ) -> List[int]: + if len(keys) != len(payload_ptrs) or len(keys) != len(payload_capacities): + raise ValueError( + "batch_get_into requires keys, payload_ptrs, and payload_capacities to have the same length" + ) + if len(keys) == 0: + return [] + + if self._client is not None: + inner_res = self._client.batch_get_into(keys, payload_ptrs, payload_capacities) + if inner_res.is_ok(): + return list(inner_res.unwrap()) + err = inner_res.unwrap_error() + return [_error_to_ret_code(err)] * len(keys) + + results: List[int] = [] + for key, ptr, size in zip(keys, payload_ptrs, payload_capacities): + get_result = self.get_payload_into_ptr_blocking(key, ptr, size) + if get_result.is_ok(): + results.append(int(get_result.unwrap())) + else: + results.append(_error_to_ret_code(get_result.unwrap_error())) + return results + + def batch_is_exist( + self, + keys: List[str], + allow_local_snapshot: bool = False, + ) -> List[int]: + if len(keys) == 0: + return [] + + if self._client is None: + code = _error_to_ret_code( + GeneralError( + message="Store not initialized when batch_is_exist(). Call setup() first." + ) + ) + return [code] * len(keys) + + try: + inner_res = self._client.batch_is_exist( + keys, + allow_local_snapshot=allow_local_snapshot, + ) + if not inner_res.is_ok(): + code = _error_to_ret_code(inner_res.unwrap_error()) + return [code] * len(keys) + batch_results = self._normalize_batch_result_list( + inner_res.unwrap(), len(keys), "batch_is_exist" + ) + out: List[int] = [] + for idx, item in enumerate(batch_results): + if not isinstance(item, int): + raise GeneralError( + message=( + f"batch_is_exist returned non-int item for key {keys[idx]!r}: " + f"{type(item)}" + ) + ) + out.append(int(item)) + return out + except ApiError as e: + code = _error_to_ret_code(e) + return [code] * len(keys) + except Exception as e: + code = _error_to_ret_code(GeneralError(f"batch_is_exist failed: {e}")) + return [code] * len(keys) + + def get_meta(self, key: str) -> Result[Dict[str, Any], ApiError]: + """Query key metadata and one live placement without fetching payload bytes.""" + try: + inner = self._client.get_meta(key) + if not inner.is_ok(): + return Result.new_error(inner.unwrap_error()) + meta = inner.unwrap() + assert isinstance(meta, dict), f"get_meta returned non-dict: {type(meta)}" + return Result.new_ok(meta) + except Exception as e: + return Result.new_error(GeneralError(f"GetMeta failed for key '{key}': {str(e)}")) + + def batch_get_meta(self, keys: List[str]) -> List[Dict[str, Any]]: + if len(keys) == 0: + return [] + + if self._client is not None and hasattr(self._client, "batch_get_meta"): + inner_res = self._client.batch_get_meta(keys) + if inner_res.is_ok(): + rows = inner_res.unwrap() + assert isinstance(rows, list), ( + f"batch_get_meta returned non-list: {type(rows)}" + ) + return list(rows) + err = inner_res.unwrap_error() + code = _error_to_ret_code(err) + return [ + { + "exists": False, + "len": 0, + "node_id": "", + "src_addr": 0, + "src_base_addr": 0, + "segment_device_id": "", + "segment_device_desc": "", + "replica_count": 0, + "transport_error": True, + "error_code": -code, + "error_json": str(err), + } + for _ in keys + ] + + rows: List[Dict[str, Any]] = [] + for key in keys: + meta_res = self.get_meta(key) + if meta_res.is_ok(): + rows.append(meta_res.unwrap()) + else: + err = meta_res.unwrap_error() + rows.append( + { + "exists": False, + "len": 0, + "node_id": "", + "src_addr": 0, + "src_base_addr": 0, + "segment_device_id": "", + "segment_device_desc": "", + "replica_count": 0, + "transport_error": True, + "error_code": -_error_to_ret_code(err), + "error_json": str(err), + } + ) + return rows + def count_prefix(self, prefix: str) -> Result[int, ApiError]: """Count number of keys with the given prefix. @@ -806,6 +1405,247 @@ def get_cluster_name(self) -> str: raise RuntimeError("Store not initialized") return str(self._client.cluster_name()) + def wait_local_segments_ready(self) -> List[dict[str, Any]]: + if self._client is None: + raise RuntimeError( + "Store not initialized when wait_local_segments_ready(). Call setup() first." + ) + inner_res = self._client.wait_local_segments_ready() + if not inner_res.is_ok(): + raise RuntimeError( + f"wait_local_segments_ready backend error: {inner_res.unwrap_error()}" + ) + inner_res = inner_res.unwrap() + if not isinstance(inner_res, list): + raise RuntimeError( + "wait_local_segments_ready must return a list of segment mappings" + ) + out: List[dict[str, Any]] = [] + for item in inner_res: + if not isinstance(item, dict): + raise RuntimeError( + "wait_local_segments_ready segment item must be a dict" + ) + out.append(dict(item)) + return out + + def local_fast_put_start( + self, + keys: List[str], + value_len: int, + opts: Optional[PutOptionalArgs] = None, + ) -> int: + if self._client is None: + raise RuntimeError( + "Store not initialized when local_fast_put_start(). Call setup() first." + ) + if len(keys) == 0: + raise ValueError("local_fast_put_start requires at least one key") + if not isinstance(value_len, int): + raise ValueError(f"value_len must be int; got {type(value_len)}") + if value_len <= 0: + raise ValueError(f"value_len must be > 0; got {value_len}") + reject_if_inflight_same_key = ( + bool(opts.reject_if_inflight_same_key) if opts is not None else False + ) + reject_if_exist_same_key = ( + bool(opts.reject_if_exist_same_key) if opts is not None else False + ) + write_through = bool(opts.write_through) if opts is not None else True + inner_res = self._client.local_fast_put_start( + keys, + value_len, + reject_if_inflight_same_key=reject_if_inflight_same_key, + reject_if_exist_same_key=reject_if_exist_same_key, + write_through=write_through, + ) + if not inner_res.is_ok(): + err = inner_res.unwrap_error() + if isinstance(err, Exception): + raise err + raise RuntimeError(f"local_fast_put_start backend error: {err}") + plan_ptr = inner_res.unwrap() + if not isinstance(plan_ptr, int) or plan_ptr <= 0: + raise RuntimeError(f"local_fast_put_start returned invalid plan_ptr: {plan_ptr!r}") + return int(plan_ptr) + + def local_fast_put_commit(self, plan_ptr: int) -> KvFuture: + if self._client is None: + raise RuntimeError( + "Store not initialized when local_fast_put_commit(). Call setup() first." + ) + inner_res = self._client.local_fast_put_commit(plan_ptr) + if not inner_res.is_ok(): + raise RuntimeError( + f"local_fast_put_commit backend error: {inner_res.unwrap_error()}" + ) + inner_future = inner_res.unwrap() + if inner_future is None: + raise RuntimeError("local_fast_put_commit returned empty future") + return _FluxonBatchRetCodeFuture(inner_future, [plan_ptr]) + + def put_abort(self, plan_ptr: int) -> None: + if self._client is None: + raise RuntimeError( + "Store not initialized when put_abort(). Call setup() first." + ) + inner_res = self._client.put_abort(plan_ptr) + if not inner_res.is_ok(): + raise RuntimeError(f"put_abort backend error: {inner_res.unwrap_error()}") + _ = inner_res.unwrap() + + def get_views( + self, + keys: List[str], + concurrency: Optional[int] = None, + ) -> int: + if self._client is None: + raise RuntimeError( + "Store not initialized when get_views(). Call setup() first." + ) + if len(keys) == 0: + raise ValueError("get_views requires at least one key") + inner_res = self._client.get_views( + keys, + concurrency=concurrency if concurrency is not None else self._batch_concurrency, + ) + if not inner_res.is_ok(): + raise RuntimeError(f"get_views backend error: {inner_res.unwrap_error()}") + plan_ptr = inner_res.unwrap() + if not isinstance(plan_ptr, int) or plan_ptr <= 0: + raise RuntimeError(f"get_views returned invalid plan_ptr: {plan_ptr!r}") + return int(plan_ptr) + + def release_views(self, plan_ptr: int) -> None: + if self._client is None: + raise RuntimeError( + "Store not initialized when release_views(). Call setup() first." + ) + inner_res = self._client.release_views(plan_ptr) + if not inner_res.is_ok(): + raise RuntimeError(f"release_views backend error: {inner_res.unwrap_error()}") + _ = inner_res.unwrap() + + def get_start( + self, + keys: List[str], + prefix_best_effort: bool = True, + atomic_group_lens: Optional[List[int]] = None, + ) -> GetStartHandle: + if self._client is None: + raise RuntimeError( + "Store not initialized when get_start(). Call setup() first." + ) + if len(keys) == 0: + raise ValueError("get_start requires at least one key") + normalized_group_lens: Optional[List[int]] = None + if atomic_group_lens is not None: + normalized_group_lens = [int(length) for length in atomic_group_lens] + if any(length <= 0 for length in normalized_group_lens): + raise ValueError("get_start atomic_group_lens entries must be > 0") + if sum(normalized_group_lens) != len(keys): + raise ValueError( + "get_start atomic_group_lens must sum to keys length: " + f"sum={sum(normalized_group_lens)} keys={len(keys)}" + ) + + started_at_ns = time.monotonic_ns() + inner_res = self._client.get_start( + list(keys), + bool(prefix_best_effort), + normalized_group_lens, + self._batch_concurrency, + ) + if not inner_res.is_ok(): + raise RuntimeError(f"get_start backend error: {inner_res.unwrap_error()}") + payload = inner_res.unwrap() + if not isinstance(payload, dict): + raise RuntimeError(f"get_start returned non-dict payload: {type(payload)}") + backend_handle = int(payload["handle"]) + result = _build_get_start_result_from_backend_payload( + payload, + list(keys), + bool(prefix_best_effort), + normalized_group_lens, + ) + logging.info( + "FluxonKVCacheStore get_start result: keys=%d raw_prefix_hit_len=%d " + "transferable_len=%d prefix_hit_groups=%d all_hit=%s " + "first_miss_index=%s first_miss_group_index=%s " + "prefix_best_effort=%s duration_ms=%.3f", + len(keys), + result.raw_prefix_hit_len, + result.transferable_len, + result.prefix_hit_groups, + result.all_hit, + result.first_miss_index, + result.first_miss_group_index, + result.prefix_best_effort, + (time.monotonic_ns() - started_at_ns) / 1_000_000.0, + ) + return GetStartHandle( + keys=tuple(keys), + result=result, + created_at_ns=started_at_ns, + backend_token=id(self), + backend_handle=backend_handle, + ) + + def cancel_get_transfer(self, handle: GetStartHandle) -> None: + if not isinstance(handle, GetStartHandle): + raise TypeError(f"cancel_get_transfer requires GetStartHandle, got {type(handle)}") + if handle.backend_token is not None and handle.backend_token != id(self): + raise RuntimeError( + "cancel_get_transfer handle belongs to a different FluxonKVCacheStore" + ) + if handle.closed: + return + if self._client is None: + raise RuntimeError( + "Store not initialized when cancel_get_transfer(). Call setup() first." + ) + inner_res = self._client.cancel_get_transfer(int(handle.backend_handle)) + if not inner_res.is_ok(): + raise RuntimeError( + f"cancel_get_transfer backend error: {inner_res.unwrap_error()}" + ) + handle.closed = True + + def get_transfer( + self, + handle: GetStartHandle, + concurrency: Optional[int] = None, + ) -> int: + if not isinstance(handle, GetStartHandle): + raise TypeError(f"get_transfer requires GetStartHandle, got {type(handle)}") + if handle.backend_token is not None and handle.backend_token != id(self): + raise RuntimeError("get_transfer handle belongs to a different FluxonKVCacheStore") + if handle.closed: + raise RuntimeError("get_transfer handle has been closed") + result = handle.result + if result.transferable_len == 0: + raise RuntimeError( + "get_transfer requires a non-empty transferable prefix: " + f"transferable_len={result.transferable_len} total={len(result.keys)} " + f"raw_prefix_hit_len={result.raw_prefix_hit_len} " + f"first_miss_index={result.first_miss_index} " + f"first_miss_group_index={result.first_miss_group_index}" + ) + if self._client is None: + raise RuntimeError( + "Store not initialized when get_transfer(). Call setup() first." + ) + _ = concurrency + inner_res = self._client.get_transfer(handle.backend_handle) + if not inner_res.is_ok(): + handle.closed = True + raise RuntimeError(f"get_transfer backend error: {inner_res.unwrap_error()}") + plan_ptr = inner_res.unwrap() + handle.closed = True + if not isinstance(plan_ptr, int) or plan_ptr <= 0: + raise RuntimeError(f"get_transfer returned invalid plan_ptr: {plan_ptr!r}") + return int(plan_ptr) + def get_etcd_config(self) -> List[str]: if self._client is None: raise RuntimeError("Store not initialized") @@ -889,6 +1729,19 @@ def metrics_snapshot(self) -> MetricSnapshot: return MetricSnapshot(per_segment=normalized) + def observability_snapshot_async(self) -> KvFuture: + """Return a future for Fluxon locality and IO counters.""" + if self._client is None: + raise RuntimeError( + "Store not initialized when observability_snapshot_async(). Call setup() first." + ) + res = self._client.observability_snapshot_async() + if not res.is_ok(): + raise RuntimeError( + f"observability_snapshot_async backend error: {res.unwrap_error()}" + ) + return res.unwrap() + # --- Fluxon-kv lease helpers (synchronous) --- def allocate_lease(self, ttl_seconds: int) -> Result[int, ApiError]: try: @@ -948,7 +1801,7 @@ def __init__(self, inner_future: Any) -> None: self._inner = inner_future def is_waiting(self) -> bool: - return bool(getattr(self._inner, "is_waiting")()) + return bool(self._inner.is_waiting()) def _decode_wait_success( self, @@ -985,7 +1838,7 @@ def __init__(self, inner_future: Any) -> None: self._inner = inner_future def is_waiting(self) -> bool: - return bool(getattr(self._inner, "is_waiting")()) + return bool(self._inner.is_waiting()) def wait(self) -> Result[bytes, ApiError]: res = self._inner.wait() @@ -1022,7 +1875,7 @@ def __del__(self) -> None: self._dlpack_capsules = [] def is_waiting(self) -> bool: - return bool(getattr(self._inner, "is_waiting")()) + return bool(self._inner.is_waiting()) def wait(self) -> Result[Union[Any, MemHolder], ApiError]: from ..api_error import OkNone, Result as PyResult # type: ignore @@ -1035,3 +1888,36 @@ def wait(self) -> Result[Union[Any, MemHolder], ApiError]: _ = res.unwrap() return PyResult.new_ok(OkNone()) # type: ignore + + +class _FluxonBatchRetCodeFuture(KvFuture): + """Future wrapper for batch APIs that resolve to one integer ret-code per key.""" + + def __init__(self, inner_future: Any, keepalive: List[object]) -> None: + self._inner = inner_future + self._keepalive = keepalive + + def __del__(self) -> None: + self._keepalive = [] + + def is_waiting(self) -> bool: + return bool(self._inner.is_waiting()) + + def wait(self) -> Result[List[int], ApiError]: + res = self._inner.wait() + self._keepalive = [] + if not res.is_ok(): + return Result.new_error(res.unwrap_error()) + raw = res.unwrap() + if not isinstance(raw, list): + return Result.new_error( + GeneralError(message=f"batch future returned non-list payload: {type(raw)}") + ) + out: List[int] = [] + for item in raw: + if not isinstance(item, int): + return Result.new_error( + GeneralError(message=f"batch future returned non-int item: {type(item)}") + ) + out.append(int(item)) + return Result.new_ok(out) diff --git a/fluxon_py/kvclient/kvclient_interface.py b/fluxon_py/kvclient/kvclient_interface.py index f50db0f..e126eec 100644 --- a/fluxon_py/kvclient/kvclient_interface.py +++ b/fluxon_py/kvclient/kvclient_interface.py @@ -21,6 +21,47 @@ FlatDict = Dict[str, Union[int, float, bool, str, bytes, DLPacked]] +@dataclass(frozen=True) +class GetStartResult: + """ + Result of a group-prefix best-effort get_start(). + + Semantics: + - ``keys`` is the caller-provided ordered page-key sequence. + - ``raw_prefix_hit_len`` is the page-level continuous hit prefix. + - ``transferable_len`` is rounded down to complete atomic groups and is the + only prefix that can be consumed by get_transfer(). + """ + + keys: Tuple[str, ...] + raw_prefix_hit_len: int + transferable_len: int + prefix_hit_groups: int + atomic_group_lens: Optional[Tuple[int, ...]] + prefix_best_effort: bool + first_miss_index: Optional[int] + first_miss_group_index: Optional[int] + all_hit: bool + + +@dataclass +class GetStartHandle: + """ + Opaque-ish handle returned by get_start() and consumed by get_transfer(). + + Callers must pass this handle to cancel_get_transfer() when abandoning it + without calling get_transfer(). Fluxon backends may keep strong holder + references alive while this handle is live. + """ + + keys: Tuple[str, ...] + result: GetStartResult + created_at_ns: int + backend_token: Optional[int] = None + backend_handle: int = 0 + closed: bool = False + + @dataclass class PutOptionalArgs: """ @@ -29,9 +70,16 @@ class PutOptionalArgs: - lease_id: attach the written key to a lease on commit. - reject_if_inflight_same_key: ask Fluxon to fail-fast when the same key is already being written by another inflight put. + - reject_if_exist_same_key: ask Fluxon to fail-fast when the key already has a + committed live replica. + - write_through: keep synchronous remote-placement semantics when the backend + supports an async write-back path. Defaults to True to match SGLang + HiCache's default write policy. """ lease_id: Optional[int] = None reject_if_inflight_same_key: bool = False + reject_if_exist_same_key: bool = False + write_through: bool = True def support_mooncake(self) -> Tuple[bool, List[str]]: """ @@ -48,6 +96,10 @@ def support_mooncake(self) -> Tuple[bool, List[str]]: unsupported.append("lease_id") if self.reject_if_inflight_same_key: unsupported.append("reject_if_inflight_same_key") + if self.reject_if_exist_same_key: + unsupported.append("reject_if_exist_same_key") + if self.write_through: + unsupported.append("write_through") return (len(unsupported) == 0, unsupported) @@ -139,7 +191,7 @@ def put_blocking( _ = wait_result.unwrap() return Result.new_ok(OkNone()) - def get_blocking(self, key: str) -> Result["MemHolder", ApiError]: + def get_blocking(self, key: str) -> Result[Union[Any, "MemHolder"], ApiError]: """Synchronously retrieve a value by key. Default implementation delegates to ``get()`` followed by @@ -151,6 +203,100 @@ def get_blocking(self, key: str) -> Result["MemHolder", ApiError]: return Result.new_error(get_result.unwrap_error()) return get_result.unwrap().wait() + def batch_put_blocking( + self, + keys: List[str], + values: List[FlatDict], + opts: Optional[PutOptionalArgs] = None, + concurrency: Optional[int] = None, + ) -> List[Result[OkNone, ApiError]]: + """Synchronously store a batch of key-value pairs.""" + if len(keys) != len(values): + raise ValueError("batch_put_blocking requires keys and values to have the same length") + _ = concurrency + return [self.put_blocking(key, value, opts=opts) for key, value in zip(keys, values)] + + def batch_get_blocking( + self, + keys: List[str], + concurrency: Optional[int] = None, + ) -> List[Result[Union[Any, "MemHolder"], ApiError]]: + """Synchronously retrieve a batch of keys.""" + _ = concurrency + return [self.get_blocking(key) for key in keys] + + def local_fast_put_start( + self, + keys: List[str], + value_len: int, + opts: Optional[PutOptionalArgs] = None, + ) -> int: + _ = keys + _ = value_len + _ = opts + raise NotImplementedError( + "local_fast_put_start is only implemented by backends with native plan_ptr support" + ) + + def local_fast_put_commit(self, plan_ptr: int) -> "KvFuture": + _ = plan_ptr + raise NotImplementedError( + "local_fast_put_commit is only implemented by backends with native plan_ptr support" + ) + + def put_abort(self, plan_ptr: int) -> None: + _ = plan_ptr + raise NotImplementedError( + "put_abort is only implemented by backends with native plan_ptr support" + ) + + def get_views( + self, + keys: List[str], + concurrency: Optional[int] = None, + ) -> int: + _ = keys + _ = concurrency + raise NotImplementedError( + "get_views is only implemented by backends with native plan_ptr support" + ) + + def release_views(self, plan_ptr: int) -> None: + _ = plan_ptr + raise NotImplementedError( + "release_views is only implemented by backends with native plan_ptr support" + ) + + def get_start( + self, + keys: List[str], + prefix_best_effort: bool = True, + atomic_group_lens: Optional[List[int]] = None, + ) -> GetStartHandle: + _ = keys + _ = prefix_best_effort + _ = atomic_group_lens + raise NotImplementedError( + "get_start is only implemented by backends with native prefix get support" + ) + + def get_transfer( + self, + handle: GetStartHandle, + concurrency: Optional[int] = None, + ) -> int: + _ = handle + _ = concurrency + raise NotImplementedError( + "get_transfer is only implemented by backends with native prefix get support" + ) + + def cancel_get_transfer(self, handle: GetStartHandle) -> None: + _ = handle + raise NotImplementedError( + "cancel_get_transfer is only implemented by backends with native prefix get support" + ) + @abstractmethod def get_size(self, key: str) -> Result[int, ApiError]: """Get the size of a stored value (non-blocking).""" diff --git a/fluxon_rs/fluxon_commu/src/facade/transfer_engine.rs b/fluxon_rs/fluxon_commu/src/facade/transfer_engine.rs index 878e5c6..e5353a5 100644 --- a/fluxon_rs/fluxon_commu/src/facade/transfer_engine.rs +++ b/fluxon_rs/fluxon_commu/src/facade/transfer_engine.rs @@ -74,12 +74,10 @@ impl ClosedLocalSegmentLeaseRegistry { where G: Send + Sync + 'static, { - let boxed = self - .guards - .lock() - .await - .remove(&handle) - .ok_or_else(|| format!("closed sdk local segment lease handle {handle} not found"))?; + let boxed = + self.guards.lock().await.remove(&handle).ok_or_else(|| { + format!("closed sdk local segment lease handle {handle} not found") + })?; boxed.downcast::().map(|guard| *guard).map_err(|_| { format!( "closed sdk local segment lease handle {handle} has unexpected runtime guard type" @@ -461,7 +459,7 @@ impl ClientTransferEngineCore { len, seg_guard, ) - .await + .await } } @@ -482,7 +480,11 @@ impl ClientTransferEngineCore { let initial_local_segment_guard = match seg_guard { Some(guard) => Some(guard), None if runtime.supports_local_segment_transfer() => { - let local_addr = if peer_src_or_target { target_addr } else { src_addr }; + let local_addr = if peer_src_or_target { + target_addr + } else { + src_addr + }; match runtime.ensure_local_segment_guard(local_addr, None).await { Ok(guard) => Some(guard), Err(_) => None, diff --git a/fluxon_rs/fluxon_commu_closed_sdk_consumer/src/lib.rs b/fluxon_rs/fluxon_commu_closed_sdk_consumer/src/lib.rs index 6fab54e..caad34b 100644 --- a/fluxon_rs/fluxon_commu_closed_sdk_consumer/src/lib.rs +++ b/fluxon_rs/fluxon_commu_closed_sdk_consumer/src/lib.rs @@ -11,9 +11,9 @@ use fluxon_commu_contract::{ ClosedRuntimeCallRawObservedOutputView, ClosedRuntimeClusterEventStreamItem, ClosedRuntimeClusterManagerCall, ClosedRuntimeClusterManagerResponse, ClosedRuntimeClusterRdmaResolvedConfigStreamItem, ClosedRuntimeDesiredTransferPeer, - ClosedRuntimeDispatchRequestView, - ClosedRuntimeDispatchResponse, ClosedRuntimeDispatchTransportPolicy, ClosedRuntimeError, - ClosedRuntimeHandle, ClosedRuntimeHostCallbackHandle, ClosedRuntimeP2pCall, + ClosedRuntimeDispatchRequestView, ClosedRuntimeDispatchResponse, + ClosedRuntimeDispatchTransportPolicy, ClosedRuntimeError, ClosedRuntimeHandle, + ClosedRuntimeHostCallbackHandle, ClosedRuntimeP2pCall, ClosedRuntimeP2pCallRawObservedRequestView, ClosedRuntimeP2pResponse, ClosedRuntimeP2pSendResponseRawRequestView, ClosedRuntimePeerGen, ClosedRuntimeRawSlice, ClosedRuntimeRequest, ClosedRuntimeResponse, ClosedRuntimeTransferEngineCall, @@ -491,11 +491,15 @@ impl WireBodyPartsOwner { let (raw_lengths, raw_payload) = match raw_bytes.len() { 0 => (WireBodyRawLengths::Empty, WireBodyRawPayload::Empty), 1 => { - let part = raw_bytes.into_iter().next().expect("single raw part missing"); - let len = - u32::try_from(part.len()).map_err(|_| ClosedSdkConsumerError::RuntimeDecode { + let part = raw_bytes + .into_iter() + .next() + .expect("single raw part missing"); + let len = u32::try_from(part.len()).map_err(|_| { + ClosedSdkConsumerError::RuntimeDecode { detail: format!("wire raw part too large for u32 length: {}", part.len()), - })?; + } + })?; ( WireBodyRawLengths::Single([len]), WireBodyRawPayload::Single(part), @@ -849,8 +853,7 @@ fn decode_call_raw_observed_output_view( return Err(ClosedSdkConsumerError::RuntimeDecode { detail: format!( "closed SDK call_raw_observed serialize_part overflow: serialize_len={} full_len={}", - message_view.body.serialize_part.len, - message_view.body.full_body.len, + message_view.body.serialize_part.len, message_view.body.full_body.len, ), }); } @@ -860,21 +863,19 @@ fn decode_call_raw_observed_output_view( .ok_or_else(|| ClosedSdkConsumerError::RuntimeDecode { detail: "closed SDK call_raw_observed raw_bytes length overflow".to_string(), })?; - let expected_full_len = - message_view - .body - .serialize_part - .len - .checked_add(raw_total) - .ok_or_else(|| ClosedSdkConsumerError::RuntimeDecode { - detail: "closed SDK call_raw_observed body length overflow".to_string(), - })?; + let expected_full_len = message_view + .body + .serialize_part + .len + .checked_add(raw_total) + .ok_or_else(|| ClosedSdkConsumerError::RuntimeDecode { + detail: "closed SDK call_raw_observed body length overflow".to_string(), + })?; if expected_full_len != message_view.body.full_body.len { return Err(ClosedSdkConsumerError::RuntimeDecode { detail: format!( "closed SDK call_raw_observed body length mismatch: expected={} full_len={}", - expected_full_len, - message_view.body.full_body.len, + expected_full_len, message_view.body.full_body.len, ), }); } @@ -923,9 +924,7 @@ fn decode_call_raw_observed_output_view( frame_recv_done_ts_us: message_view.local_observe.frame_recv_done_ts_us, dispatch_enqueued_ts_us: message_view.local_observe.dispatch_enqueued_ts_us, dispatch_started_ts_us: message_view.local_observe.dispatch_started_ts_us, - complete_pending_call_ts_us: message_view - .local_observe - .complete_pending_call_ts_us, + complete_pending_call_ts_us: message_view.local_observe.complete_pending_call_ts_us, }, }, observe: fluxon_commu_contract::ClosedRuntimeRpcCallTransportObserveTrace { @@ -1550,8 +1549,8 @@ async fn invoke_completion_async_with_keepalive( ) -> i32, ) -> Result<(i32, Bytes), ClosedSdkConsumerError> { let (sender, receiver) = tokio::sync::oneshot::channel::<(i32, Bytes)>(); - let user_data = Box::into_raw(Box::new(RuntimeCompletionState { sender, keepalive })) - .cast::(); + let user_data = + Box::into_raw(Box::new(RuntimeCompletionState { sender, keepalive })).cast::(); let submit_status = submit(user_data, Some(runtime_completion_callback)); if submit_status != 0 { unsafe { @@ -2082,7 +2081,9 @@ pub async fn p2p_call_raw_observed( ) .await?; match status_code { - FLUXON_COMMU_CLOSED_RUNTIME_RESULT_OK => decode_call_raw_observed_output_view(payload.as_ref()), + FLUXON_COMMU_CLOSED_RUNTIME_RESULT_OK => { + decode_call_raw_observed_output_view(payload.as_ref()) + } FLUXON_COMMU_CLOSED_RUNTIME_RESULT_ERR => { let error = bitcode::decode::(payload.as_ref()).map_err( |decode_error| ClosedSdkConsumerError::RuntimeDecode { diff --git a/fluxon_rs/fluxon_fs/src/agent.rs b/fluxon_rs/fluxon_fs/src/agent.rs index a482616..45e15e7 100644 --- a/fluxon_rs/fluxon_fs/src/agent.rs +++ b/fluxon_rs/fluxon_fs/src/agent.rs @@ -1408,13 +1408,24 @@ impl FluxonFsAgent { .id .to_string(); let cache_root_base = if self.kv_framework.is_external_mode() { - self.kv_framework + let shared_file_path = self + .kv_framework .external_client_api_view() .external_client_api() .inner() - .large_file_paths() - .fs_disk_cache_base_dir() - .map_err(|err| format!("invalid external large_file_paths: {}", err))? + .shared_file_path(); + if shared_file_path.is_empty() { + return Err("external shared_file_path is empty".to_string()); + } + let cache_root = Path::new(&shared_file_path).join("fluxon_fs_disk_cache"); + fs::create_dir_all(&cache_root).map_err(|err| { + format!( + "invalid external shared_file_path for fluxon fs disk cache: {} ({})", + cache_root.display(), + err + ) + })?; + cache_root } else { self.kv_framework .client_seg_pool_view() diff --git a/fluxon_rs/fluxon_fs/src/agent_service/transfer_agent.rs b/fluxon_rs/fluxon_fs/src/agent_service/transfer_agent.rs index 1738ade..ca54a71 100644 --- a/fluxon_rs/fluxon_fs/src/agent_service/transfer_agent.rs +++ b/fluxon_rs/fluxon_fs/src/agent_service/transfer_agent.rs @@ -9,28 +9,23 @@ use std::time::{Duration, Instant}; use fluxon_fs_core::config::{ FS_AGENT_TRANSFER_STREAM_CLOSE_RPC_PATH, FS_AGENT_TRANSFER_STREAM_NEXT_RPC_PATH, - FS_AGENT_TRANSFER_STREAM_OPEN_RPC_PATH, - FS_MASTER_TRANSFER_SCHEDULER_HEARTBEAT_RPC_PATH, FS_MASTER_TRANSFER_SCHEDULER_RESULT_RPC_PATH, - FluxonFsTransferBatchCollectInfoWire, FluxonFsTransferBatchKind, - FluxonFsTransferCollectInfoKind, FluxonFsTransferDispositionWire, - FluxonFsTransferFailedFileReasonKindWire, - FluxonFsTransferReadStreamCloseWire, FluxonFsTransferReadStreamNextResultWire, - FluxonFsTransferReadStreamNextWire, FluxonFsTransferReadStreamOpenResultWire, - FluxonFsTransferReadStreamOpenWire, - FluxonFsTransferSkipEntryKind, FluxonFsTransferSkipEntryWire, - FluxonFsTransferManifestEntryWire, FluxonFsTransferManifestWire, - FluxonFsTransferScanMode, - FluxonFsTransferScanEventAckWire, FluxonFsTransferScanEventKindWire, - FluxonFsTransferScanEventWire, FluxonFsTransferScanLaunchResultWire, + FS_AGENT_TRANSFER_STREAM_OPEN_RPC_PATH, FS_MASTER_TRANSFER_SCHEDULER_HEARTBEAT_RPC_PATH, + FS_MASTER_TRANSFER_SCHEDULER_RESULT_RPC_PATH, FluxonFsTransferBatchCollectInfoWire, + FluxonFsTransferBatchKind, FluxonFsTransferCollectInfoKind, FluxonFsTransferDispositionWire, + FluxonFsTransferFailedFileReasonKindWire, FluxonFsTransferManifestEntryWire, + FluxonFsTransferManifestWire, FluxonFsTransferReadStreamCloseWire, + FluxonFsTransferReadStreamNextResultWire, FluxonFsTransferReadStreamNextWire, + FluxonFsTransferReadStreamOpenResultWire, FluxonFsTransferReadStreamOpenWire, FluxonFsTransferScanAssignmentWire, FluxonFsTransferScanBatchWire, - FluxonFsTransferScanChildUnitWire, FluxonFsTransferScanFrontier, + FluxonFsTransferScanChildUnitWire, FluxonFsTransferScanEventAckWire, + FluxonFsTransferScanEventKindWire, FluxonFsTransferScanEventWire, FluxonFsTransferScanFrontier, FluxonFsTransferScanFrontierDirEntry, FluxonFsTransferScanFrontierEntry, - FluxonFsTransferScanResultWire, - FluxonFsTransferSymlinkNoticeEntryWire, FluxonFsTransferWorkerCollectInfoResultWire, - FluxonFsTransferWorkerAssignmentWire, FluxonFsTransferWorkerFileResultWire, - FluxonFsTransferWorkerFailedFileResultWire, - FluxonFsTransferWorkerHeartbeatResultWire, FluxonFsTransferWorkerHeartbeatTelemetryWire, - FluxonFsTransferWorkerHeartbeatWire, + FluxonFsTransferScanLaunchResultWire, FluxonFsTransferScanMode, FluxonFsTransferScanResultWire, + FluxonFsTransferSkipEntryKind, FluxonFsTransferSkipEntryWire, + FluxonFsTransferSymlinkNoticeEntryWire, FluxonFsTransferWorkerAssignmentWire, + FluxonFsTransferWorkerCollectInfoResultWire, FluxonFsTransferWorkerFailedFileResultWire, + FluxonFsTransferWorkerFileResultWire, FluxonFsTransferWorkerHeartbeatResultWire, + FluxonFsTransferWorkerHeartbeatTelemetryWire, FluxonFsTransferWorkerHeartbeatWire, FluxonFsTransferWorkerLaunchResultWire, FluxonFsTransferWorkerResultAckWire, FluxonFsTransferWorkerResultWire, FluxonFsTransferWorkerStopReasonWire, transfer_collect_info_output_relpath, @@ -39,8 +34,8 @@ use fluxon_fs_core::retry::{ BackoffConfig, DEFAULT_WARN_INTERVAL_SECS, WarnConfig, next_backoff, should_warn, }; use fluxon_kv::rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError}; -use fluxon_kv::user_api::flat_dict::{FlatDict, FlatValue}; use fluxon_kv::user_api::FluxonUserApi; +use fluxon_kv::user_api::flat_dict::{FlatDict, FlatValue}; use parking_lot::{Condvar, Mutex}; use super::{ @@ -202,16 +197,13 @@ fn transfer_scan_session_state() -> &'static Mutex { TRANSFER_SCAN_SESSION_STATE.get_or_init(|| Mutex::new(TransferScanSessionState::default())) } -fn cleanup_expired_transfer_scan_sessions( - state: &mut TransferScanSessionState, - now_unix_ms: i64, -) { - state - .root_dir_listing_sessions - .retain(|_, session| session.lease_expire_unix_ms <= 0 || session.lease_expire_unix_ms > now_unix_ms); - state - .subtree_streaming_sessions - .retain(|_, session| session.lease_expire_unix_ms <= 0 || session.lease_expire_unix_ms > now_unix_ms); +fn cleanup_expired_transfer_scan_sessions(state: &mut TransferScanSessionState, now_unix_ms: i64) { + state.root_dir_listing_sessions.retain(|_, session| { + session.lease_expire_unix_ms <= 0 || session.lease_expire_unix_ms > now_unix_ms + }); + state.subtree_streaming_sessions.retain(|_, session| { + session.lease_expire_unix_ms <= 0 || session.lease_expire_unix_ms > now_unix_ms + }); } fn same_root_continuation_scan_unit( @@ -301,10 +293,7 @@ fn flush_pending_root_direct_files_batch( return Ok(None); } let batch = build_direct_files_only_batch_from_entries_with_batch_id( - direct_files_only_batch_id_for_partition( - assignment, - session.next_direct_files_batch_index, - ), + direct_files_only_batch_id_for_partition(assignment, session.next_direct_files_batch_index), assignment, assignment.root_relpath.clone(), std::mem::take(&mut session.pending_direct_files), @@ -313,7 +302,8 @@ fn flush_pending_root_direct_files_batch( )?; session.pending_direct_bytes = 0; session.next_direct_files_batch_index = session.next_direct_files_batch_index.saturating_add(1); - session.emitted_direct_files_batch_count = session.emitted_direct_files_batch_count.saturating_add(1); + session.emitted_direct_files_batch_count = + session.emitted_direct_files_batch_count.saturating_add(1); Ok(Some(batch)) } @@ -414,7 +404,8 @@ fn open_transfer_root_dir_listing_session( root_dir_abs: &str, assignment: &FluxonFsTransferScanAssignmentWire, ) -> Result, FlatDict> { - let dir_abs = safe_join_root(root_dir_abs, assignment.root_relpath.as_str()).map_err(resp_err_kverr)?; + let dir_abs = + safe_join_root(root_dir_abs, assignment.root_relpath.as_str()).map_err(resp_err_kverr)?; let read_dir = match retry_after_target_path_chmod( dir_abs.as_path(), "root_read_dir", @@ -458,7 +449,10 @@ fn take_transfer_root_dir_listing_session( let now_unix_ms = chrono::Utc::now().timestamp_millis(); let mut state = transfer_scan_session_state().lock(); cleanup_expired_transfer_scan_sessions(&mut state, now_unix_ms); - if let Some(mut session) = state.root_dir_listing_sessions.remove(assignment.scan_unit_id.as_str()) { + if let Some(mut session) = state + .root_dir_listing_sessions + .remove(assignment.scan_unit_id.as_str()) + { if session.job_id == assignment.job_id && session.scan_epoch == assignment.scan_epoch && session.root_relpath == assignment.root_relpath @@ -507,7 +501,8 @@ fn open_transfer_subtree_streaming_session( if is_relpath_skipped(&assignment.skip_entries, assignment.root_relpath.as_str()) { return Ok(None); } - let dir_abs = safe_join_root(root_dir_abs, assignment.root_relpath.as_str()).map_err(resp_err_kverr)?; + let dir_abs = + safe_join_root(root_dir_abs, assignment.root_relpath.as_str()).map_err(resp_err_kverr)?; let root_md = retry_after_target_path_chmod( Path::new(root_dir_abs), "subtree_stream_root_symlink_metadata", @@ -790,7 +785,8 @@ fn collect_transfer_root_dir_listing_slice( assignment: &FluxonFsTransferScanAssignmentWire, deadline: Option, ) -> Result { - let Some(mut session) = take_transfer_root_dir_listing_session(root_dir_abs, assignment)? else { + let Some(mut session) = take_transfer_root_dir_listing_session(root_dir_abs, assignment)? + else { return Ok(TransferRootDirListingOutcome::Finished( build_finished_empty_transfer_scan_result(assignment), )); @@ -848,7 +844,8 @@ fn collect_transfer_root_dir_listing_slice( }; scanned_entries = scanned_entries.saturating_add(1); let name = ent.file_name().to_string_lossy().to_string(); - let child_relpath = normalize_child_relpath(assignment.root_relpath.as_str(), name.as_str()); + let child_relpath = + normalize_child_relpath(assignment.root_relpath.as_str(), name.as_str()); if is_relpath_skipped(&assignment.skip_entries, child_relpath.as_str()) { continue; } @@ -899,10 +896,12 @@ fn collect_transfer_root_dir_listing_slice( let size = md.len().min(i64::MAX as u64) as i64; session.root_visible_entries = true; session.root_total_bytes = session.root_total_bytes.saturating_add(size); - session.pending_direct_files.push(FluxonFsTransferScanFrontierEntry { - relpath: child_relpath, - size, - }); + session + .pending_direct_files + .push(FluxonFsTransferScanFrontierEntry { + relpath: child_relpath, + size, + }); session.pending_direct_bytes = session.pending_direct_bytes.saturating_add(size); if should_flush_direct_batch( assignment.batch_ready_bytes, @@ -910,7 +909,9 @@ fn collect_transfer_root_dir_listing_slice( session.pending_direct_files.len(), session.pending_direct_empty_dirs.len(), ) { - if let Some(batch) = flush_pending_root_direct_files_batch(assignment, &mut session)? { + if let Some(batch) = + flush_pending_root_direct_files_batch(assignment, &mut session)? + { direct_files_only_batches.push(batch); } } @@ -933,14 +934,18 @@ fn collect_transfer_root_dir_listing_slice( session.pending_direct_files.len(), session.pending_direct_empty_dirs.len(), ) { - if let Some(batch) = flush_pending_root_direct_files_batch(assignment, &mut session)? { + if let Some(batch) = + flush_pending_root_direct_files_batch(assignment, &mut session)? + { direct_files_only_batches.push(batch); } } } else { - session.direct_dirs.push(FluxonFsTransferScanFrontierDirEntry { - relpath: child_relpath, - }); + session + .direct_dirs + .push(FluxonFsTransferScanFrontierDirEntry { + relpath: child_relpath, + }); } } } @@ -1244,12 +1249,14 @@ impl TransferWorkerProgressWindow { fn record_written_bytes_and_maybe_ramp(&self, bytes: i64, now_unix_ms: i64) { let normalized = bytes.max(0); self.window_bytes.fetch_add(normalized, Ordering::SeqCst); - self.total_written_bytes.fetch_add(normalized, Ordering::SeqCst); + self.total_written_bytes + .fetch_add(normalized, Ordering::SeqCst); self.maybe_ramp(now_unix_ms); } fn record_materialized_empty_dir(&self) { - self.total_materialized_empty_dirs.fetch_add(1, Ordering::SeqCst); + self.total_materialized_empty_dirs + .fetch_add(1, Ordering::SeqCst); } fn total_materialized_empty_dirs(&self) -> i64 { @@ -1298,8 +1305,9 @@ impl TransferWorkerProgressWindow { } if previous_goodput > 0 { let delta = current_goodput.saturating_sub(previous_goodput); - let improvement_percent = - delta.saturating_mul(100).saturating_div(previous_goodput.max(1)); + let improvement_percent = delta + .saturating_mul(100) + .saturating_div(previous_goodput.max(1)); if improvement_percent < self.policy.min_improvement_percent { return; } @@ -1335,10 +1343,8 @@ impl TransferWorkerProgressWindow { .saturating_mul(1000) .saturating_div(window_elapsed_ms.max(1)) }; - self.peak_sample_goodput_bytes_per_sec.fetch_max( - window_goodput_bytes_per_sec.max(0), - Ordering::SeqCst, - ); + self.peak_sample_goodput_bytes_per_sec + .fetch_max(window_goodput_bytes_per_sec.max(0), Ordering::SeqCst); Some(TransferWorkerThroughputSample { window_started_unix_ms, window_elapsed_ms, @@ -1448,7 +1454,8 @@ impl TransferReadStreamActorOwned { data: Vec::new(), }); } - self.fill_prefetch_queue().map_err(|err| self.cache_terminal_error(err))?; + self.fill_prefetch_queue() + .map_err(|err| self.cache_terminal_error(err))?; let to_take = std::cmp::min(length as usize, (self.file_size - next_offset) as usize); let buf = self .take_prefetched_bytes(to_take) @@ -1457,7 +1464,8 @@ impl TransferReadStreamActorOwned { self.replay_offset = next_offset; self.replay_data = buf.clone(); self.next_offset = next_offset.saturating_add(buf.len() as i64); - self.fill_prefetch_queue().map_err(|err| self.cache_terminal_error(err))?; + self.fill_prefetch_queue() + .map_err(|err| self.cache_terminal_error(err))?; Ok(FluxonFsTransferReadStreamNextResultWire { stream_missing: false, data: buf, @@ -1598,7 +1606,11 @@ impl TransferReadStreamActorHandle { struct TransferWorkerCoordinator where - ReadChunkFn: Fn(&FluxonFsTransferManifestEntryWire, i64, i64) -> Result, TransferWorkerExecutionError>, + ReadChunkFn: Fn( + &FluxonFsTransferManifestEntryWire, + i64, + i64, + ) -> Result, TransferWorkerExecutionError>, CheckpointFn: Fn() -> Result<(), TransferWorkerExecutionError>, { log_context: TransferWorkerLogContext, @@ -1611,7 +1623,11 @@ where impl TransferWorkerCoordinator where - ReadChunkFn: Fn(&FluxonFsTransferManifestEntryWire, i64, i64) -> Result, TransferWorkerExecutionError>, + ReadChunkFn: Fn( + &FluxonFsTransferManifestEntryWire, + i64, + i64, + ) -> Result, TransferWorkerExecutionError>, CheckpointFn: Fn() -> Result<(), TransferWorkerExecutionError>, { fn new( @@ -1693,7 +1709,8 @@ where } fn progress_snapshot(&self) -> TransferWorkerProgressSnapshot { - self.progress.snapshot(chrono::Utc::now().timestamp_millis()) + self.progress + .snapshot(chrono::Utc::now().timestamp_millis()) } fn stop(&self) { @@ -1737,7 +1754,8 @@ impl TransferReadStreamRegistryHandle { }); } } - let full_path = safe_join_root(root_dir_abs, open.relpath.as_str()).map_err(resp_err_kverr)?; + let full_path = + safe_join_root(root_dir_abs, open.relpath.as_str()).map_err(resp_err_kverr)?; let file = open_file_with_target_path_chmod_retry(&full_path, "open_stream")?; let md = file.metadata().map_err(resp_err_io)?; let file_size = md.len().min(i64::MAX as u64) as i64; @@ -1764,12 +1782,15 @@ impl TransferReadStreamRegistryHandle { }); } state.streams.insert(stream_id.clone(), entry); - state.dedup_by_worker_file.insert(dedup_key, stream_id.clone()); + state + .dedup_by_worker_file + .insert(dedup_key, stream_id.clone()); drop(state); if let Err(resp) = TransferReadStreamActorHandle::start(stream_id.as_str(), actor) { let mut state = self.state.lock(); state.streams.remove(stream_id.as_str()); - state.dedup_by_worker_file + state + .dedup_by_worker_file .retain(|_, existing_stream_id| existing_stream_id != &stream_id); return Err(resp); } @@ -1811,7 +1832,9 @@ impl TransferReadStreamRegistryHandle { let Some(entry) = state.streams.remove(stream_id) else { return; }; - state.dedup_by_worker_file.retain(|_, existing_stream_id| existing_stream_id != stream_id); + state + .dedup_by_worker_file + .retain(|_, existing_stream_id| existing_stream_id != stream_id); entry.close(); } } @@ -1894,20 +1917,22 @@ fn decode_transfer_stream_open_result_payload( return Err(TransferWorkerRpcFailure::Fatal(resp.clone())); } Ok(FluxonFsTransferReadStreamOpenResultWire { - stream_id: require_str(resp, "stream_id").map_err(resp_err_kverr).map_err( - |err| { + stream_id: require_str(resp, "stream_id") + .map_err(resp_err_kverr) + .map_err(|err| { invalid_transfer_rpc_response(format!( "transfer read stream open response missing stream_id: err={}", transfer_rpc_response_err_text(&err) )) - }, - )?, - size: require_i64(resp, "size").map_err(resp_err_kverr).map_err(|err| { - invalid_transfer_rpc_response(format!( - "transfer read stream open response missing size: err={}", - transfer_rpc_response_err_text(&err) - )) - })?, + })?, + size: require_i64(resp, "size") + .map_err(resp_err_kverr) + .map_err(|err| { + invalid_transfer_rpc_response(format!( + "transfer read stream open response missing size: err={}", + transfer_rpc_response_err_text(&err) + )) + })?, }) } @@ -1980,11 +2005,15 @@ fn is_relpath_skipped(skip_entries: &[FluxonFsTransferSkipEntryWire], relpath: & } fn file_name_from_relpath(relpath: &str) -> Result<&str, FlatDict> { - relpath.rsplit('/').next().filter(|v| !v.is_empty()).ok_or_else(|| { - resp_err_kverr(KvError::Api(ApiError::InvalidArgument { - detail: format!("relpath must contain file name: {}", relpath), - })) - }) + relpath + .rsplit('/') + .next() + .filter(|v| !v.is_empty()) + .ok_or_else(|| { + resp_err_kverr(KvError::Api(ApiError::InvalidArgument { + detail: format!("relpath must contain file name: {}", relpath), + })) + }) } fn transfer_staging_dir_for_file(staging_prefix: &str, relpath: &str) -> String { @@ -2106,8 +2135,12 @@ where match attempt() { Ok(value) => Ok(value), Err(initial_err) if initial_err.kind() == ErrorKind::PermissionDenied => { - let repair_dir = - repair_permission_denied_dir_for_retry(repair_anchor, op, target_path, &initial_err)?; + let repair_dir = repair_permission_denied_dir_for_retry( + repair_anchor, + op, + target_path, + &initial_err, + )?; attempt().map_err(|retry_err| { resp_err_kverr(KvError::Api(ApiError::Unknown { detail: format!( @@ -2334,10 +2367,11 @@ fn collect_transfer_tree_with_deadline( continue; } }; - out.symlink_notices.push(FluxonFsTransferSymlinkNoticeEntryWire { - relpath: child_rel, - link_target: link_target.to_string_lossy().to_string(), - }); + out.symlink_notices + .push(FluxonFsTransferSymlinkNoticeEntryWire { + relpath: child_rel, + link_target: link_target.to_string_lossy().to_string(), + }); continue; } if md.is_dir() { @@ -2361,7 +2395,8 @@ fn collect_transfer_tree_with_deadline( } out.files.sort_by(|a, b| a.relpath.cmp(&b.relpath)); out.empty_dirs.sort(); - out.symlink_notices.sort_by(|a, b| a.relpath.cmp(&b.relpath)); + out.symlink_notices + .sort_by(|a, b| a.relpath.cmp(&b.relpath)); Ok(out) } @@ -2574,10 +2609,8 @@ fn build_transfer_scan_events_for_result( event_seq_no_start: i64, result: FluxonFsTransferScanResultWire, ) -> (Vec, bool, i64) { - let (child_scan_units, continue_locally) = split_same_root_continuation_from_child_scan_units( - assignment, - result.child_scan_units, - ); + let (child_scan_units, continue_locally) = + split_same_root_continuation_from_child_scan_units(assignment, result.child_scan_units); if continue_locally { let event = build_transfer_scan_event( assignment, @@ -2588,11 +2621,7 @@ fn build_transfer_scan_events_for_result( result.full_dir_batches, String::new(), ); - return ( - vec![event], - true, - event_seq_no_start.saturating_add(1), - ); + return (vec![event], true, event_seq_no_start.saturating_add(1)); } let mut next_event_seq_no = event_seq_no_start; let mut events = Vec::new(); @@ -2620,11 +2649,7 @@ fn build_transfer_scan_events_for_result( Vec::new(), String::new(), )); - ( - events, - false, - next_event_seq_no.saturating_add(1), - ) + (events, false, next_event_seq_no.saturating_add(1)) } fn send_transfer_scan_event_once( @@ -2637,10 +2662,7 @@ fn send_transfer_scan_event_once( } let event_json = serde_json::to_string(event) .map_err(|e| format!("serialize transfer scan event failed: {}", e))?; - let payload = FlatDict::from([( - "scan_event_json".to_string(), - FlatValue::String(event_json), - )]); + let payload = FlatDict::from([("scan_event_json".to_string(), FlatValue::String(event_json))]); let resp = api .rpc_client() .call( @@ -2793,30 +2815,28 @@ fn run_transfer_scan_background_task( } let mut next_event_seq_no = 1_i64; loop { - let result = match build_transfer_scan_result_for_root_dir_abs( - root_dir_abs.as_str(), - &assignment, - ) { - Ok(v) => v, - Err(resp) => { - let failed = build_transfer_scan_event( - &assignment, - next_event_seq_no, - FluxonFsTransferScanEventKindWire::Failed, - Vec::new(), - Vec::new(), - Vec::new(), - transfer_rpc_response_err_text(&resp), - ); - let _ = send_transfer_scan_event_with_retry( - api.as_ref(), - master_id.as_str(), - &mut assignment, - &failed, - ); - break; - } - }; + let result = + match build_transfer_scan_result_for_root_dir_abs(root_dir_abs.as_str(), &assignment) { + Ok(v) => v, + Err(resp) => { + let failed = build_transfer_scan_event( + &assignment, + next_event_seq_no, + FluxonFsTransferScanEventKindWire::Failed, + Vec::new(), + Vec::new(), + Vec::new(), + transfer_rpc_response_err_text(&resp), + ); + let _ = send_transfer_scan_event_with_retry( + api.as_ref(), + master_id.as_str(), + &mut assignment, + &failed, + ); + break; + } + }; let (events, continue_locally, next_seq_no_after_events) = build_transfer_scan_events_for_result(&assignment, next_event_seq_no, result); next_event_seq_no = next_seq_no_after_events; @@ -2922,17 +2942,14 @@ impl TransferScanRegistryHandle { let assignment2 = assignment.clone(); let thread_name = format!("fluxon_fs_transfer_scan_{}", assignment.scan_task_id); match thread::Builder::new().name(thread_name).spawn(move || { - run_transfer_scan_background_task( - registry, - api2, - master_id2, - exports2, - assignment2, - ); + run_transfer_scan_background_task(registry, api2, master_id2, exports2, assignment2); }) { Ok(_) => Ok(FluxonFsTransferScanLaunchResultWire::started()), Err(err) => { - self.state.lock().tasks.remove(assignment.scan_task_id.as_str()); + self.state + .lock() + .tasks + .remove(assignment.scan_task_id.as_str()); Err(resp_err_kverr(KvError::Api(ApiError::Unknown { detail: format!( "spawn transfer scan thread failed: scan_task_id={} err={}", @@ -3006,22 +3023,16 @@ impl TransferWorkerRegistryHandle { let master_id2 = master_id.to_string(); let exports2 = exports.clone(); let assignment2 = assignment.clone(); - let thread_name = format!( - "fluxon_fs_transfer_worker_{}", - assignment.worker_task_id - ); + let thread_name = format!("fluxon_fs_transfer_worker_{}", assignment.worker_task_id); match thread::Builder::new().name(thread_name).spawn(move || { - run_transfer_worker_background_task( - registry, - api2, - master_id2, - exports2, - assignment2, - ); + run_transfer_worker_background_task(registry, api2, master_id2, exports2, assignment2); }) { Ok(_) => Ok(FluxonFsTransferWorkerLaunchResultWire::started()), Err(err) => { - self.state.lock().tasks.remove(assignment.worker_task_id.as_str()); + self.state + .lock() + .tasks + .remove(assignment.worker_task_id.as_str()); Err(resp_err_kverr(KvError::Api(ApiError::Unknown { detail: format!( "spawn transfer worker thread failed: worker_task_id={} err={}", @@ -3298,10 +3309,7 @@ fn send_transfer_worker_result_once( detail: format!("serialize transfer worker result failed: {}", e), }))) })?; - let payload = FlatDict::from([( - "result_json".to_string(), - FlatValue::String(result_json), - )]); + let payload = FlatDict::from([("result_json".to_string(), FlatValue::String(result_json))]); let resp = api .rpc_client() .call( @@ -3396,7 +3404,10 @@ fn open_transfer_read_stream_via_rpc_once( "relpath".to_string(), FlatValue::String(file.relpath.clone()), ), - ("initial_offset".to_string(), FlatValue::Int64(initial_offset)), + ( + "initial_offset".to_string(), + FlatValue::Int64(initial_offset), + ), ]); let resp = api .rpc_client() @@ -3518,25 +3529,25 @@ impl TransferWorkerRemoteControl { loop { self.before_heartbeat_retry_attempt()?; let current_materialized_empty_dirs = self.progress.total_materialized_empty_dirs(); - match self - .heartbeat - .ensure_continue( - force, - current_materialized_empty_dirs, - |heartbeat_unix_ms, _heartbeat_detail| { - let progress_snapshot = - self.progress.snapshot(chrono::Utc::now().timestamp_millis()); - let telemetry = - Some(transfer_worker_telemetry_from_progress_snapshot(&progress_snapshot)); - send_transfer_worker_heartbeat_once( - self.api.as_ref(), - self.master_id.as_str(), - &self.assignment, - heartbeat_unix_ms, - telemetry, - ) - }, - ) { + match self.heartbeat.ensure_continue( + force, + current_materialized_empty_dirs, + |heartbeat_unix_ms, _heartbeat_detail| { + let progress_snapshot = self + .progress + .snapshot(chrono::Utc::now().timestamp_millis()); + let telemetry = Some(transfer_worker_telemetry_from_progress_snapshot( + &progress_snapshot, + )); + send_transfer_worker_heartbeat_once( + self.api.as_ref(), + self.master_id.as_str(), + &self.assignment, + heartbeat_unix_ms, + telemetry, + ) + }, + ) { Ok(()) => return Ok(()), Err(TransferWorkerHeartbeatGateError::Terminal(err)) => return Err(err), Err(TransferWorkerHeartbeatGateError::Retryable { @@ -3631,10 +3642,7 @@ impl TransferWorkerRemoteControl { ) } - fn close_stream_with_retry( - &self, - stream_id: &str, - ) -> Result<(), TransferWorkerExecutionError> { + fn close_stream_with_retry(&self, stream_id: &str) -> Result<(), TransferWorkerExecutionError> { let api = self.api.clone(); let assignment = self.assignment.clone(); let op_detail = format!( @@ -3744,9 +3752,9 @@ impl TransferWorkerRemoteControl { if ack.accepted { return Ok(()); } - Err(TransferWorkerExecutionError::Stop(stop_reason_or_superseded( - ack.stop_reason, - ))) + Err(TransferWorkerExecutionError::Stop( + stop_reason_or_superseded(ack.stop_reason), + )) } } @@ -3825,10 +3833,12 @@ impl TransferWorkerHeartbeatGate { mut heartbeat_op: HeartbeatOp, ) -> Result<(), TransferWorkerHeartbeatGateError> where - HeartbeatOp: FnMut( - i64, - &'static str, - ) -> Result, + HeartbeatOp: + FnMut( + i64, + &'static str, + ) + -> Result, { loop { let (heartbeat_unix_ms, heartbeat_detail) = { @@ -3875,15 +3885,13 @@ impl TransferWorkerHeartbeatGate { state.heartbeat_inflight = false; let result = match heartbeat_result { Ok(heartbeat_result) if heartbeat_result.continue_running => { - state.last_heartbeat_completed_unix_ms = - chrono::Utc::now().timestamp_millis(); + state.last_heartbeat_completed_unix_ms = chrono::Utc::now().timestamp_millis(); state.last_heartbeat_materialized_empty_dirs = current_materialized_empty_dirs; state.granted_lease_expire_unix_ms = heartbeat_result.lease_expire_unix_ms; Ok(()) } Ok(heartbeat_result) => { - state.last_heartbeat_completed_unix_ms = - chrono::Utc::now().timestamp_millis(); + state.last_heartbeat_completed_unix_ms = chrono::Utc::now().timestamp_millis(); state.last_heartbeat_materialized_empty_dirs = current_materialized_empty_dirs; let reason = stop_reason_or_superseded(heartbeat_result.stop_reason); state.terminal_state = @@ -3933,7 +3941,8 @@ fn run_transfer_worker_background_task( )); let dedup_expire_unix_ms = match control.ensure_continue(true) { Ok(()) => { - let dst_export_root = match exports.export_root_dir_abs(assignment.dst_export.as_str()) { + let dst_export_root = match exports.export_root_dir_abs(assignment.dst_export.as_str()) + { Ok(v) => v, Err(err) => { tracing::warn!( @@ -3996,7 +4005,9 @@ fn run_transfer_worker_background_task( }, { let control = control.clone(); - move |file, read_offset, length| control.read_chunk_with_retry(file, read_offset, length) + move |file, read_offset, length| { + control.read_chunk_with_retry(file, read_offset, length) + } }, ) { Ok(result) => { @@ -4004,34 +4015,38 @@ fn run_transfer_worker_background_task( if let Err(resp) = cleanup_transfer_worker_attempt_artifacts(&dst_root, &assignment) { - log_transfer_worker_cleanup_failure("before_result_submit", &assignment, &resp); - } - match control.submit_result_with_retry(&result) { - Ok(()) => control.dedup_expire_unix_ms(), - Err(TransferWorkerExecutionError::Stop(reason)) => { - tracing::info!( - "transfer worker result submission stopped: job_id={} batch_id={} worker_id={} worker_task_id={} reason={:?}", - assignment.job_id, - assignment.batch_id, - assignment.worker_id, - assignment.worker_task_id, - reason + log_transfer_worker_cleanup_failure( + "before_result_submit", + &assignment, + &resp, ); - control.dedup_expire_unix_ms() } - Err(TransferWorkerExecutionError::Fatal(resp)) => { - tracing::warn!( - "transfer worker result submission failed: job_id={} batch_id={} worker_id={} worker_task_id={} resp={:?}", - assignment.job_id, - assignment.batch_id, - assignment.worker_id, - assignment.worker_task_id, - resp - ); - control.dedup_expire_unix_ms() + match control.submit_result_with_retry(&result) { + Ok(()) => control.dedup_expire_unix_ms(), + Err(TransferWorkerExecutionError::Stop(reason)) => { + tracing::info!( + "transfer worker result submission stopped: job_id={} batch_id={} worker_id={} worker_task_id={} reason={:?}", + assignment.job_id, + assignment.batch_id, + assignment.worker_id, + assignment.worker_task_id, + reason + ); + control.dedup_expire_unix_ms() + } + Err(TransferWorkerExecutionError::Fatal(resp)) => { + tracing::warn!( + "transfer worker result submission failed: job_id={} batch_id={} worker_id={} worker_task_id={} resp={:?}", + assignment.job_id, + assignment.batch_id, + assignment.worker_id, + assignment.worker_task_id, + resp + ); + control.dedup_expire_unix_ms() + } } } - } Err(TransferWorkerExecutionError::Stop(reason)) => { control.close_all_streams(); if let Err(resp) = @@ -4054,10 +4069,13 @@ fn run_transfer_worker_background_task( if let Err(cleanup_resp) = cleanup_transfer_worker_attempt_artifacts(&dst_root, &assignment) { - log_transfer_worker_cleanup_failure("after_fatal", &assignment, &cleanup_resp); + log_transfer_worker_cleanup_failure( + "after_fatal", + &assignment, + &cleanup_resp, + ); } - if let Some((fatal_kind, fatal_message)) = - classify_transfer_worker_fatal(&resp) + if let Some((fatal_kind, fatal_message)) = classify_transfer_worker_fatal(&resp) { match report_transfer_worker_fatal_once( control.api.as_ref(), @@ -4107,15 +4125,25 @@ fn run_transfer_worker_background_task( } } Err(TransferWorkerExecutionError::Stop(reason)) => { - let dst_export_root = exports.export_root_dir_abs(assignment.dst_export.as_str()).ok(); + let dst_export_root = exports + .export_root_dir_abs(assignment.dst_export.as_str()) + .ok(); let dst_root = dst_export_root.and_then(|dst_export_root| { - safe_join_root(dst_export_root.as_str(), assignment.dst_root_relpath.as_str()) - .ok() - .map(PathBuf::from) + safe_join_root( + dst_export_root.as_str(), + assignment.dst_root_relpath.as_str(), + ) + .ok() + .map(PathBuf::from) }); if let Some(dst_root) = dst_root { - if let Err(resp) = cleanup_transfer_worker_attempt_artifacts(&dst_root, &assignment) { - log_transfer_worker_cleanup_failure("before_execution_stop", &assignment, &resp); + if let Err(resp) = cleanup_transfer_worker_attempt_artifacts(&dst_root, &assignment) + { + log_transfer_worker_cleanup_failure( + "before_execution_stop", + &assignment, + &resp, + ); } } tracing::info!( @@ -4129,11 +4157,16 @@ fn run_transfer_worker_background_task( control.dedup_expire_unix_ms() } Err(TransferWorkerExecutionError::Fatal(resp)) => { - let dst_export_root = exports.export_root_dir_abs(assignment.dst_export.as_str()).ok(); + let dst_export_root = exports + .export_root_dir_abs(assignment.dst_export.as_str()) + .ok(); let dst_root = dst_export_root.and_then(|dst_export_root| { - safe_join_root(dst_export_root.as_str(), assignment.dst_root_relpath.as_str()) - .ok() - .map(PathBuf::from) + safe_join_root( + dst_export_root.as_str(), + assignment.dst_root_relpath.as_str(), + ) + .ok() + .map(PathBuf::from) }); if let Some(dst_root) = dst_root { if let Err(cleanup_resp) = @@ -4509,7 +4542,9 @@ fn plan_transfer_subtree_batches( total_bytes: 0, root_is_empty: true, mergeable_empty_dir_count: 1, - mergeable_empty_dir_estimated_bytes: estimate_empty_dir_manifest_entry_bytes(root_relpath), + mergeable_empty_dir_estimated_bytes: estimate_empty_dir_manifest_entry_bytes( + root_relpath, + ), direct_files_only_batches: Vec::new(), full_dir_batches: Vec::new(), child_scan_units: Vec::new(), @@ -4540,8 +4575,7 @@ fn plan_transfer_subtree_batches( let child_empty_dir_count = child_plan.mergeable_empty_dir_count; let child_empty_dir_estimated_bytes = child_plan.mergeable_empty_dir_estimated_bytes; - if mergeable_empty_dir_count - .saturating_add(child_empty_dir_count) + if mergeable_empty_dir_count.saturating_add(child_empty_dir_count) > TRANSFER_MERGEABLE_EMPTY_DIR_BUDGET || mergeable_empty_dir_estimated_bytes .saturating_add(child_empty_dir_estimated_bytes) @@ -4716,7 +4750,11 @@ fn build_root_direct_files_only_batch_from_entries( } fn sort_transfer_scan_batches(batches: &mut [FluxonFsTransferScanBatchWire]) { - batches.sort_by(|a, b| a.root_relpath.cmp(&b.root_relpath).then(a.batch_id.cmp(&b.batch_id))); + batches.sort_by(|a, b| { + a.root_relpath + .cmp(&b.root_relpath) + .then(a.batch_id.cmp(&b.batch_id)) + }); } fn build_full_dir_batch_for_mergeable_subtree( @@ -4750,14 +4788,12 @@ fn build_transfer_scan_result_for_subtree_streaming_root_dir_abs( root_dir_abs: &str, assignment: &FluxonFsTransferScanAssignmentWire, ) -> Result { - let Some(mut session) = take_transfer_subtree_streaming_session(root_dir_abs, assignment)? else { + let Some(mut session) = take_transfer_subtree_streaming_session(root_dir_abs, assignment)? + else { return Ok(build_finished_empty_subtree_stream_result(assignment)); }; loop { - if session - .dir_stack - .is_empty() - { + if session.dir_stack.is_empty() { let mut full_dir_batches = Vec::new(); if let Some(batch) = flush_pending_subtree_stream_batch(assignment, &mut session)? { full_dir_batches.push(batch); @@ -4776,7 +4812,9 @@ fn build_transfer_scan_result_for_subtree_streaming_root_dir_abs( finished: true, }); } - if TransferScanDeadline::from_assignment(assignment).is_some_and(|deadline| deadline.reached()) { + if TransferScanDeadline::from_assignment(assignment) + .is_some_and(|deadline| deadline.reached()) + { let mut full_dir_batches = Vec::new(); if let Some(batch) = flush_pending_subtree_stream_batch(assignment, &mut session)? { full_dir_batches.push(batch); @@ -4808,7 +4846,10 @@ fn build_transfer_scan_result_for_subtree_streaming_root_dir_abs( if should_flush_subtree_stream_batch( assignment.batch_ready_bytes, session.pending_bytes, - session.pending_files.len().saturating_add(session.pending_symlink_notices.len()), + session + .pending_files + .len() + .saturating_add(session.pending_symlink_notices.len()), session.pending_empty_dirs.len(), ) { let batch = flush_pending_subtree_stream_batch(assignment, &mut session)?.unwrap(); @@ -4865,22 +4906,30 @@ fn build_transfer_scan_result_for_subtree_streaming_root_dir_abs( }); } else if md.is_dir() { frame.saw_visible_child = true; - session.dir_stack.push(open_transfer_subtree_streaming_dir_frame( - child_path, - child_relpath, - )?); + session + .dir_stack + .push(open_transfer_subtree_streaming_dir_frame( + child_path, + child_relpath, + )?); } else if md.is_file() { frame.saw_visible_child = true; let size = md.len().min(i64::MAX as u64) as i64; session.pending_bytes = session.pending_bytes.saturating_add(size); session .pending_files - .push(FluxonFsTransferScanFrontierEntry { relpath: child_relpath, size }); + .push(FluxonFsTransferScanFrontierEntry { + relpath: child_relpath, + size, + }); } if should_flush_subtree_stream_batch( assignment.batch_ready_bytes, session.pending_bytes, - session.pending_files.len().saturating_add(session.pending_symlink_notices.len()), + session + .pending_files + .len() + .saturating_add(session.pending_symlink_notices.len()), session.pending_empty_dirs.len(), ) { let batch = flush_pending_subtree_stream_batch(assignment, &mut session)?.unwrap(); @@ -4928,11 +4977,12 @@ pub(crate) fn build_transfer_scan_result_for_root_dir_abs( ); } let deadline = TransferScanDeadline::from_assignment(assignment); - let root_listing = match collect_transfer_root_dir_listing_slice(root_dir_abs, assignment, deadline)? { - TransferRootDirListingOutcome::Complete(v) => v, - TransferRootDirListingOutcome::Finished(result) => return Ok(result), - TransferRootDirListingOutcome::Partial(result) => return Ok(result), - }; + let root_listing = + match collect_transfer_root_dir_listing_slice(root_dir_abs, assignment, deadline)? { + TransferRootDirListingOutcome::Complete(v) => v, + TransferRootDirListingOutcome::Finished(result) => return Ok(result), + TransferRootDirListingOutcome::Partial(result) => return Ok(result), + }; let mut direct_files = root_listing.direct_files; let mut direct_symlink_notices = root_listing.direct_symlink_notices; let mut direct_empty_dirs = root_listing.direct_empty_dirs; @@ -4976,7 +5026,10 @@ pub(crate) fn build_transfer_scan_result_for_root_dir_abs( if (!direct_files.is_empty() || !direct_symlink_notices.is_empty() || !direct_empty_dirs.is_empty()) - && !direct_files_only_disposition_covers_root(assignment, assignment.root_relpath.as_str()) + && !direct_files_only_disposition_covers_root( + assignment, + assignment.root_relpath.as_str(), + ) { let mut next_partition_index = root_listing.emitted_direct_files_batch_count; direct_files_only_batches.extend(build_partitioned_root_direct_files_only_batches( @@ -4987,17 +5040,15 @@ pub(crate) fn build_transfer_scan_result_for_root_dir_abs( direct_empty_dirs.clone(), )?); } - child_scan_units.extend( - direct_dirs[delegated_child_scan_unit_count..] - .iter() - .map(|entry| { - new_child_scan_unit( - entry.relpath.clone(), - assignment.generation + 1, - delegated_child_scan_mode(), - ) - }), - ); + child_scan_units.extend(direct_dirs[delegated_child_scan_unit_count..].iter().map( + |entry| { + new_child_scan_unit( + entry.relpath.clone(), + assignment.generation + 1, + delegated_child_scan_mode(), + ) + }, + )); child_scan_units.sort_by(|a, b| a.root_relpath.cmp(&b.root_relpath)); sort_transfer_scan_batches(&mut direct_files_only_batches); return Ok(FluxonFsTransferScanResultWire { @@ -5027,7 +5078,8 @@ pub(crate) fn build_transfer_scan_result_for_root_dir_abs( let mut root_partitioned = root_listing.emitted_direct_files_batch_count > 0 || direct_files_only_disposition_covers_root(assignment, assignment.root_relpath.as_str()); let mut mergeable_empty_dir_count = direct_empty_dirs.len(); - let mut mergeable_empty_dir_estimated_bytes = estimate_empty_dir_manifest_bytes(&direct_empty_dirs); + let mut mergeable_empty_dir_estimated_bytes = + estimate_empty_dir_manifest_bytes(&direct_empty_dirs); for child_relpath in direct_dirs.iter().map(|entry| entry.relpath.clone()) { let child_plan = plan_transfer_subtree_batches( root_dir_abs, @@ -5043,8 +5095,7 @@ pub(crate) fn build_transfer_scan_result_for_root_dir_abs( let child_empty_dir_count = child_plan.mergeable_empty_dir_count; let child_empty_dir_estimated_bytes = child_plan.mergeable_empty_dir_estimated_bytes; - if mergeable_empty_dir_count - .saturating_add(child_empty_dir_count) + if mergeable_empty_dir_count.saturating_add(child_empty_dir_count) > TRANSFER_MERGEABLE_EMPTY_DIR_BUDGET || mergeable_empty_dir_estimated_bytes .saturating_add(child_empty_dir_estimated_bytes) @@ -5083,7 +5134,10 @@ pub(crate) fn build_transfer_scan_result_for_root_dir_abs( if (!direct_files.is_empty() || !direct_symlink_notices.is_empty() || !mergeable_empty_child_relpaths.is_empty()) - && !direct_files_only_disposition_covers_root(assignment, assignment.root_relpath.as_str()) + && !direct_files_only_disposition_covers_root( + assignment, + assignment.root_relpath.as_str(), + ) { let mut next_partition_index = root_listing.emitted_direct_files_batch_count; direct_empty_dirs.extend(mergeable_empty_child_relpaths); @@ -5212,10 +5266,11 @@ fn handle_transfer_scan_assignment( assignment.generation, assignment.known_dispositions.len(), ); - let result = match build_transfer_scan_result_for_root_dir_abs(root_dir_abs.as_str(), &assignment) { - Ok(v) => v, - Err(resp) => return resp, - }; + let result = + match build_transfer_scan_result_for_root_dir_abs(root_dir_abs.as_str(), &assignment) { + Ok(v) => v, + Err(resp) => return resp, + }; encode_transfer_scan_result(&result, "transfer scan result") } @@ -5228,8 +5283,11 @@ fn prepare_transfer_file_streaming( coordinator: &TransferWorkerCoordinator, ) -> Result where - ReadChunkFn: - Fn(&FluxonFsTransferManifestEntryWire, i64, i64) -> Result, TransferWorkerExecutionError>, + ReadChunkFn: Fn( + &FluxonFsTransferManifestEntryWire, + i64, + i64, + ) -> Result, TransferWorkerExecutionError>, CheckpointFn: Fn() -> Result<(), TransferWorkerExecutionError>, { let staging_relpath = transfer_staging_file_relpath(staging_prefix, file.relpath.as_str()) @@ -5239,9 +5297,12 @@ where .map_err(TransferWorkerExecutionError::fatal)?; ensure_transfer_parent_dirs(dst_root, final_relpath.as_str()) .map_err(TransferWorkerExecutionError::fatal)?; - let staging_abs = safe_join_root(dst_root.to_string_lossy().as_ref(), staging_relpath.as_str()) - .map_err(resp_err_kverr) - .map_err(TransferWorkerExecutionError::fatal)?; + let staging_abs = safe_join_root( + dst_root.to_string_lossy().as_ref(), + staging_relpath.as_str(), + ) + .map_err(resp_err_kverr) + .map_err(TransferWorkerExecutionError::fatal)?; let mut dst_file = open_create_file_with_parent_dir_chmod_retry(&staging_abs) .map_err(TransferWorkerExecutionError::fatal)?; dst_file @@ -5254,14 +5315,14 @@ where let remaining = file.size.saturating_sub(copied); let chunk = coordinator.read_chunk(file, copied, remaining.min(CHUNK_BYTES as i64))?; if chunk.is_empty() { - return Err(TransferWorkerExecutionError::fatal(resp_err_kverr(KvError::Api( - ApiError::InvalidArgument { + return Err(TransferWorkerExecutionError::fatal(resp_err_kverr( + KvError::Api(ApiError::InvalidArgument { detail: format!( "transfer worker source ended before expected size: relpath={} expected={} copied={}", file.relpath, file.size, copied ), - }, - )))); + }), + ))); } dst_file .write_all(&chunk) @@ -5271,13 +5332,14 @@ where coordinator.record_written_bytes(chunk.len() as i64); } if copied != file.size { - return Err(TransferWorkerExecutionError::fatal(resp_err_kverr(KvError::Api( - ApiError::InvalidArgument { - detail: format!( - "transfer worker size mismatch before staging completion: relpath={} expected={} actual={}", - file.relpath, file.size, copied - ), - })))); + return Err(TransferWorkerExecutionError::fatal(resp_err_kverr( + KvError::Api(ApiError::InvalidArgument { + detail: format!( + "transfer worker size mismatch before staging completion: relpath={} expected={} actual={}", + file.relpath, file.size, copied + ), + }), + ))); } // The staged file is still invisible at this point, so one more checkpoint // keeps supersession able to stop the worker before any later visible @@ -5302,48 +5364,57 @@ fn execute_transfer_single_file( coordinator: &TransferWorkerCoordinator, ) -> Result where - ReadChunkFn: - Fn(&FluxonFsTransferManifestEntryWire, i64, i64) -> Result, TransferWorkerExecutionError>, + ReadChunkFn: Fn( + &FluxonFsTransferManifestEntryWire, + i64, + i64, + ) -> Result, TransferWorkerExecutionError>, CheckpointFn: Fn() -> Result<(), TransferWorkerExecutionError>, { coordinator.checkpoint_continue()?; - let prepared = match prepare_transfer_file_streaming(dst_root, staging_prefix, file, coordinator) { - Ok(v) => v, - Err(TransferWorkerExecutionError::Fatal(resp)) => { - if let Some(failed) = classify_transfer_failed_file(file, &resp) { - let staging_relpath = - transfer_staging_file_relpath(staging_prefix, file.relpath.as_str()) - .map_err(TransferWorkerExecutionError::fatal)?; - let staging_abs = safe_join_root( - dst_root.to_string_lossy().as_ref(), - staging_relpath.as_str(), - ) - .map_err(resp_err_kverr) - .map_err(TransferWorkerExecutionError::fatal)?; - match fs::remove_file(&staging_abs) { - Ok(()) => {} - Err(err) if err.kind() == ErrorKind::NotFound => {} - Err(err) => return Err(TransferWorkerExecutionError::fatal(resp_err_io(err))), + let prepared = + match prepare_transfer_file_streaming(dst_root, staging_prefix, file, coordinator) { + Ok(v) => v, + Err(TransferWorkerExecutionError::Fatal(resp)) => { + if let Some(failed) = classify_transfer_failed_file(file, &resp) { + let staging_relpath = + transfer_staging_file_relpath(staging_prefix, file.relpath.as_str()) + .map_err(TransferWorkerExecutionError::fatal)?; + let staging_abs = safe_join_root( + dst_root.to_string_lossy().as_ref(), + staging_relpath.as_str(), + ) + .map_err(resp_err_kverr) + .map_err(TransferWorkerExecutionError::fatal)?; + match fs::remove_file(&staging_abs) { + Ok(()) => {} + Err(err) if err.kind() == ErrorKind::NotFound => {} + Err(err) => { + return Err(TransferWorkerExecutionError::fatal(resp_err_io(err))); + } + } + return Ok(TransferWorkerLaneOutcome::Failed( + TransferWorkerLaneFailedFileResult { result: failed }, + )); } - return Ok(TransferWorkerLaneOutcome::Failed( - TransferWorkerLaneFailedFileResult { result: failed }, - )); + return Err(TransferWorkerExecutionError::Fatal(resp)); } - return Err(TransferWorkerExecutionError::Fatal(resp)); - } - Err(err) => return Err(err), - }; + Err(err) => return Err(err), + }; coordinator.checkpoint_continue()?; - let result = promote_prepared_transfer_file(dst_root, PreparedTransferFile { - staging_relpath: prepared.staging_relpath.clone(), - final_relpath: prepared.final_relpath.clone(), - visible_size: prepared.visible_size, - }) + let result = promote_prepared_transfer_file( + dst_root, + PreparedTransferFile { + staging_relpath: prepared.staging_relpath.clone(), + final_relpath: prepared.final_relpath.clone(), + visible_size: prepared.visible_size, + }, + ) .map_err(TransferWorkerExecutionError::fatal); match result { - Ok(result) => Ok(TransferWorkerLaneOutcome::Visible(TransferWorkerLaneFileResult { - result, - })), + Ok(result) => Ok(TransferWorkerLaneOutcome::Visible( + TransferWorkerLaneFileResult { result }, + )), Err(TransferWorkerExecutionError::Fatal(resp)) => { if let Some(failed) = classify_transfer_failed_file(file, &resp) { let staging_abs = safe_join_root( @@ -5374,8 +5445,11 @@ fn execute_transfer_empty_dir( coordinator: &TransferWorkerCoordinator, ) -> Result where - ReadChunkFn: - Fn(&FluxonFsTransferManifestEntryWire, i64, i64) -> Result, TransferWorkerExecutionError>, + ReadChunkFn: Fn( + &FluxonFsTransferManifestEntryWire, + i64, + i64, + ) -> Result, TransferWorkerExecutionError>, CheckpointFn: Fn() -> Result<(), TransferWorkerExecutionError>, { coordinator.checkpoint_continue()?; @@ -5393,11 +5467,14 @@ fn execute_transfer_worker_assignment_with_policy( read_chunk: ReadChunkFn, ) -> Result where - ReadChunkFn: - Fn(&FluxonFsTransferManifestEntryWire, i64, i64) -> Result, TransferWorkerExecutionError> - + Send - + Sync - + 'static, + ReadChunkFn: Fn( + &FluxonFsTransferManifestEntryWire, + i64, + i64, + ) -> Result, TransferWorkerExecutionError> + + Send + + Sync + + 'static, CheckpointFn: Fn() -> Result<(), TransferWorkerExecutionError> + Send + Sync + 'static, { let policy = policy.normalized(); @@ -5424,11 +5501,14 @@ fn execute_transfer_worker_assignment_with_policy_and_progress Result where - ReadChunkFn: - Fn(&FluxonFsTransferManifestEntryWire, i64, i64) -> Result, TransferWorkerExecutionError> - + Send - + Sync - + 'static, + ReadChunkFn: Fn( + &FluxonFsTransferManifestEntryWire, + i64, + i64, + ) -> Result, TransferWorkerExecutionError> + + Send + + Sync + + 'static, CheckpointFn: Fn() -> Result<(), TransferWorkerExecutionError> + Send + Sync + 'static, { create_dir_all_with_parent_dir_chmod_retry(dst_root) @@ -5436,9 +5516,11 @@ where let manifest = FluxonFsTransferManifestWire::decode_from_blob(assignment.manifest_blob.as_slice()) .map_err(|e| { - TransferWorkerExecutionError::fatal(resp_err_kverr(KvError::Api(ApiError::InvalidArgument { - detail: format!("decode transfer worker manifest failed: {}", e), - }))) + TransferWorkerExecutionError::fatal(resp_err_kverr(KvError::Api( + ApiError::InvalidArgument { + detail: format!("decode transfer worker manifest failed: {}", e), + }, + ))) })?; if transfer_manifest_is_empty_dirs_only_batch(&manifest, assignment.collect_infos.as_slice()) { // Empty-dir-only batches never generate byte-based ramp-up signals, so @@ -5664,10 +5746,16 @@ fn promote_prepared_transfer_file( dst_root: &PathBuf, file: PreparedTransferFile, ) -> Result { - let staging_abs = safe_join_root(dst_root.to_string_lossy().as_ref(), file.staging_relpath.as_str()) - .map_err(resp_err_kverr)?; - let final_abs = safe_join_root(dst_root.to_string_lossy().as_ref(), file.final_relpath.as_str()) - .map_err(resp_err_kverr)?; + let staging_abs = safe_join_root( + dst_root.to_string_lossy().as_ref(), + file.staging_relpath.as_str(), + ) + .map_err(resp_err_kverr)?; + let final_abs = safe_join_root( + dst_root.to_string_lossy().as_ref(), + file.final_relpath.as_str(), + ) + .map_err(resp_err_kverr)?; rename_with_dst_parent_dir_chmod_retry(&staging_abs, &final_abs)?; Ok(FluxonFsTransferWorkerFileResultWire { relpath: file.final_relpath.clone(), @@ -5694,15 +5782,15 @@ fn prepare_transfer_collect_info_materialization( ), })) })?; - let staging_relpath = transfer_collect_info_staging_relpath( - batch_id, - worker_task_id, - collect_info.collect_kind, - )?; + let staging_relpath = + transfer_collect_info_staging_relpath(batch_id, worker_task_id, collect_info.collect_kind)?; ensure_transfer_parent_dirs(dst_root, staging_relpath.as_str())?; ensure_transfer_parent_dirs(dst_root, output_relpath.as_str())?; - let staging_abs = safe_join_root(dst_root.to_string_lossy().as_ref(), staging_relpath.as_str()) - .map_err(resp_err_kverr)?; + let staging_abs = safe_join_root( + dst_root.to_string_lossy().as_ref(), + staging_relpath.as_str(), + ) + .map_err(resp_err_kverr)?; let mut dst_file = open_create_file_with_parent_dir_chmod_retry(&staging_abs)?; dst_file.set_len(0).map_err(resp_err_io)?; dst_file @@ -5723,14 +5811,15 @@ fn transfer_collect_info_staging_relpath( worker_task_id: &str, collect_kind: FluxonFsTransferCollectInfoKind, ) -> Result { - let output_relpath = transfer_collect_info_output_relpath(batch_id, collect_kind).map_err(|detail| { - resp_err_kverr(KvError::Api(ApiError::InvalidArgument { - detail: format!( - "build transfer collect info output relpath failed: batch_id={} err={}", - batch_id, detail - ), - })) - })?; + let output_relpath = + transfer_collect_info_output_relpath(batch_id, collect_kind).map_err(|detail| { + resp_err_kverr(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "build transfer collect info output relpath failed: batch_id={} err={}", + batch_id, detail + ), + })) + })?; Ok(format!("{}.{}.fluxon.part", output_relpath, worker_task_id)) } @@ -5750,9 +5839,12 @@ fn prune_empty_parent_dirs(mut current: PathBuf, root: &PathBuf) -> Result<(), F Ok(()) } -fn cleanup_attempt_staging_prefix(dst_root: &PathBuf, staging_prefix: &str) -> Result<(), FlatDict> { - let staging_abs = - safe_join_root(dst_root.to_string_lossy().as_ref(), staging_prefix).map_err(resp_err_kverr)?; +fn cleanup_attempt_staging_prefix( + dst_root: &PathBuf, + staging_prefix: &str, +) -> Result<(), FlatDict> { + let staging_abs = safe_join_root(dst_root.to_string_lossy().as_ref(), staging_prefix) + .map_err(resp_err_kverr)?; match fs::remove_dir_all(&staging_abs) { Ok(()) => {} Err(err) if err.kind() == ErrorKind::NotFound => return Ok(()), @@ -5865,7 +5957,8 @@ pub(crate) fn read_transfer_chunk_from_root_dir_abs( return Ok(Vec::new()); } let to_read = std::cmp::min(length, size - offset) as usize; - f.seek(SeekFrom::Start(offset as u64)).map_err(resp_err_io)?; + f.seek(SeekFrom::Start(offset as u64)) + .map_err(resp_err_io)?; let mut buf = vec![0u8; to_read]; f.read_exact(&mut buf).map_err(resp_err_io)?; Ok(buf) @@ -5881,11 +5974,14 @@ pub(crate) fn execute_transfer_worker_assignment( read_chunk: ReadChunkFn, ) -> Result where - ReadChunkFn: - Fn(&FluxonFsTransferManifestEntryWire, i64, i64) -> Result, TransferWorkerExecutionError> - + Send - + Sync - + 'static, + ReadChunkFn: Fn( + &FluxonFsTransferManifestEntryWire, + i64, + i64, + ) -> Result, TransferWorkerExecutionError> + + Send + + Sync + + 'static, CheckpointFn: Fn() -> Result<(), TransferWorkerExecutionError> + Send + Sync + 'static, { execute_transfer_worker_assignment_with_policy( @@ -5943,12 +6039,19 @@ pub(super) fn handle_transfer_read(exports: &AgentExportsHandle, payload: FlatDi Ok(v) => v, Err(e) => return resp_err_kverr(e), }; - let buf = - match read_transfer_chunk_from_root_dir_abs(root_dir_abs.as_str(), relpath.as_str(), offset, length) { - Ok(v) => v, - Err(resp) => return resp, - }; - resp_ok(BTreeMap::from([("data".to_string(), FlatValue::Bytes(buf))])) + let buf = match read_transfer_chunk_from_root_dir_abs( + root_dir_abs.as_str(), + relpath.as_str(), + offset, + length, + ) { + Ok(v) => v, + Err(resp) => return resp, + }; + resp_ok(BTreeMap::from([( + "data".to_string(), + FlatValue::Bytes(buf), + )])) } pub(super) fn handle_transfer_stream_open( @@ -6010,7 +6113,9 @@ pub(super) fn handle_transfer_worker( Err(resp) => return resp, }; match registry.launch_task(api, master_id, exports, assignment) { - Ok(result) => encode_transfer_worker_launch_result(&result, "transfer worker launch result"), + Ok(result) => { + encode_transfer_worker_launch_result(&result, "transfer worker launch result") + } Err(resp) => resp, } } @@ -6086,15 +6191,15 @@ mod tests { .collect() } - fn assert_all_child_scan_units_are_subtree_streaming( - result: &FluxonFsTransferScanResultWire, - ) { - assert!(result - .child_scan_units - .iter() - .all(|child| child.scan_mode == FluxonFsTransferScanMode::SubtreeStreaming)); - } - + fn assert_all_child_scan_units_are_subtree_streaming(result: &FluxonFsTransferScanResultWire) { + assert!( + result + .child_scan_units + .iter() + .all(|child| child.scan_mode == FluxonFsTransferScanMode::SubtreeStreaming) + ); + } + fn ok_bool(resp: &FlatDict) -> bool { matches!(resp.get("ok"), Some(FlatValue::Bool(true))) } @@ -6106,10 +6211,7 @@ mod tests { panic!("unexpected open result fatal decode error: {:?}", other) } Err(TransferWorkerRpcFailure::Retryable { detail }) => { - panic!( - "unexpected open result retryable decode error: {}", - detail - ) + panic!("unexpected open result retryable decode error: {}", detail) } } } @@ -6121,10 +6223,7 @@ mod tests { panic!("unexpected next result fatal decode error: {:?}", other) } Err(TransferWorkerRpcFailure::Retryable { detail }) => { - panic!( - "unexpected next result retryable decode error: {}", - detail - ) + panic!("unexpected next result retryable decode error: {}", detail) } } } @@ -6140,10 +6239,7 @@ mod tests { .collect() } - fn test_worker_assignment( - relpath: &str, - size: i64, - ) -> FluxonFsTransferWorkerAssignmentWire { + fn test_worker_assignment(relpath: &str, size: i64) -> FluxonFsTransferWorkerAssignmentWire { FluxonFsTransferWorkerAssignmentWire { job_id: "job".to_string(), batch_id: "batch".to_string(), @@ -6158,12 +6254,13 @@ mod tests { root_relpath: ".".to_string(), staging_prefix: ".fluxon.stage/job/batch".to_string(), lease_expire_unix_ms: 0, - manifest_blob: build_transfer_manifest_blob(vec![ - FluxonFsTransferScanFrontierEntry { + manifest_blob: build_transfer_manifest_blob( + vec![FluxonFsTransferScanFrontierEntry { relpath: relpath.to_string(), size, - }, - ], Vec::new()) + }], + Vec::new(), + ) .unwrap(), collect_infos: Vec::new(), } @@ -6183,7 +6280,11 @@ mod tests { read_chunk: ReadChunkFn, ) -> TransferWorkerCoordinator where - ReadChunkFn: Fn(&FluxonFsTransferManifestEntryWire, i64, i64) -> Result, TransferWorkerExecutionError>, + ReadChunkFn: Fn( + &FluxonFsTransferManifestEntryWire, + i64, + i64, + ) -> Result, TransferWorkerExecutionError>, CheckpointFn: Fn() -> Result<(), TransferWorkerExecutionError>, { let policy = Arc::new(TransferWorkerLanePolicy::production_default()); @@ -6217,16 +6318,19 @@ mod tests { #[test] fn build_transfer_manifest_blob_round_trips_entries() { - let blob = build_transfer_manifest_blob(vec![ - FluxonFsTransferScanFrontierEntry { - relpath: "a".to_string(), - size: 1, - }, - FluxonFsTransferScanFrontierEntry { - relpath: "b/c".to_string(), - size: 2, - }, - ], vec!["empty".to_string()]) + let blob = build_transfer_manifest_blob( + vec![ + FluxonFsTransferScanFrontierEntry { + relpath: "a".to_string(), + size: 1, + }, + FluxonFsTransferScanFrontierEntry { + relpath: "b/c".to_string(), + size: 2, + }, + ], + vec!["empty".to_string()], + ) .unwrap(); let manifest = FluxonFsTransferManifestWire::decode_from_blob(&blob).unwrap(); assert_eq!(manifest.entry_count, 2); @@ -6250,11 +6354,12 @@ mod tests { #[test] fn materialize_transfer_collect_info_writes_task_scoped_staging_then_output_file() { let root = TempDir::new().unwrap(); - let collect_infos = build_symlink_collect_infos(vec![FluxonFsTransferSymlinkNoticeEntryWire { - relpath: "root/link-file.bin".to_string(), - link_target: "target/file.bin".to_string(), - }]) - .unwrap(); + let collect_infos = + build_symlink_collect_infos(vec![FluxonFsTransferSymlinkNoticeEntryWire { + relpath: "root/link-file.bin".to_string(), + link_target: "target/file.bin".to_string(), + }]) + .unwrap(); let prepared = prepare_transfer_collect_info_materialization( &root.path().to_path_buf(), "batch-1", @@ -6383,7 +6488,10 @@ mod tests { &exports, FlatDict::from([ ("export".to_string(), FlatValue::String("src".to_string())), - ("relpath".to_string(), FlatValue::String("f.bin".to_string())), + ( + "relpath".to_string(), + FlatValue::String("f.bin".to_string()), + ), ("offset".to_string(), FlatValue::Int64(2)), ("length".to_string(), FlatValue::Int64(3)), ]), @@ -6398,7 +6506,10 @@ mod tests { &exports, FlatDict::from([ ("export".to_string(), FlatValue::String("src".to_string())), - ("relpath".to_string(), FlatValue::String("f.bin".to_string())), + ( + "relpath".to_string(), + FlatValue::String("f.bin".to_string()), + ), ("offset".to_string(), FlatValue::Int64(6)), ("length".to_string(), FlatValue::Int64(1)), ]), @@ -6423,7 +6534,10 @@ mod tests { &exports, FlatDict::from([ ("export".to_string(), FlatValue::String("src".to_string())), - ("relpath".to_string(), FlatValue::String("f.bin".to_string())), + ( + "relpath".to_string(), + FlatValue::String("f.bin".to_string()), + ), ("offset".to_string(), FlatValue::Int64(1)), ("length".to_string(), FlatValue::Int64(3)), ]), @@ -6446,9 +6560,15 @@ mod tests { &exports, FlatDict::from([ ("export".to_string(), FlatValue::String("src".to_string())), - ("relpath".to_string(), FlatValue::String("f.bin".to_string())), + ( + "relpath".to_string(), + FlatValue::String("f.bin".to_string()), + ), ("offset".to_string(), FlatValue::Int64(0)), - ("length".to_string(), FlatValue::Int64(CHUNK_BYTES as i64 + 1)), + ( + "length".to_string(), + FlatValue::Int64(CHUNK_BYTES as i64 + 1), + ), ]), ); assert!(matches!(resp.get("ok"), Some(FlatValue::Bool(false)))); @@ -6470,7 +6590,10 @@ mod tests { FlatValue::String("task-0".to_string()), ), ("export".to_string(), FlatValue::String("src".to_string())), - ("relpath".to_string(), FlatValue::String("f.bin".to_string())), + ( + "relpath".to_string(), + FlatValue::String("f.bin".to_string()), + ), ("initial_offset".to_string(), FlatValue::Int64(0)), ]), ); @@ -6551,7 +6674,10 @@ mod tests { FlatValue::String("task-1".to_string()), ), ("export".to_string(), FlatValue::String("src".to_string())), - ("relpath".to_string(), FlatValue::String("f.bin".to_string())), + ( + "relpath".to_string(), + FlatValue::String("f.bin".to_string()), + ), ("initial_offset".to_string(), FlatValue::Int64(0)), ]), ); @@ -6584,7 +6710,10 @@ mod tests { ("length".to_string(), FlatValue::Int64(2)), ]), ); - assert!(matches!(invalid_resp.get("ok"), Some(FlatValue::Bool(false)))); + assert!(matches!( + invalid_resp.get("ok"), + Some(FlatValue::Bool(false)) + )); } #[test] @@ -6603,7 +6732,10 @@ mod tests { FlatValue::String("task-2".to_string()), ), ("export".to_string(), FlatValue::String("src".to_string())), - ("relpath".to_string(), FlatValue::String("f.bin".to_string())), + ( + "relpath".to_string(), + FlatValue::String("f.bin".to_string()), + ), ("initial_offset".to_string(), FlatValue::Int64(3)), ]), ); @@ -6647,7 +6779,10 @@ mod tests { FlatValue::String("task-3".to_string()), ), ("export".to_string(), FlatValue::String("src".to_string())), - ("relpath".to_string(), FlatValue::String("f.bin".to_string())), + ( + "relpath".to_string(), + FlatValue::String("f.bin".to_string()), + ), ("initial_offset".to_string(), FlatValue::Int64(3)), ]), ); @@ -6718,7 +6853,10 @@ mod tests { let result = decode_result_json(&resp); assert!(result.finished); assert!(result.direct_files_only_batches.is_empty()); - assert_eq!(child_scan_unit_roots(&result), vec!["root/child".to_string()]); + assert_eq!( + child_scan_unit_roots(&result), + vec!["root/child".to_string()] + ); assert_all_child_scan_units_are_subtree_streaming(&result); assert!(result.full_dir_batches.is_empty()); } @@ -6781,7 +6919,8 @@ mod tests { } #[test] - fn handle_transfer_scan_assignment_groups_empty_children_into_direct_batch_without_direct_files() { + fn handle_transfer_scan_assignment_groups_empty_children_into_direct_batch_without_direct_files() + { let root = TempDir::new().unwrap(); write_file(&root, "root/big/data.bin", b"12345"); fs::create_dir_all(root.path().join("root/empty-a")).unwrap(); @@ -6814,9 +6953,10 @@ mod tests { assert_eq!(child_scan_unit_roots(&result), vec!["root/big".to_string()]); assert_all_child_scan_units_are_subtree_streaming(&result); assert!(result.full_dir_batches.is_empty()); - let direct_manifest = - FluxonFsTransferManifestWire::decode_from_blob(&result.direct_files_only_batches[0].manifest_blob) - .unwrap(); + let direct_manifest = FluxonFsTransferManifestWire::decode_from_blob( + &result.direct_files_only_batches[0].manifest_blob, + ) + .unwrap(); assert!(direct_manifest.entries.is_empty()); assert_eq!( direct_manifest.empty_dir_relpaths, @@ -6854,16 +6994,17 @@ mod tests { assert_eq!(result.direct_files_only_batches.len(), 1); assert_eq!(result.full_dir_batches.len(), 0); assert_eq!(result.child_scan_units.len(), 1); - assert_eq!(result.child_scan_units[0].root_relpath, "root/huge".to_string()); + assert_eq!( + result.child_scan_units[0].root_relpath, + "root/huge".to_string() + ); let manifest = FluxonFsTransferManifestWire::decode_from_blob( &result.direct_files_only_batches[0].manifest_blob, ) .unwrap(); assert!(manifest.entries.is_empty()); assert!(!manifest.empty_dir_relpaths.is_empty()); - assert!( - manifest.empty_dir_relpaths.len() <= TRANSFER_MERGEABLE_EMPTY_DIR_BUDGET - ); + assert!(manifest.empty_dir_relpaths.len() <= TRANSFER_MERGEABLE_EMPTY_DIR_BUDGET); assert!( estimate_empty_dir_manifest_bytes(&manifest.empty_dir_relpaths) <= TRANSFER_MERGEABLE_EMPTY_DIR_ESTIMATED_BYTES_BUDGET @@ -6879,10 +7020,10 @@ mod tests { )) + 1; for idx in 0..child_count { - fs::create_dir_all(root.path().join(format!( - "root/branch-{idx:05}/{}", - "x".repeat(200) - ))) + fs::create_dir_all( + root.path() + .join(format!("root/branch-{idx:05}/{}", "x".repeat(200))), + ) .unwrap(); } let result = build_transfer_scan_result_for_root_dir_abs( @@ -6908,10 +7049,12 @@ mod tests { assert!(!result.finished); assert!(result.direct_files_only_batches.is_empty()); assert!(!result.child_scan_units.is_empty()); - assert!(result - .child_scan_units - .iter() - .any(|child| child.scan_mode == FluxonFsTransferScanMode::FullTree)); + assert!( + result + .child_scan_units + .iter() + .any(|child| child.scan_mode == FluxonFsTransferScanMode::FullTree) + ); assert!(result.child_scan_units.iter().all(|child| { child.scan_mode == FluxonFsTransferScanMode::FullTree || child.scan_mode == FluxonFsTransferScanMode::SubtreeStreaming @@ -6963,10 +7106,16 @@ mod tests { assert!(!continue_locally); assert_eq!(next_event_seq_no, 9); assert_eq!(events.len(), 2); - assert_eq!(events[0].event_kind, FluxonFsTransferScanEventKindWire::Append); + assert_eq!( + events[0].event_kind, + FluxonFsTransferScanEventKindWire::Append + ); assert_eq!(events[0].event_seq_no, 7); assert_eq!(events[0].full_dir_batches.len(), 1); - assert_eq!(events[1].event_kind, FluxonFsTransferScanEventKindWire::Finished); + assert_eq!( + events[1].event_kind, + FluxonFsTransferScanEventKindWire::Finished + ); assert_eq!(events[1].event_seq_no, 8); assert!(events[1].direct_files_only_batches.is_empty()); assert!(events[1].child_scan_units.is_empty()); @@ -6997,17 +7146,21 @@ mod tests { skip_entries: Vec::new(), }; - let first = build_transfer_scan_result_for_root_dir_abs( - root.path().to_str().unwrap(), - &assignment, - ) - .unwrap(); + let first = + build_transfer_scan_result_for_root_dir_abs(root.path().to_str().unwrap(), &assignment) + .unwrap(); assert!(!first.finished); assert!(!first.direct_files_only_batches.is_empty()); assert!(first.full_dir_batches.is_empty()); assert_eq!(first.child_scan_units.len(), 1); - assert_eq!(first.child_scan_units[0].scan_unit_id, assignment.scan_unit_id); - assert_eq!(first.child_scan_units[0].root_relpath, assignment.root_relpath); + assert_eq!( + first.child_scan_units[0].scan_unit_id, + assignment.scan_unit_id + ); + assert_eq!( + first.child_scan_units[0].root_relpath, + assignment.root_relpath + ); assert_eq!(first.child_scan_units[0].generation, assignment.generation); let first_entry_count = first .direct_files_only_batches @@ -7019,7 +7172,10 @@ mod tests { .len() }) .sum::(); - assert_eq!(first_entry_count, TRANSFER_SCAN_ROOT_LISTING_SLICE_ENTRY_LIMIT); + assert_eq!( + first_entry_count, + TRANSFER_SCAN_ROOT_LISTING_SLICE_ENTRY_LIMIT + ); let second_assignment = FluxonFsTransferScanAssignmentWire { scan_task_id: "task-2".to_string(), @@ -7086,7 +7242,8 @@ mod tests { } #[test] - fn build_transfer_scan_result_root_direct_fanout_only_emits_child_scan_units_without_recursing() { + fn build_transfer_scan_result_root_direct_fanout_only_emits_child_scan_units_without_recursing() + { let root = TempDir::new().unwrap(); write_file(&root, "root/direct.bin", b"abc"); write_file(&root, "root/child/payload.bin", b"xyz"); @@ -7114,14 +7271,18 @@ mod tests { assert_eq!(result.direct_files_only_batches.len(), 1); assert_eq!(result.child_scan_units.len(), 1); assert!(result.full_dir_batches.is_empty()); - assert_eq!(result.child_scan_units[0].root_relpath, "root/child".to_string()); + assert_eq!( + result.child_scan_units[0].root_relpath, + "root/child".to_string() + ); assert_eq!( result.child_scan_units[0].scan_mode, FluxonFsTransferScanMode::FullTree ); - let manifest = - FluxonFsTransferManifestWire::decode_from_blob(&result.direct_files_only_batches[0].manifest_blob) - .unwrap(); + let manifest = FluxonFsTransferManifestWire::decode_from_blob( + &result.direct_files_only_batches[0].manifest_blob, + ) + .unwrap(); assert_eq!( manifest.entries, vec![FluxonFsTransferManifestEntryWire { @@ -7133,7 +7294,8 @@ mod tests { } #[test] - fn build_transfer_scan_result_directory_direct_fanout_only_emits_child_scan_units_without_recursing() { + fn build_transfer_scan_result_directory_direct_fanout_only_emits_child_scan_units_without_recursing() + { let root = TempDir::new().unwrap(); write_file(&root, "root/child/direct.bin", b"abc"); write_file(&root, "root/child/grand/payload.bin", b"xyz"); @@ -7161,14 +7323,18 @@ mod tests { assert_eq!(result.direct_files_only_batches.len(), 1); assert_eq!(result.child_scan_units.len(), 1); assert!(result.full_dir_batches.is_empty()); - assert_eq!(result.child_scan_units[0].root_relpath, "root/child/grand".to_string()); + assert_eq!( + result.child_scan_units[0].root_relpath, + "root/child/grand".to_string() + ); assert_eq!( result.child_scan_units[0].scan_mode, FluxonFsTransferScanMode::FullTree ); - let manifest = - FluxonFsTransferManifestWire::decode_from_blob(&result.direct_files_only_batches[0].manifest_blob) - .unwrap(); + let manifest = FluxonFsTransferManifestWire::decode_from_blob( + &result.direct_files_only_batches[0].manifest_blob, + ) + .unwrap(); assert_eq!( manifest.entries, vec![FluxonFsTransferManifestEntryWire { @@ -7206,10 +7372,14 @@ mod tests { .unwrap(); assert!(result.finished); assert_eq!(result.direct_files_only_batches.len(), 1); - assert_eq!(result.direct_files_only_batches[0].root_relpath, "root/child"); - let manifest = - FluxonFsTransferManifestWire::decode_from_blob(&result.direct_files_only_batches[0].manifest_blob) - .unwrap(); + assert_eq!( + result.direct_files_only_batches[0].root_relpath, + "root/child" + ); + let manifest = FluxonFsTransferManifestWire::decode_from_blob( + &result.direct_files_only_batches[0].manifest_blob, + ) + .unwrap(); assert_eq!( manifest.entries, vec![FluxonFsTransferManifestEntryWire { @@ -7218,7 +7388,10 @@ mod tests { }] ); assert!(manifest.empty_dir_relpaths.is_empty()); - assert_eq!(child_scan_unit_roots(&result), vec!["root/child/grand".to_string()]); + assert_eq!( + child_scan_unit_roots(&result), + vec!["root/child/grand".to_string()] + ); assert_all_child_scan_units_are_subtree_streaming(&result); assert!(result.full_dir_batches.is_empty()); } @@ -7253,10 +7426,14 @@ mod tests { assert!(result.finished); assert_eq!(result.direct_files_only_batches.len(), 1); assert_eq!(result.child_scan_units.len(), 1); - assert_eq!(result.child_scan_units[0].root_relpath, "root/child".to_string()); - let manifest = - FluxonFsTransferManifestWire::decode_from_blob(&result.direct_files_only_batches[0].manifest_blob) - .unwrap(); + assert_eq!( + result.child_scan_units[0].root_relpath, + "root/child".to_string() + ); + let manifest = FluxonFsTransferManifestWire::decode_from_blob( + &result.direct_files_only_batches[0].manifest_blob, + ) + .unwrap(); assert_eq!( manifest.entries, vec![FluxonFsTransferManifestEntryWire { @@ -7330,9 +7507,10 @@ mod tests { assert_eq!(result.direct_files_only_batches.len(), 1); assert!(result.child_scan_units.is_empty()); assert!(result.full_dir_batches.is_empty()); - let manifest = - FluxonFsTransferManifestWire::decode_from_blob(&result.direct_files_only_batches[0].manifest_blob) - .unwrap(); + let manifest = FluxonFsTransferManifestWire::decode_from_blob( + &result.direct_files_only_batches[0].manifest_blob, + ) + .unwrap(); assert_eq!( manifest.entries, vec![FluxonFsTransferManifestEntryWire { @@ -7407,7 +7585,10 @@ mod tests { assert!(result.finished); assert_eq!(result.direct_files_only_batches.len(), 1); assert_eq!(result.child_scan_units.len(), 1); - assert_eq!(result.child_scan_units[0].root_relpath, "root/child-b".to_string()); + assert_eq!( + result.child_scan_units[0].root_relpath, + "root/child-b".to_string() + ); assert_eq!( result.child_scan_units[0].scan_mode, FluxonFsTransferScanMode::FullTree @@ -7447,9 +7628,10 @@ mod tests { assert_eq!(result.direct_files_only_batches.len(), 1); assert!(result.child_scan_units.is_empty()); assert!(result.full_dir_batches.is_empty()); - let manifest = - FluxonFsTransferManifestWire::decode_from_blob(&result.direct_files_only_batches[0].manifest_blob) - .unwrap(); + let manifest = FluxonFsTransferManifestWire::decode_from_blob( + &result.direct_files_only_batches[0].manifest_blob, + ) + .unwrap(); assert_eq!( manifest.entries, vec![FluxonFsTransferManifestEntryWire { @@ -7490,9 +7672,10 @@ mod tests { assert!(result.direct_files_only_batches.is_empty()); assert!(result.child_scan_units.is_empty()); assert_eq!(result.full_dir_batches.len(), 1); - let manifest = - FluxonFsTransferManifestWire::decode_from_blob(&result.full_dir_batches[0].manifest_blob) - .unwrap(); + let manifest = FluxonFsTransferManifestWire::decode_from_blob( + &result.full_dir_batches[0].manifest_blob, + ) + .unwrap(); assert!(manifest.entries.is_empty()); assert_eq!(manifest.empty_dir_relpaths, vec!["root".to_string()]); } @@ -7533,7 +7716,8 @@ mod tests { } #[test] - fn handle_transfer_scan_assignment_does_not_reaggregate_root_when_descendant_batch_is_durable() { + fn handle_transfer_scan_assignment_does_not_reaggregate_root_when_descendant_batch_is_durable() + { let root = TempDir::new().unwrap(); write_file(&root, "root/direct.bin", b"abc"); write_file(&root, "root/big/data.bin", b"12345"); @@ -7579,21 +7763,29 @@ mod tests { size: 3, }] ); - assert!(result - .full_dir_batches - .iter() - .all(|batch| batch.root_relpath != "root")); - assert!(result - .full_dir_batches - .iter() - .all(|batch| batch.root_relpath != "root/big")); - assert_eq!(child_scan_unit_roots(&result), vec!["root/small".to_string()]); + assert!( + result + .full_dir_batches + .iter() + .all(|batch| batch.root_relpath != "root") + ); + assert!( + result + .full_dir_batches + .iter() + .all(|batch| batch.root_relpath != "root/big") + ); + assert_eq!( + child_scan_unit_roots(&result), + vec!["root/small".to_string()] + ); assert_all_child_scan_units_are_subtree_streaming(&result); assert!(result.full_dir_batches.is_empty()); } #[test] - fn handle_transfer_scan_assignment_honors_cross_generation_descendant_full_dir_during_restart() { + fn handle_transfer_scan_assignment_honors_cross_generation_descendant_full_dir_during_restart() + { let root = TempDir::new().unwrap(); write_file(&root, "root/direct.bin", b"abc"); write_file(&root, "root/big/data.bin", b"12345"); @@ -7639,21 +7831,29 @@ mod tests { size: 3, }] ); - assert!(result - .full_dir_batches - .iter() - .all(|batch| batch.root_relpath != "root")); - assert!(result - .full_dir_batches - .iter() - .all(|batch| batch.root_relpath != "root/big")); - assert_eq!(child_scan_unit_roots(&result), vec!["root/small".to_string()]); + assert!( + result + .full_dir_batches + .iter() + .all(|batch| batch.root_relpath != "root") + ); + assert!( + result + .full_dir_batches + .iter() + .all(|batch| batch.root_relpath != "root/big") + ); + assert_eq!( + child_scan_unit_roots(&result), + vec!["root/small".to_string()] + ); assert_all_child_scan_units_are_subtree_streaming(&result); assert!(result.full_dir_batches.is_empty()); } #[test] - fn handle_transfer_scan_assignment_replays_descendant_current_layer_when_only_partial_descendant_direct_files_batch_is_durable() { + fn handle_transfer_scan_assignment_replays_descendant_current_layer_when_only_partial_descendant_direct_files_batch_is_durable() + { let root = TempDir::new().unwrap(); write_file(&root, "root/child/a.bin", b"ab"); write_file(&root, "root/child/b.bin", b"cd"); @@ -7688,10 +7888,14 @@ mod tests { assert!(result.child_scan_units.is_empty()); assert!(result.full_dir_batches.is_empty()); assert_eq!(result.direct_files_only_batches.len(), 1); - assert_eq!(result.direct_files_only_batches[0].root_relpath, "root/child"); - let manifest = - FluxonFsTransferManifestWire::decode_from_blob(&result.direct_files_only_batches[0].manifest_blob) - .unwrap(); + assert_eq!( + result.direct_files_only_batches[0].root_relpath, + "root/child" + ); + let manifest = FluxonFsTransferManifestWire::decode_from_blob( + &result.direct_files_only_batches[0].manifest_blob, + ) + .unwrap(); assert_eq!( manifest.entries, vec![ @@ -7737,7 +7941,10 @@ mod tests { assert!(result.finished); assert!(result.direct_files_only_batches.is_empty()); - assert_eq!(child_scan_unit_roots(&result), vec!["root/parent".to_string()]); + assert_eq!( + child_scan_unit_roots(&result), + vec!["root/parent".to_string()] + ); assert_all_child_scan_units_are_subtree_streaming(&result); assert!(result.full_dir_batches.is_empty()); } @@ -7772,9 +7979,10 @@ mod tests { assert!(result.finished); assert_eq!(result.direct_files_only_batches.len(), 1); - let manifest = - FluxonFsTransferManifestWire::decode_from_blob(&result.direct_files_only_batches[0].manifest_blob) - .unwrap(); + let manifest = FluxonFsTransferManifestWire::decode_from_blob( + &result.direct_files_only_batches[0].manifest_blob, + ) + .unwrap(); assert_eq!( manifest.entries, vec![FluxonFsTransferManifestEntryWire { @@ -7782,7 +7990,10 @@ mod tests { size: 10, }] ); - assert_eq!(child_scan_unit_roots(&result), vec!["root/child".to_string()]); + assert_eq!( + child_scan_unit_roots(&result), + vec!["root/child".to_string()] + ); assert_all_child_scan_units_are_subtree_streaming(&result); assert!(result.full_dir_batches.is_empty()); } @@ -7820,7 +8031,10 @@ mod tests { assert!(ok_bool(&resp)); assert!(result.finished); - assert_eq!(child_scan_unit_roots(&result), vec!["root/blocked".to_string()]); + assert_eq!( + child_scan_unit_roots(&result), + vec!["root/blocked".to_string()] + ); assert_all_child_scan_units_are_subtree_streaming(&result); assert!(result.full_dir_batches.is_empty()); } @@ -7870,7 +8084,11 @@ mod tests { ); assert_eq!( child_scan_unit_roots(&result), - vec!["root/a".to_string(), "root/b".to_string(), "root/c".to_string()] + vec![ + "root/a".to_string(), + "root/b".to_string(), + "root/c".to_string() + ] ); assert_all_child_scan_units_are_subtree_streaming(&result); assert!(result.full_dir_batches.is_empty()); @@ -7905,7 +8123,10 @@ mod tests { ); let result = decode_result_json(&resp); assert_eq!(result.full_dir_batches.len(), 1); - assert_eq!(result.full_dir_batches[0].batch_kind, FluxonFsTransferBatchKind::SubtreeSlice); + assert_eq!( + result.full_dir_batches[0].batch_kind, + FluxonFsTransferBatchKind::SubtreeSlice + ); assert_eq!(result.full_dir_batches[0].collect_infos.len(), 1); assert_eq!( decode_symlink_notice_collect_blob( @@ -7957,11 +8178,15 @@ mod tests { assert!(result.direct_files_only_batches.is_empty()); assert!(result.child_scan_units.is_empty()); assert_eq!(result.full_dir_batches.len(), 1); - assert_eq!(result.full_dir_batches[0].batch_kind, FluxonFsTransferBatchKind::SubtreeSlice); + assert_eq!( + result.full_dir_batches[0].batch_kind, + FluxonFsTransferBatchKind::SubtreeSlice + ); assert_eq!(result.full_dir_batches[0].root_relpath, "root".to_string()); - let manifest = - FluxonFsTransferManifestWire::decode_from_blob(&result.full_dir_batches[0].manifest_blob) - .unwrap(); + let manifest = FluxonFsTransferManifestWire::decode_from_blob( + &result.full_dir_batches[0].manifest_blob, + ) + .unwrap(); assert_eq!( manifest.entries, vec![ @@ -7982,7 +8207,9 @@ mod tests { FluxonFsTransferCollectInfoKind::SymlinkNotice ); let mut notices = decode_symlink_notice_collect_blob( - direct_files_only_batch.collect_infos[0].collect_blob.as_slice() + direct_files_only_batch.collect_infos[0] + .collect_blob + .as_slice(), ); notices.sort_by(|a, b| a.relpath.cmp(&b.relpath)); assert_eq!( @@ -8004,16 +8231,17 @@ mod tests { fn prepare_transfer_file_from_chunks_promotes_staged_file_to_final_path() { let root = TempDir::new().unwrap(); let dst_root = root.path().to_path_buf(); - let coordinator = test_transfer_coordinator( - || Ok(()), - { - let chunks = Arc::new(Mutex::new(vec![b"ab".to_vec(), b"cde".to_vec(), Vec::new()])); - move |_file, _read_offset, _length| { - let mut chunks = chunks.lock(); - Ok(chunks.remove(0)) - } - }, - ); + let coordinator = test_transfer_coordinator(|| Ok(()), { + let chunks = Arc::new(Mutex::new(vec![ + b"ab".to_vec(), + b"cde".to_vec(), + Vec::new(), + ])); + move |_file, _read_offset, _length| { + let mut chunks = chunks.lock(); + Ok(chunks.remove(0)) + } + }); let prepared = prepare_transfer_file_streaming( &dst_root, ".fluxon.stage/job/batch", @@ -8038,32 +8266,31 @@ mod tests { fs::read(root.path().join("dir/file.bin")).unwrap(), b"abcde".to_vec() ); - assert!(!root - .path() - .join(".fluxon.stage/job/batch/dir/file.bin/file.bin.fluxon.part") - .exists()); + assert!( + !root + .path() + .join(".fluxon.stage/job/batch/dir/file.bin/file.bin.fluxon.part") + .exists() + ); } #[test] fn prepare_transfer_file_from_chunks_truncates_existing_staging_file() { let root = TempDir::new().unwrap(); let dst_root = root.path().to_path_buf(); - let stale_staging = - root.path() - .join(".fluxon.stage/job/batch/dir/file.bin/file.bin.fluxon.part"); + let stale_staging = root + .path() + .join(".fluxon.stage/job/batch/dir/file.bin/file.bin.fluxon.part"); fs::create_dir_all(stale_staging.parent().unwrap()).unwrap(); fs::write(&stale_staging, b"stale-data").unwrap(); - let coordinator = test_transfer_coordinator( - || Ok(()), - { - let chunks = Arc::new(Mutex::new(vec![b"xy".to_vec(), Vec::new()])); - move |_file, _read_offset, _length| { - let mut chunks = chunks.lock(); - Ok(chunks.remove(0)) - } - }, - ); + let coordinator = test_transfer_coordinator(|| Ok(()), { + let chunks = Arc::new(Mutex::new(vec![b"xy".to_vec(), Vec::new()])); + move |_file, _read_offset, _length| { + let mut chunks = chunks.lock(); + Ok(chunks.remove(0)) + } + }); let prepared = prepare_transfer_file_streaming( &dst_root, ".fluxon.stage/job/batch", @@ -8076,23 +8303,23 @@ mod tests { .unwrap(); promote_prepared_transfer_file(&dst_root, prepared).unwrap(); - assert_eq!(fs::read(root.path().join("dir/file.bin")).unwrap(), b"xy".to_vec()); + assert_eq!( + fs::read(root.path().join("dir/file.bin")).unwrap(), + b"xy".to_vec() + ); } #[test] fn prepare_transfer_file_from_chunks_rejects_size_mismatch_and_keeps_staging_file() { let root = TempDir::new().unwrap(); let dst_root = root.path().to_path_buf(); - let coordinator = test_transfer_coordinator( - || Ok(()), - { - let chunks = Arc::new(Mutex::new(vec![b"xy".to_vec(), Vec::new()])); - move |_file, _read_offset, _length| { - let mut chunks = chunks.lock(); - Ok(chunks.remove(0)) - } - }, - ); + let coordinator = test_transfer_coordinator(|| Ok(()), { + let chunks = Arc::new(Mutex::new(vec![b"xy".to_vec(), Vec::new()])); + move |_file, _read_offset, _length| { + let mut chunks = chunks.lock(); + Ok(chunks.remove(0)) + } + }); let err = prepare_transfer_file_streaming( &dst_root, ".fluxon.stage/job/batch", @@ -8275,15 +8502,10 @@ mod tests { let file_bytes = b"hello".to_vec(); let assignment = test_worker_assignment("dir/file.bin", file_bytes.len() as i64); - let result = execute_transfer_worker_assignment( - &assignment, - &dst_root, - || Ok(()), - { - let file_bytes = file_bytes.clone(); - move |_file, _read_offset, _length| Ok(file_bytes.clone()) - }, - ) + let result = execute_transfer_worker_assignment(&assignment, &dst_root, || Ok(()), { + let file_bytes = file_bytes.clone(); + move |_file, _read_offset, _length| Ok(file_bytes.clone()) + }) .unwrap(); assert_eq!(result.file_results.len(), 1); @@ -8303,7 +8525,10 @@ mod tests { create_dir_all_with_parent_dir_chmod_retry(&target).unwrap(); assert!(target.is_dir()); - assert_eq!(fs::metadata(&locked_parent).unwrap().permissions().mode() & 0o777, 0o777); + assert_eq!( + fs::metadata(&locked_parent).unwrap().permissions().mode() & 0o777, + 0o777 + ); } #[cfg(unix)] @@ -8318,21 +8543,19 @@ mod tests { let file_bytes = b"hello".to_vec(); let assignment = test_worker_assignment("dir/file.bin", file_bytes.len() as i64); - let result = execute_transfer_worker_assignment( - &assignment, - &dst_root, - || Ok(()), - { - let file_bytes = file_bytes.clone(); - move |_file, _read_offset, _length| Ok(file_bytes.clone()) - }, - ) + let result = execute_transfer_worker_assignment(&assignment, &dst_root, || Ok(()), { + let file_bytes = file_bytes.clone(); + move |_file, _read_offset, _length| Ok(file_bytes.clone()) + }) .unwrap(); assert_eq!(result.file_results.len(), 1); assert!(dst_root.is_dir()); assert_eq!(fs::read(dst_root.join("dir/file.bin")).unwrap(), file_bytes); - assert_eq!(fs::metadata(&locked_parent).unwrap().permissions().mode() & 0o777, 0o777); + assert_eq!( + fs::metadata(&locked_parent).unwrap().permissions().mode() & 0o777, + 0o777 + ); } #[test] @@ -8349,47 +8572,48 @@ mod tests { let assignment = assignment.clone(); let heartbeat_attempts = heartbeat_attempts.clone(); move || { - retry_transfer_worker_rpc_with_backoff( - &assignment, - "checkpoint", - "test-checkpoint", - BackoffConfig { - initial_secs: 0, - max_secs: 0, - }, - WarnConfig { - warn_interval_secs: 0, - }, - || { - let attempt = - heartbeat_attempts.fetch_add(1, Ordering::SeqCst) + 1; - if attempt < 3 { - return Err(TransferWorkerRpcFailure::Retryable { - detail: format!( - "transient heartbeat failure attempt={}", - attempt - ), - }); - } - Ok(()) - }, - ) - .map_err(TransferWorkerExecutionError::fatal) - } + retry_transfer_worker_rpc_with_backoff( + &assignment, + "checkpoint", + "test-checkpoint", + BackoffConfig { + initial_secs: 0, + max_secs: 0, + }, + WarnConfig { + warn_interval_secs: 0, + }, + || { + let attempt = heartbeat_attempts.fetch_add(1, Ordering::SeqCst) + 1; + if attempt < 3 { + return Err(TransferWorkerRpcFailure::Retryable { + detail: format!( + "transient heartbeat failure attempt={}", + attempt + ), + }); + } + Ok(()) + }, + ) + .map_err(TransferWorkerExecutionError::fatal) + } }, { let file_bytes = file_bytes.clone(); move |file, read_offset, _length| { - if file.relpath != "dir/file.bin" { - return Err(TransferWorkerExecutionError::fatal(resp_err_kverr(KvError::Api(ApiError::InvalidArgument { - detail: format!("unexpected file relpath: {}", file.relpath), - })))); - } - if read_offset == 0 { - return Ok(file_bytes.clone()); + if file.relpath != "dir/file.bin" { + return Err(TransferWorkerExecutionError::fatal(resp_err_kverr( + KvError::Api(ApiError::InvalidArgument { + detail: format!("unexpected file relpath: {}", file.relpath), + }), + ))); + } + if read_offset == 0 { + return Ok(file_bytes.clone()); + } + Ok(Vec::new()) } - Ok(Vec::new()) - } }, ) .unwrap(); @@ -8409,24 +8633,20 @@ mod tests { let file_bytes = b"payload".to_vec(); let assignment = test_worker_assignment("dir/file.bin", file_bytes.len() as i64); let read_attempts = Arc::new(AtomicUsize::new(0)); - let result = execute_transfer_worker_assignment( - &assignment, - &dst_root, - || Ok(()), - { - let assignment = assignment.clone(); - let file_bytes = file_bytes.clone(); - let read_attempts = read_attempts.clone(); - move |file, read_offset, _length| { + let result = execute_transfer_worker_assignment(&assignment, &dst_root, || Ok(()), { + let assignment = assignment.clone(); + let file_bytes = file_bytes.clone(); + let read_attempts = read_attempts.clone(); + move |file, read_offset, _length| { if file.relpath != "dir/file.bin" { - return Err(TransferWorkerExecutionError::fatal(resp_err_kverr(KvError::Api(ApiError::InvalidArgument { - detail: format!("unexpected file relpath: {}", file.relpath), - })))); + return Err(TransferWorkerExecutionError::fatal(resp_err_kverr( + KvError::Api(ApiError::InvalidArgument { + detail: format!("unexpected file relpath: {}", file.relpath), + }), + ))); } - let op_detail = format!( - "test-read relpath={} offset={}", - file.relpath, read_offset - ); + let op_detail = + format!("test-read relpath={} offset={}", file.relpath, read_offset); retry_transfer_worker_rpc_with_backoff( &assignment, "read_chunk", @@ -8443,10 +8663,7 @@ mod tests { let attempt = read_attempts.fetch_add(1, Ordering::SeqCst) + 1; if attempt < 3 { return Err(TransferWorkerRpcFailure::Retryable { - detail: format!( - "transient read failure attempt={}", - attempt - ), + detail: format!("transient read failure attempt={}", attempt), }); } return Ok(file_bytes.clone()); @@ -8456,8 +8673,7 @@ mod tests { ) .map_err(TransferWorkerExecutionError::fatal) } - }, - ) + }) .unwrap(); assert_eq!(read_attempts.load(Ordering::SeqCst), 3); @@ -8481,23 +8697,23 @@ mod tests { { let checkpoint_calls = checkpoint_calls.clone(); move || { - let calls = checkpoint_calls.fetch_add(1, Ordering::SeqCst) + 1; - if calls >= 4 { - return Err(TransferWorkerExecutionError::Stop( - FluxonFsTransferWorkerStopReasonWire::Superseded, - )); + let calls = checkpoint_calls.fetch_add(1, Ordering::SeqCst) + 1; + if calls >= 4 { + return Err(TransferWorkerExecutionError::Stop( + FluxonFsTransferWorkerStopReasonWire::Superseded, + )); + } + Ok(()) } - Ok(()) - } }, { let file_bytes = file_bytes.clone(); move |_file, read_offset, _length| { - if read_offset == 0 { - return Ok(file_bytes.clone()); + if read_offset == 0 { + return Ok(file_bytes.clone()); + } + Ok(Vec::new()) } - Ok(Vec::new()) - } }, ); assert!(matches!( @@ -8567,12 +8783,7 @@ mod tests { break; } if max_in_flight - .compare_exchange( - observed, - current, - Ordering::SeqCst, - Ordering::SeqCst, - ) + .compare_exchange(observed, current, Ordering::SeqCst, Ordering::SeqCst) .is_ok() { break; @@ -8588,8 +8799,14 @@ mod tests { assert_eq!(result.file_results.len(), 2); assert!(max_in_flight.load(Ordering::SeqCst) >= 2); - assert_eq!(fs::read(root.path().join("dir/a.bin")).unwrap(), b"xxx".to_vec()); - assert_eq!(fs::read(root.path().join("dir/b.bin")).unwrap(), b"xxx".to_vec()); + assert_eq!( + fs::read(root.path().join("dir/a.bin")).unwrap(), + b"xxx".to_vec() + ); + assert_eq!( + fs::read(root.path().join("dir/b.bin")).unwrap(), + b"xxx".to_vec() + ); } #[test] @@ -8597,29 +8814,25 @@ mod tests { let root = TempDir::new().unwrap(); let dst_root = root.path().to_path_buf(); let file_bytes = b"hello".to_vec(); - let collect_infos = build_symlink_collect_infos(vec![FluxonFsTransferSymlinkNoticeEntryWire { - relpath: "dir/link.bin".to_string(), - link_target: "dir/file.bin".to_string(), - }]) - .unwrap(); + let collect_infos = + build_symlink_collect_infos(vec![FluxonFsTransferSymlinkNoticeEntryWire { + relpath: "dir/link.bin".to_string(), + link_target: "dir/file.bin".to_string(), + }]) + .unwrap(); let assignment = FluxonFsTransferWorkerAssignmentWire { collect_infos: collect_infos.clone(), ..test_worker_assignment("dir/file.bin", file_bytes.len() as i64) }; - let result = execute_transfer_worker_assignment( - &assignment, - &dst_root, - || Ok(()), - { - let file_bytes = file_bytes.clone(); - move |_file, read_offset, _length| { - if read_offset == 0 { - return Ok(file_bytes.clone()); - } - Ok(Vec::new()) + let result = execute_transfer_worker_assignment(&assignment, &dst_root, || Ok(()), { + let file_bytes = file_bytes.clone(); + move |_file, read_offset, _length| { + if read_offset == 0 { + return Ok(file_bytes.clone()); } - }, - ) + Ok(Vec::new()) + } + }) .unwrap(); assert_eq!(result.file_results.len(), 1); @@ -8633,7 +8846,11 @@ mod tests { "fluxon_collect_info/batches/batch/symlinks.jsonl" ); assert_eq!( - fs::read(root.path().join("fluxon_collect_info/batches/batch/symlinks.jsonl")).unwrap(), + fs::read( + root.path() + .join("fluxon_collect_info/batches/batch/symlinks.jsonl") + ) + .unwrap(), collect_infos[0].collect_blob ); } @@ -8643,16 +8860,19 @@ mod tests { let root = TempDir::new().unwrap(); let dst_root = root.path().to_path_buf(); let assignment = FluxonFsTransferWorkerAssignmentWire { - manifest_blob: build_transfer_manifest_blob(vec![ - FluxonFsTransferScanFrontierEntry { - relpath: "dir/good.bin".to_string(), - size: 5, - }, - FluxonFsTransferScanFrontierEntry { - relpath: "dir/bad.bin".to_string(), - size: 5, - }, - ], Vec::new()) + manifest_blob: build_transfer_manifest_blob( + vec![ + FluxonFsTransferScanFrontierEntry { + relpath: "dir/good.bin".to_string(), + size: 5, + }, + FluxonFsTransferScanFrontierEntry { + relpath: "dir/bad.bin".to_string(), + size: 5, + }, + ], + Vec::new(), + ) .unwrap(), ..test_worker_assignment("dir/good.bin", 5) }; @@ -8816,20 +9036,16 @@ mod tests { .unwrap(); let progress_heartbeat_count = Arc::new(AtomicUsize::new(0)); - gate.ensure_continue( - false, - TRANSFER_WORKER_HEARTBEAT_EMPTY_DIR_PROGRESS_COUNT, - { - let progress_heartbeat_count = progress_heartbeat_count.clone(); - move |_heartbeat_unix_ms, heartbeat_detail| { - assert_eq!(heartbeat_detail, "empty_dir_progress"); - progress_heartbeat_count.fetch_add(1, Ordering::SeqCst); - Ok(FluxonFsTransferWorkerHeartbeatResultWire::continue_running( - chrono::Utc::now().timestamp_millis() + 60_000, - )) - } - }, - ) + gate.ensure_continue(false, TRANSFER_WORKER_HEARTBEAT_EMPTY_DIR_PROGRESS_COUNT, { + let progress_heartbeat_count = progress_heartbeat_count.clone(); + move |_heartbeat_unix_ms, heartbeat_detail| { + assert_eq!(heartbeat_detail, "empty_dir_progress"); + progress_heartbeat_count.fetch_add(1, Ordering::SeqCst); + Ok(FluxonFsTransferWorkerHeartbeatResultWire::continue_running( + chrono::Utc::now().timestamp_millis() + 60_000, + )) + } + }) .unwrap(); gate.ensure_continue( @@ -8927,20 +9143,15 @@ mod tests { let dst_root = root.path().to_path_buf(); let file_bytes = b"hello".to_vec(); let assignment = test_worker_assignment("dir/file.bin", file_bytes.len() as i64); - let result = execute_transfer_worker_assignment( - &assignment, - &dst_root, - || Ok(()), - { - let file_bytes = file_bytes.clone(); - move |_file, read_offset, _length| { - if read_offset == 0 { - return Ok(file_bytes.clone()); - } - Ok(Vec::new()) + let result = execute_transfer_worker_assignment(&assignment, &dst_root, || Ok(()), { + let file_bytes = file_bytes.clone(); + move |_file, read_offset, _length| { + if read_offset == 0 { + return Ok(file_bytes.clone()); } - }, - ) + Ok(Vec::new()) + } + }) .unwrap(); assert_eq!(result.file_results.len(), 1); @@ -8948,7 +9159,10 @@ mod tests { cleanup_transfer_worker_attempt_artifacts(&dst_root, &assignment).unwrap(); - assert_eq!(fs::read(root.path().join("dir/file.bin")).unwrap(), file_bytes); + assert_eq!( + fs::read(root.path().join("dir/file.bin")).unwrap(), + file_bytes + ); assert!(!root.path().join(".fluxon.stage").exists()); } @@ -8957,11 +9171,12 @@ mod tests { let root = TempDir::new().unwrap(); let dst_root = root.path().to_path_buf(); let file_bytes = b"hello".to_vec(); - let collect_infos = build_symlink_collect_infos(vec![FluxonFsTransferSymlinkNoticeEntryWire { - relpath: "root/link-file.bin".to_string(), - link_target: "target/file.bin".to_string(), - }]) - .unwrap(); + let collect_infos = + build_symlink_collect_infos(vec![FluxonFsTransferSymlinkNoticeEntryWire { + relpath: "root/link-file.bin".to_string(), + link_target: "target/file.bin".to_string(), + }]) + .unwrap(); let assignment = FluxonFsTransferWorkerAssignmentWire { collect_infos: collect_infos.clone(), ..test_worker_assignment("dir/file.bin", file_bytes.len() as i64) @@ -8976,9 +9191,11 @@ mod tests { let result = execute_transfer_worker_assignment( &assignment, &dst_root, - || Err(TransferWorkerExecutionError::Stop( - FluxonFsTransferWorkerStopReasonWire::Superseded, - )), + || { + Err(TransferWorkerExecutionError::Stop( + FluxonFsTransferWorkerStopReasonWire::Superseded, + )) + }, { let file_bytes = file_bytes.clone(); move |_file, read_offset, _length| { @@ -8996,11 +9213,20 @@ mod tests { FluxonFsTransferWorkerStopReasonWire::Superseded )) )); - assert!(root.path().join(prepared_collect.staging_relpath.as_str()).exists()); + assert!( + root.path() + .join(prepared_collect.staging_relpath.as_str()) + .exists() + ); cleanup_transfer_worker_attempt_artifacts(&dst_root, &assignment).unwrap(); assert!(!root.path().join(".fluxon.stage").exists()); - assert!(!root.path().join(prepared_collect.staging_relpath.as_str()).exists()); + assert!( + !root + .path() + .join(prepared_collect.staging_relpath.as_str()) + .exists() + ); } } diff --git a/fluxon_rs/fluxon_fs/src/cache_controller.rs b/fluxon_rs/fluxon_fs/src/cache_controller.rs index 8a0845c..13ce5a8 100644 --- a/fluxon_rs/fluxon_fs/src/cache_controller.rs +++ b/fluxon_rs/fluxon_fs/src/cache_controller.rs @@ -429,8 +429,8 @@ fn now_ms() -> i64 { #[cfg(test)] mod tests { use super::*; - use std::sync::mpsc; use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; + use std::sync::mpsc; use std::sync::{Condvar, Mutex}; use tokio::time::{Duration, sleep}; diff --git a/fluxon_rs/fluxon_fs_s3_gateway/src/lib.rs b/fluxon_rs/fluxon_fs_s3_gateway/src/lib.rs index 827bb23..0866432 100644 --- a/fluxon_rs/fluxon_fs_s3_gateway/src/lib.rs +++ b/fluxon_rs/fluxon_fs_s3_gateway/src/lib.rs @@ -5344,10 +5344,9 @@ mod tests { }; use crate::transfer::encode_transfer_manifest_blob_with_empty_dirs; use fluxon_fs_core::config::{ - FS_CACHE_DEFAULT_WRITE_SESSION_TARGET_INFLIGHT_BYTES_V1, - FS_EXPORT_DEFAULT_INLINE_BYTES_MAX_BYTES_V1, - FS_EXPORT_DEFAULT_METADATA_CACHE_TTL_MS_V1, FLUXON_FS_LOCAL_TRANSFER_CHECK_DST_EXPORT, FLUXON_FS_LOCAL_TRANSFER_CHECK_SRC_EXPORT, + FS_CACHE_DEFAULT_WRITE_SESSION_TARGET_INFLIGHT_BYTES_V1, + FS_EXPORT_DEFAULT_INLINE_BYTES_MAX_BYTES_V1, FS_EXPORT_DEFAULT_METADATA_CACHE_TTL_MS_V1, FluxonFsAccessModel, FluxonFsAccessUser, FluxonFsExport, FluxonFsExportRoutingMode, FluxonFsGlobalConfig, FluxonFsLocalTransferCheckJobSpecWire, FluxonFsRequestIdentity, FluxonFsS3GatewayConfig, FluxonFsS3KvMissPolicy, FluxonFsS3PermissionAccount, diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/delete.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/delete.rs index 8e37608..63db807 100755 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/delete.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/delete.rs @@ -16,21 +16,6 @@ use crate::{ }; use limit_thirdparty::tokio; -fn remove_local_cached_info_for_delete( - client_inner: &ClientKvApiInner, - delete_item: &DeleteClientKvMetaCacheItem, -) { - client_inner - .get_cached_info - .remove_if(&delete_item.key, |_, v| { - if v.put_time_ms == delete_item.put_time_ms { - v.put_version <= delete_item.put_version - } else { - v.put_time_ms <= delete_item.put_time_ms - } - }); -} - impl ClientKvApiInner { pub async fn delete(&self, key: &str) -> KvResult<()> { if !self.view.register_shutdown_poller().is_running() { @@ -64,14 +49,12 @@ impl ClientKvApiInner { resp.serialize_part.error_json.clone(), )?; - remove_local_cached_info_for_delete( - self, - &DeleteClientKvMetaCacheItem { - key: key.to_string(), - put_time_ms: resp.serialize_part.deleted_put_time_ms, - put_version: resp.serialize_part.deleted_put_version, - }, - ); + let delete_item = DeleteClientKvMetaCacheItem { + key: key.to_string(), + put_time_ms: resp.serialize_part.deleted_put_time_ms, + put_version: resp.serialize_part.deleted_put_version, + }; + apply_delete_client_kv_meta_cache_item(&self.view, &delete_item).await; Ok(()) } @@ -99,6 +82,59 @@ pub fn spawn_owner_delete_ack_batch( }); } +async fn apply_delete_client_kv_meta_cache_item( + view: &ClientKvApiView, + delete_item: &DeleteClientKvMetaCacheItem, +) { + let client_api = view.client_kv_api(); + let client_inner = client_api.inner(); + + if let Some((_removed_key, cached_info)) = + client_inner + .get_cached_info + .remove_if(&delete_item.key, |_, v| { + let res = if v.put_time_ms == delete_item.put_time_ms { + v.put_version <= delete_item.put_version + } else { + v.put_time_ms <= delete_item.put_time_ms + }; + if res { + tracing::debug!("do remove local cache for key: {}", delete_item.key); + } else { + tracing::debug!( + "skip remove local cache for key: {}, request ({},{}), local ({},{})", + delete_item.key, + delete_item.put_time_ms, + delete_item.put_version, + v.put_time_ms, + v.put_version + ); + } + res + }) + { + client_inner.release_local_reserve_route_for_memory_info(cached_info.mem_holder.as_ref()); + } + let _ = client_inner.remove_local_snapshot_if( + &delete_item.key, + delete_item.put_time_ms, + delete_item.put_version, + ); + + if let Err(err) = client_inner + .external_invalidate_delete + .sender() + .send(delete_item.clone()) + .await + { + tracing::warn!( + "Failed to enqueue external weak-index invalidation for key '{}': {}", + delete_item.key, + err + ); + } +} + /// 批量删除客户端 KV 元数据缓存的处理函数 pub async fn handle_batch_delete_client_kv_meta_cache( view: &ClientKvApiView, @@ -111,9 +147,6 @@ pub async fn handle_batch_delete_client_kv_meta_cache( req.serialize_part.delete_items.len() ); - let client_api = view.client_kv_api(); - let client_inner = client_api.inner(); - let mut deleted_count = 0u32; for delete_item in &req.serialize_part.delete_items { @@ -124,21 +157,8 @@ pub async fn handle_batch_delete_client_kv_meta_cache( delete_item.put_version ); - remove_local_cached_info_for_delete(client_inner, delete_item); + apply_delete_client_kv_meta_cache_item(view, delete_item).await; deleted_count += 1; - - if let Err(err) = client_inner - .external_invalidate_delete - .sender() - .send(delete_item.clone()) - .await - { - tracing::warn!( - "Failed to enqueue external weak-index invalidation for key '{}': {}", - delete_item.key, - err - ); - } } tracing::debug!( diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs index 60986be..3cfd44d 100755 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs @@ -1,23 +1,43 @@ use crate::client_kv_api::msg_pack::{ - ExternalDeleteReq, ExternalDeleteResp, ExternalGetReq, ExternalGetResp, ExternalIsExistReq, - ExternalIsExistResp, ExternalPutCommitReq, ExternalPutCommitResp, ExternalPutRevokeReq, - ExternalPutRevokeResp, ExternalPutStartReq, ExternalPutStartResp, ExternalPutTransferEndReq, - ExternalPutTransferEndResp, TestPutPhaseTrace, + ExternalBatchGetCancelReq, ExternalBatchGetCancelResp, ExternalBatchGetItemResp, + ExternalBatchGetReq, ExternalBatchGetResp, ExternalBatchGetStartReq, ExternalBatchGetStartResp, + ExternalBatchGetTransferReq, ExternalBatchGetTransferResp, ExternalBatchIsExistReq, + ExternalBatchIsExistResp, ExternalBatchPutCommitItemResp, ExternalBatchPutCommitReq, + ExternalBatchPutCommitResp, ExternalBatchPutStartItemResp, ExternalBatchPutStartReq, + ExternalBatchPutStartResp, ExternalBatchPutTransferEndItemResp, ExternalBatchPutTransferEndReq, + ExternalBatchPutTransferEndResp, ExternalDeleteReq, ExternalDeleteResp, ExternalGetReq, + ExternalGetResp, ExternalIsExistReq, ExternalIsExistResp, ExternalObservabilitySnapshotReq, + ExternalObservabilitySnapshotResp, ExternalPutCommitReq, ExternalPutCommitResp, + ExternalPutRevokeReq, ExternalPutRevokeResp, ExternalPutStartReq, ExternalPutStartResp, + ExternalPutTransferEndReq, ExternalPutTransferEndResp, TestPutPhaseTrace, }; -use crate::client_kv_api::{ClientKvApi, ExternalHoldingGetInfo, ExternalPendingPutCtx}; -use crate::client_seg_pool::{ResolveSideTransferLaneReq, parse_side_transfer_worker_lane_idx}; +use crate::client_kv_api::ClientKvApi; +use crate::client_kv_api::{ + self, ExternalGetStartDedupKey, ExternalGetStartEntry, ExternalGetStartOwnerItem, + ExternalGetStartPrefixResult, ExternalGetStartSharedItemResult, ExternalGetStartSharedOp, + ExternalGetStartSharedPhase, ExternalGetStartTransferOutput, ExternalHoldingGetInfo, + ExternalPendingPutCtx, +}; +use crate::client_seg_pool::{parse_side_transfer_worker_lane_idx, ResolveSideTransferLaneReq}; use crate::cluster_manager::NodeIDString; use crate::cluster_manager::{ META_KEY_SHARED_STORAGE_NODE_ID, META_KEY_SHARED_STORAGE_NODE_START_TIME, }; -use crate::memholder::ExternalMemHolderInfo; +use crate::master_kv_router::msg_pack::{ + BatchPutDoneItemReq, BatchPutRevokeItemReq, BatchPutStartItemReq, +}; use crate::memholder::MemholderManagerTrait; use crate::memholder::NodeHolderKey; +use crate::memholder::{ExternalMemHolderInfo, UserMemHolder, UserMemHolderExposeKind}; use crate::p2p::msg_pack::MsgPack; +use crate::rpcresp_kvresult_convert::msg_and_error::{codes_api, ApiError, KvError, KvResult, OK}; use crate::rpcresp_kvresult_convert::FromError; use crate::rpcresp_kvresult_convert::ToResult; -use crate::rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, KvResult, OK}; use async_trait::async_trait; +use dashmap::mapref::entry::Entry; +use futures::stream::{self, StreamExt}; +use std::sync::atomic::Ordering; +use std::sync::Arc; use std::time::Duration; use std::time::Instant; use tracing; @@ -29,6 +49,494 @@ fn duration_to_i64_us(duration: std::time::Duration) -> i64 { const SIDE_TRANSFER_OWNER_RPC_TIMEOUT_SECS: u64 = 30; const SIDE_TRANSFER_TARGET_RESOLVE_TIMEOUT_SECS: u64 = 10; +#[derive(Clone)] +struct LocalCommittedCachePublish { + src_offset: u64, + len: u32, +} + +fn local_committed_cache_publish( + op: &'static str, + key: &str, + put_id: crate::master_kv_router::put::PutIDForAKey, + pending_ctx: Option<&ExternalPendingPutCtx>, + req_src_offset: u64, + req_len: u64, +) -> KvResult { + if let Some(ctx) = pending_ctx { + if ctx.src_offset != req_src_offset || ctx.len != req_len { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "{op} local cache publish request mismatches pending ctx: key={} put_id=({},{}) req_src_offset={} ctx_src_offset={} req_len={} ctx_len={}", + key, put_id.0, put_id.1, req_src_offset, ctx.src_offset, req_len, ctx.len + ), + })); + } + } + let len = u32::try_from(req_len).map_err(|_| { + KvError::Api(ApiError::Unknown { + detail: format!( + "{op} local cache len does not fit u32: key={} len={}", + key, req_len + ), + }) + })?; + Ok(LocalCommittedCachePublish { + src_offset: req_src_offset, + len, + }) +} + +pub(crate) fn normalize_external_get_start_group_lens( + keys_len: usize, + atomic_group_lens: Option>, +) -> KvResult> { + match atomic_group_lens { + Some(group_lens) => { + if group_lens.is_empty() { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: "external_batch_get_start atomic_group_lens must be non-empty" + .to_string(), + })); + } + if group_lens.iter().any(|len| *len == 0) { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: "external_batch_get_start atomic_group_lens entries must be > 0" + .to_string(), + })); + } + let group_sum = group_lens.iter().sum::(); + if group_sum != keys_len { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "external_batch_get_start atomic_group_lens must sum to keys length: sum={} keys={}", + group_sum, keys_len + ), + })); + } + Ok(group_lens) + } + None => Ok(vec![keys_len]), + } +} + +fn external_get_start_error_kind_from_code(error_code: u32, error_json: &str) -> Option { + if error_code == OK || error_code == codes_api::API_KEY_NOT_FOUND { + None + } else if error_json.is_empty() { + Some(format!("error_code:{}", error_code)) + } else { + Some(format!("error_code:{} {}", error_code, error_json)) + } +} + +fn compute_external_get_start_raw_prefix( + item_codes: &[(u32, String)], +) -> (usize, Option, Option) { + let mut prefix_hit_len = 0usize; + for (idx, (error_code, error_json)) in item_codes.iter().enumerate() { + if *error_code == OK { + prefix_hit_len += 1; + continue; + } + return ( + prefix_hit_len, + Some(idx), + external_get_start_error_kind_from_code(*error_code, error_json), + ); + } + (prefix_hit_len, None, None) +} + +pub(crate) fn compute_external_get_start_transfer_prefix( + raw_prefix_hit_len: usize, + group_lens: &[usize], + prefix_best_effort: bool, +) -> usize { + let mut transferable_len = 0usize; + for group_len in group_lens.iter().copied() { + let next = transferable_len + group_len; + if next > raw_prefix_hit_len { + break; + } + transferable_len = next; + } + let requested_len = group_lens.iter().sum::(); + if !prefix_best_effort && transferable_len != requested_len { + 0 + } else { + transferable_len + } +} + +async fn finish_external_get_start_transfer( + view: crate::client_kv_api::ClientKvApiView, + transfer_items: Vec, + transfer_concurrency: usize, +) -> KvResult { + let client_api = view.client_kv_api(); + let inner = client_api.inner(); + let refcount = inner.get_or_init_all_memholder_refcount(); + let mut results: Vec< + Option, Option)>>>, + > = (0..transfer_items.len()).map(|_| None).collect(); + let mut started_positions = Vec::new(); + let mut started_keys = Vec::new(); + let mut started_items = Vec::new(); + + for (idx, item) in transfer_items.into_iter().enumerate() { + match item { + ExternalGetStartOwnerItem::Local { memory_info } => { + let holder = Arc::new(UserMemHolder::new( + memory_info, + refcount.clone(), + UserMemHolderExposeKind::SegPtr, + )); + results[idx] = Some(Ok(Some((holder, None)))); + } + ExternalGetStartOwnerItem::Started { key, item } => { + started_positions.push(idx); + started_keys.push(key); + started_items.push(item); + } + } + } + + if !started_items.is_empty() { + let started_results = inner + .batch_get_finish_started(started_keys, started_items, transfer_concurrency) + .await?; + if started_results.len() != started_positions.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external get_start transfer result length mismatch: expected={} got={}", + started_positions.len(), + started_results.len() + ), + })); + } + for (idx, result) in started_positions + .into_iter() + .zip(started_results.into_iter()) + { + results[idx] = Some(result); + } + } + + Ok(results + .into_iter() + .map(|item| { + item.unwrap_or_else(|| { + Err(KvError::Api(ApiError::Unknown { + detail: "external get_start transfer result slot was not populated".to_string(), + })) + }) + }) + .collect()) +} + +fn external_get_start_error_parts(err: &KvError) -> (u32, String) { + (err.code(), err.to_json()) +} + +fn register_external_get_start_waiter(shared_op: &Arc) { + let mut state = shared_op.state.lock(); + state.waiter_count = state + .waiter_count + .checked_add(1) + .expect("external get_start shared waiter count overflow"); +} + +fn release_external_get_start_waiter( + inner: &client_kv_api::ClientKvApiInner, + shared_op: &Arc, +) { + let should_remove = { + let mut state = shared_op.state.lock(); + assert!( + state.waiter_count > 0, + "external get_start shared waiter count underflow" + ); + state.waiter_count -= 1; + state.waiter_count == 0 + }; + if should_remove { + inner + .external_get_start_by_key + .remove_if(&shared_op.dedup_key, |_, op| { + if !Arc::ptr_eq(op, shared_op) { + return false; + } + op.state.lock().waiter_count == 0 + }); + } +} + +fn publish_external_get_start_failed(shared_op: &Arc, err: &KvError) { + let (error_code, error_json) = external_get_start_error_parts(err); + { + let mut state = shared_op.state.lock(); + state.phase = ExternalGetStartSharedPhase::Failed { + error_code, + error_json, + }; + } + shared_op.notify.notify_waiters(); +} + +fn publish_external_get_start_ready( + shared_op: &Arc, + keys: Vec, + transfer_result: KvResult, +) { + let phase = match transfer_result { + Ok(transfer_results) => { + if transfer_results.len() != keys.len() { + let err = KvError::Api(ApiError::Unknown { + detail: format!( + "external shared get_start transfer result length mismatch: expected={} got={}", + keys.len(), + transfer_results.len() + ), + }); + let (error_code, error_json) = external_get_start_error_parts(&err); + ExternalGetStartSharedPhase::Failed { + error_code, + error_json, + } + } else { + let items = keys + .iter() + .zip(transfer_results.into_iter()) + .map(|(_key, item_result)| match item_result { + Ok(Some((memholder, _))) => { + ExternalGetStartSharedItemResult::Hit { memholder } + } + Ok(None) => ExternalGetStartSharedItemResult::Miss, + Err(err) => { + let (error_code, error_json) = external_get_start_error_parts(&err); + ExternalGetStartSharedItemResult::Error { + error_code, + error_json, + } + } + }) + .collect::>(); + let prefix = match { + let state = shared_op.state.lock(); + match &state.phase { + ExternalGetStartSharedPhase::Running { prefix, .. } + | ExternalGetStartSharedPhase::Ready { prefix, .. } => Ok(prefix.clone()), + ExternalGetStartSharedPhase::Starting + | ExternalGetStartSharedPhase::Failed { .. } => Err(KvError::Api( + ApiError::Unknown { + detail: + "external shared get_start transfer completed before prefix was published" + .to_string(), + }, + )), + } + } { + Ok(prefix) => prefix, + Err(err) => { + let (error_code, error_json) = external_get_start_error_parts(&err); + let mut state = shared_op.state.lock(); + state.phase = ExternalGetStartSharedPhase::Failed { + error_code, + error_json, + }; + shared_op.notify.notify_waiters(); + return; + } + }; + ExternalGetStartSharedPhase::Ready { + prefix, + keys, + items, + } + } + } + Err(err) => { + let (error_code, error_json) = external_get_start_error_parts(&err); + ExternalGetStartSharedPhase::Failed { + error_code, + error_json, + } + } + }; + { + let mut state = shared_op.state.lock(); + state.phase = phase; + } + shared_op.notify.notify_waiters(); +} + +async fn wait_external_get_start_prefix( + shared_op: Arc, +) -> KvResult { + loop { + let notified = shared_op.notify.notified(); + futures::pin_mut!(notified); + let should_wait = { + let state = shared_op.state.lock(); + match &state.phase { + ExternalGetStartSharedPhase::Starting => { + notified.as_mut().enable(); + true + } + ExternalGetStartSharedPhase::Running { prefix, .. } + | ExternalGetStartSharedPhase::Ready { prefix, .. } => { + return Ok(prefix.clone()); + } + ExternalGetStartSharedPhase::Failed { + error_code, + error_json, + } => return Err(KvError::from_json(*error_code, error_json)), + } + }; + if should_wait { + notified.await; + } + } +} + +async fn wait_external_get_start_transfer( + shared_op: Arc, +) -> KvResult<(Vec, Vec)> { + loop { + let notified = shared_op.notify.notified(); + futures::pin_mut!(notified); + let should_wait = { + let state = shared_op.state.lock(); + match &state.phase { + ExternalGetStartSharedPhase::Starting + | ExternalGetStartSharedPhase::Running { .. } => { + notified.as_mut().enable(); + true + } + ExternalGetStartSharedPhase::Ready { keys, items, .. } => { + return Ok((keys.clone(), items.clone())); + } + ExternalGetStartSharedPhase::Failed { + error_code, + error_json, + } => return Err(KvError::from_json(*error_code, error_json)), + } + }; + if should_wait { + notified.await; + } + } +} + +async fn prepare_external_get_start_shared_op( + inner: &client_kv_api::ClientKvApiInner, + req: &ExternalBatchGetStartReq, + group_lens: &[usize], +) -> KvResult<( + ExternalGetStartPrefixResult, + Vec, + Vec, +)> { + let mut item_slots: Vec> = + (0..req.keys.len()).map(|_| None).collect(); + let mut missing_indices = Vec::new(); + let mut missing_keys = Vec::new(); + + for (idx, key) in req.keys.iter().enumerate() { + if let Some(memory_info) = inner.local_visible_mem_holder(key) { + item_slots[idx] = Some(ExternalGetStartOwnerItem::Local { memory_info }); + } else { + missing_indices.push(idx); + missing_keys.push(key.clone()); + } + } + + if !missing_keys.is_empty() { + let start_resp = inner.batch_get_start(missing_keys.clone()).await?; + if start_resp.items.len() != missing_indices.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external_batch_get_start response length mismatch: expected={} got={}", + missing_indices.len(), + start_resp.items.len() + ), + })); + } + for ((idx, key), item) in missing_indices + .into_iter() + .zip(missing_keys.into_iter()) + .zip(start_resp.items.into_iter()) + { + item_slots[idx] = Some(ExternalGetStartOwnerItem::Started { key, item }); + } + } + + let items = item_slots + .into_iter() + .map(|item| { + item.ok_or_else(|| { + KvError::Api(ApiError::Unknown { + detail: "external_batch_get_start item slot was not populated".to_string(), + }) + }) + }) + .collect::>>()?; + let item_codes = items + .iter() + .map(|item| match item { + ExternalGetStartOwnerItem::Local { .. } => (OK, String::new()), + ExternalGetStartOwnerItem::Started { item, .. } => { + (item.error_code, item.error_json.clone()) + } + }) + .collect::>(); + let (raw_prefix_hit_len, first_miss_index, first_error_kind) = + compute_external_get_start_raw_prefix(&item_codes); + let transferable_len = compute_external_get_start_transfer_prefix( + raw_prefix_hit_len, + group_lens, + req.prefix_best_effort, + ); + if let Some(error_kind) = first_error_kind.as_ref() { + tracing::warn!( + "external_batch_get_start prefix stopped on non-key-miss item: req_node_id={} raw_prefix_hit_len={} transferable_len={} first_miss_index={:?} error_kind={}", + req.req_node_id, + raw_prefix_hit_len, + transferable_len, + first_miss_index, + error_kind + ); + } + + let revoke_get_ids = items + .iter() + .skip(transferable_len) + .filter_map(|item| match item { + ExternalGetStartOwnerItem::Started { item, .. } if item.error_code == OK => { + Some(item.get_id) + } + _ => None, + }) + .collect::>(); + if !revoke_get_ids.is_empty() { + inner.batch_get_revoke(revoke_get_ids).await?; + } + + let transfer_keys = req.keys[..transferable_len].to_vec(); + let transfer_items = items.into_iter().take(transferable_len).collect::>(); + Ok(( + ExternalGetStartPrefixResult { + raw_prefix_hit_len, + transferable_len, + first_miss_index, + first_error_kind, + }, + transfer_keys, + transfer_items, + )) +} + impl ClientKvApi { fn is_side_transfer_worker(&self) -> bool { self.inner() @@ -253,8 +761,15 @@ impl ClientKvApi { let commit_req = MsgPack { serialize_part: ExternalPutCommitReq { key: req.key.clone(), + len: req.len, + src_offset: req.src_offset, + remote_target: req + .peer_id + .as_deref() + .is_some_and(|peer| peer != owner_id.as_str()), put_id: Some(put_id), lease_id: req.lease_id, + write_through: req.write_through, started_time: req.started_time, test_observe_put_phases: req.test_observe_put_phases, }, @@ -298,22 +813,55 @@ pub trait HandlerForExternalClient { /// Validate external's observed owner start_time (0 means skip validation for legacy callers) fn validate_requester_owner_status_updated(&self, started_time: i64) -> KvResult<()>; async fn external_get(&self, req: ExternalGetReq) -> KvResult; + async fn external_batch_get(&self, req: ExternalBatchGetReq) -> KvResult; + async fn external_batch_get_start( + &self, + req: ExternalBatchGetStartReq, + ) -> KvResult; + async fn external_batch_get_transfer( + &self, + req: ExternalBatchGetTransferReq, + ) -> KvResult; + async fn external_batch_get_cancel( + &self, + req: ExternalBatchGetCancelReq, + ) -> KvResult; async fn external_put_start(&self, req: ExternalPutStartReq) -> KvResult; + async fn external_batch_put_start( + &self, + req: ExternalBatchPutStartReq, + ) -> KvResult; // deprecated: transfer merged into external_put_transfer_end async fn external_put_transfer_end( &self, req: ExternalPutTransferEndReq, ) -> KvResult; + async fn external_batch_put_transfer_end( + &self, + req: ExternalBatchPutTransferEndReq, + ) -> KvResult; async fn external_put_commit( &self, req: ExternalPutCommitReq, ) -> KvResult; + async fn external_batch_put_commit( + &self, + req: ExternalBatchPutCommitReq, + ) -> KvResult; async fn external_put_revoke( &self, req: ExternalPutRevokeReq, ) -> KvResult; async fn external_delete(&self, req: ExternalDeleteReq) -> KvResult; async fn external_is_exist(&self, req: ExternalIsExistReq) -> KvResult; + async fn external_batch_is_exist( + &self, + req: ExternalBatchIsExistReq, + ) -> KvResult; + async fn external_observability_snapshot( + &self, + req: ExternalObservabilitySnapshotReq, + ) -> KvResult; } /// Handle external get request @@ -376,6 +924,283 @@ impl HandlerForExternalClient for ClientKvApi { }) } + async fn external_batch_get(&self, req: ExternalBatchGetReq) -> KvResult { + if self.is_side_transfer_worker() { + return Err(Self::side_transfer_unsupported("external_batch_get")); + } + let inner = self.inner(); + + self.validate_requester_owner_status_updated(req.started_time)?; + + let batch_results = inner.batch_get(req.keys, req.transfer_concurrency).await?; + let mut items = Vec::with_capacity(batch_results.len()); + for item_result in batch_results { + match item_result { + Ok(Some((memholder, _))) => { + let memory_info = memholder.memory_info(); + inner.external_get_holding.insert( + NodeHolderKey::new(req.req_node_id.clone(), memholder.holder_id()), + ExternalHoldingGetInfo { + key: memory_info.key.clone(), + req_node_id: req.req_node_id.clone(), + memory_info, + }, + ); + items.push(ExternalBatchGetItemResp { + error_code: OK, + error_json: String::new(), + external_memholder_info: Some(ExternalMemHolderInfo { + offset: memholder.get_offset(), + len: memholder.get_length() as u32, + holder_id: memholder.holder_id(), + }), + }); + } + Ok(None) => items.push(ExternalBatchGetItemResp { + error_code: + crate::rpcresp_kvresult_convert::msg_and_error::codes_api::API_KEY_NOT_FOUND, + error_json: "Key not found".to_string(), + external_memholder_info: None, + }), + Err(err) => items.push(ExternalBatchGetItemResp { + external_memholder_info: None, + ..ExternalBatchGetItemResp::from_error(&err) + }), + } + } + + Ok(ExternalBatchGetResp { + items, + error_code: OK, + error_json: String::new(), + }) + } + + async fn external_batch_get_start( + &self, + req: ExternalBatchGetStartReq, + ) -> KvResult { + if self.is_side_transfer_worker() { + return Err(Self::side_transfer_unsupported("external_batch_get_start")); + } + if req.keys.is_empty() { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: "external_batch_get_start requires at least one key".to_string(), + })); + } + let inner = self.inner(); + self.validate_requester_owner_status_updated(req.started_time)?; + + let group_lens = + normalize_external_get_start_group_lens(req.keys.len(), req.atomic_group_lens.clone())?; + let dedup_key = ExternalGetStartDedupKey { + keys: req.keys.clone(), + atomic_group_lens: group_lens.clone(), + prefix_best_effort: req.prefix_best_effort, + }; + let (shared_op, is_creator) = match inner.external_get_start_by_key.entry(dedup_key.clone()) + { + Entry::Occupied(entry) => { + let shared_op = entry.get().clone(); + register_external_get_start_waiter(&shared_op); + (shared_op, false) + } + Entry::Vacant(entry) => { + let shared_op = Arc::new(ExternalGetStartSharedOp::new( + dedup_key, + req.transfer_concurrency, + )); + entry.insert(shared_op.clone()); + (shared_op, true) + } + }; + + if is_creator { + match prepare_external_get_start_shared_op(inner, &req, &group_lens).await { + Ok((prefix, transfer_keys, transfer_items)) => { + { + let mut state = shared_op.state.lock(); + state.phase = ExternalGetStartSharedPhase::Running { + prefix: prefix.clone(), + keys: transfer_keys.clone(), + }; + } + shared_op.notify.notify_waiters(); + + let transfer_shared_op = shared_op.clone(); + let transfer_concurrency = shared_op.transfer_concurrency; + let spawn_view = inner.view.clone_view(); + let transfer_view = spawn_view.clone(); + spawn_view.spawn("external_get_start_transfer", async move { + let transfer_result = finish_external_get_start_transfer( + transfer_view, + transfer_items, + transfer_concurrency, + ) + .await; + publish_external_get_start_ready( + &transfer_shared_op, + transfer_keys, + transfer_result, + ); + }); + } + Err(err) => { + publish_external_get_start_failed(&shared_op, &err); + release_external_get_start_waiter(inner, &shared_op); + return Err(err); + } + } + } + + let prefix = match wait_external_get_start_prefix(shared_op.clone()).await { + Ok(prefix) => prefix, + Err(err) => { + release_external_get_start_waiter(inner, &shared_op); + return Err(err); + } + }; + let handle = inner + .next_external_get_start_handle + .fetch_add(1, Ordering::Relaxed); + inner.external_get_start_registry.insert( + handle, + Arc::new(ExternalGetStartEntry { + req_node_id: req.req_node_id.clone(), + shared_op, + }), + ); + + Ok(ExternalBatchGetStartResp { + error_code: OK, + error_json: String::new(), + handle, + raw_prefix_hit_len: prefix.raw_prefix_hit_len, + }) + } + + async fn external_batch_get_transfer( + &self, + req: ExternalBatchGetTransferReq, + ) -> KvResult { + if self.is_side_transfer_worker() { + return Err(Self::side_transfer_unsupported( + "external_batch_get_transfer", + )); + } + let inner = self.inner(); + self.validate_requester_owner_status_updated(req.started_time)?; + + let Some((_handle, entry)) = inner.external_get_start_registry.remove(&req.handle) else { + return Err(KvError::Api(ApiError::KeyNotFound { + key: format!("external_get_start_handle:{}", req.handle), + })); + }; + if entry.req_node_id != req.req_node_id { + tracing::warn!( + "external_batch_get_transfer req_node_id mismatch: handle={} expected={} got={}", + req.handle, + entry.req_node_id, + req.req_node_id + ); + } + let shared_op = entry.shared_op.clone(); + let result = match wait_external_get_start_transfer(shared_op.clone()).await { + Ok((keys, shared_items)) => { + if shared_items.len() != keys.len() { + Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external_batch_get_transfer shared result length mismatch: expected={} got={}", + keys.len(), + shared_items.len() + ), + })) + } else { + let mut items = Vec::with_capacity(shared_items.len()); + for (key, item_result) in keys.iter().zip(shared_items.into_iter()) { + match item_result { + ExternalGetStartSharedItemResult::Hit { memholder } => { + let memory_info = memholder.memory_info(); + inner.external_get_holding.insert( + NodeHolderKey::new( + req.req_node_id.clone(), + memholder.holder_id(), + ), + ExternalHoldingGetInfo { + key: memory_info.key.clone(), + req_node_id: req.req_node_id.clone(), + memory_info, + }, + ); + items.push(ExternalBatchGetItemResp { + error_code: OK, + error_json: String::new(), + external_memholder_info: Some(ExternalMemHolderInfo { + offset: memholder.get_offset(), + len: memholder.get_length() as u32, + holder_id: memholder.holder_id(), + }), + }); + } + ExternalGetStartSharedItemResult::Miss => { + items.push(ExternalBatchGetItemResp { + error_code: codes_api::API_KEY_NOT_FOUND, + error_json: format!("Key not found: {}", key), + external_memholder_info: None, + }); + } + ExternalGetStartSharedItemResult::Error { + error_code, + error_json, + } => { + items.push(ExternalBatchGetItemResp { + error_code, + error_json, + external_memholder_info: None, + }); + } + } + } + Ok(ExternalBatchGetTransferResp { + items, + error_code: OK, + error_json: String::new(), + }) + } + } + Err(err) => Err(err), + }; + release_external_get_start_waiter(inner, &shared_op); + result + } + + async fn external_batch_get_cancel( + &self, + req: ExternalBatchGetCancelReq, + ) -> KvResult { + if self.is_side_transfer_worker() { + return Err(Self::side_transfer_unsupported("external_batch_get_cancel")); + } + let inner = self.inner(); + self.validate_requester_owner_status_updated(req.started_time)?; + + if let Some((_handle, entry)) = inner.external_get_start_registry.remove(&req.handle) { + if entry.req_node_id != req.req_node_id { + tracing::warn!( + "external_batch_get_cancel req_node_id mismatch: handle={} expected={} got={}", + req.handle, + entry.req_node_id, + req.req_node_id + ); + } + release_external_get_start_waiter(inner, &entry.shared_op); + } + Ok(ExternalBatchGetCancelResp { + error_code: OK, + error_json: String::new(), + }) + } + /// Handle external put start request: allocate with native KV op and return offsets. /// For remote targets, return a local staging offset (no `peer_id` exposed); owner records /// remote context internally and completes transfer during `external_put_transfer_end`. @@ -396,6 +1221,8 @@ impl HandlerForExternalClient for ClientKvApi { &req.key, req.len as u32, req.reject_if_inflight_same_key, + req.reject_if_exist_same_key, + req.write_through, req.preferred_sub_cluster.as_deref(), source_node_id, ) @@ -428,21 +1255,31 @@ impl HandlerForExternalClient for ClientKvApi { // Remote target: external still writes into owner's shared memory (src_offset). src_offset }; - if !is_local_target { - // Stash remote context for transfer_end: peer_id, target_base_addr, target_offset(remote) - let remote_offset = put_start_resp.target_addr - put_start_resp.target_base_addr; - inner.external_pending_puts.insert( - ( - req.key.clone(), - put_start_resp.put_id.0, - put_start_resp.put_id.1, - ), - ExternalPendingPutCtx { - peer_id: put_start_resp.node_id.clone(), - target_base_addr: put_start_resp.target_base_addr, - target_offset: remote_offset, + let remote_offset = put_start_resp.target_addr - put_start_resp.target_base_addr; + inner.external_pending_puts.insert( + ( + req.key.clone(), + put_start_resp.put_id.0, + put_start_resp.put_id.1, + ), + ExternalPendingPutCtx { + peer_id: if is_local_target { + None + } else { + Some(put_start_resp.node_id.clone()) }, - ); + src_offset, + target_base_addr: put_start_resp.target_base_addr, + target_offset: if is_local_target { + target_offset + } else { + remote_offset + }, + len: req.len, + preferred_sub_cluster: req.preferred_sub_cluster.clone(), + }, + ); + if !is_local_target { tracing::debug!( "external_put_start stash remote ctx: key={}, put_id=({},{}) peer_id={}, target_base={:#x}, target_off={:#x}, src_off(staging)={:#x}", req.key, @@ -489,59 +1326,222 @@ impl HandlerForExternalClient for ClientKvApi { }) } - /// Handle external transfer+end request - transfer data then commit - async fn external_put_transfer_end( + async fn external_batch_put_start( &self, - req: ExternalPutTransferEndReq, - ) -> KvResult { + req: ExternalBatchPutStartReq, + ) -> KvResult { if self.is_side_transfer_worker() { - return self.external_put_transfer_end_side_worker(req).await; + return Err(Self::side_transfer_unsupported("external_batch_put_start")); } let inner = self.inner(); - let total_started_at = Instant::now(); self.validate_requester_owner_status_updated(req.started_time)?; - // Extract put_id early so we can revoke on transfer failure - let Some(put_id) = req.put_id else { - let err = crate::rpcresp_kvresult_convert::msg_and_error::KvError::Unreachable( - crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::RpcDecodeError { - rpc_input_json: format!("missing put_id; key={}", req.key), - }, - ); - return Ok(ExternalPutTransferEndResp::from_error(&err)); - }; + let start_resp = inner + .batch_put_start( + req.items + .iter() + .map(|item| BatchPutStartItemReq { + key: item.key.clone(), + len: item.len, + reject_if_inflight_same_key: item.reject_if_inflight_same_key, + reject_if_exist_same_key: item.reject_if_exist_same_key, + write_through: item.write_through, + preferred_sub_cluster: item.preferred_sub_cluster.clone(), + }) + .collect(), + ) + .await?; + if start_resp.items.len() != req.items.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external_batch_put_start response length mismatch: expected={} got={}", + req.items.len(), + start_resp.items.len() + ), + })); + } - // Delegate transfer to owner put_transfer (offset-based) then end - // For remote target, ignore caller's target_offset (staging) and use stashed remote ctx. - let (peer_id_for_transfer, target_off_for_transfer, target_base_for_transfer) = - if let Some(peer) = req.peer_id.clone() { - // Remote path requires a stashed context; do not fallback to caller-provided target_offset - match inner - .external_pending_puts - .get(&(req.key.clone(), put_id.0, put_id.1)) - { - Some(ctx) => ( - Some(ctx.peer_id.clone()), - ctx.target_offset, - Some(ctx.target_base_addr), - ), - None => match req.target_base_addr { - Some(target_base_addr) => { - (Some(peer.into()), req.target_offset, Some(target_base_addr)) - } - None => { - let err = KvError::Unreachable( - crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::RpcDecodeError { - rpc_input_json: format!( - "missing pending remote put ctx and caller target_base_addr; key={}, put_id=({},{}), peer_id={}", - req.key, put_id.0, put_id.1, peer - ), - }, - ); - return Ok(ExternalPutTransferEndResp::from_error(&err)); - } + let self_node_id = inner.view.cluster_manager().get_self_info().id.clone(); + let mut items = Vec::with_capacity(req.items.len()); + for (req_item, start_item) in req.items.into_iter().zip(start_resp.items.into_iter()) { + if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( + start_item.error_code, + start_item.error_json.clone(), + ) { + items.push(ExternalBatchPutStartItemResp { + put_id: None, + ..ExternalBatchPutStartItemResp::from_error(&err) + }); + continue; + } + + let src_offset = start_item.src_addr - start_item.src_base_addr; + let is_local_target = start_item.node_id == self_node_id; + let target_offset = if is_local_target { + start_item.target_addr - start_item.target_base_addr + } else { + src_offset + }; + let remote_offset = start_item.target_addr - start_item.target_base_addr; + inner.external_pending_puts.insert( + ( + req_item.key.clone(), + start_item.put_id.0, + start_item.put_id.1, + ), + ExternalPendingPutCtx { + peer_id: if is_local_target { + None + } else { + Some(start_item.node_id.clone()) }, + src_offset, + target_base_addr: start_item.target_base_addr, + target_offset: if is_local_target { + target_offset + } else { + remote_offset + }, + len: req_item.len, + preferred_sub_cluster: req_item.preferred_sub_cluster.clone(), + }, + ); + items.push(ExternalBatchPutStartItemResp { + error_code: OK, + src_offset, + target_offset, + transfer_target_offset: if is_local_target { + None + } else { + Some(remote_offset) + }, + peer_id: if is_local_target { + None + } else { + Some(start_item.node_id) + }, + src_base_addr: start_item.src_base_addr, + target_base_addr: start_item.target_base_addr, + error_json: String::new(), + put_id: Some(start_item.put_id), + }); + } + + Ok(ExternalBatchPutStartResp { + items, + error_code: OK, + error_json: String::new(), + }) + } + + /// Handle external transfer+end request - transfer data then commit + async fn external_put_transfer_end( + &self, + req: ExternalPutTransferEndReq, + ) -> KvResult { + if self.is_side_transfer_worker() { + return self.external_put_transfer_end_side_worker(req).await; + } + let inner = self.inner(); + let total_started_at = Instant::now(); + + self.validate_requester_owner_status_updated(req.started_time)?; + + // Extract put_id early so we can revoke on transfer failure + let Some(put_id) = req.put_id else { + let err = crate::rpcresp_kvresult_convert::msg_and_error::KvError::Unreachable( + crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::RpcDecodeError { + rpc_input_json: format!("missing put_id; key={}", req.key), + }, + ); + return Ok(ExternalPutTransferEndResp::from_error(&err)); + }; + + let pending_ctx = inner + .external_pending_puts + .get(&(req.key.clone(), put_id.0, put_id.1)) + .map(|ctx| ctx.clone()); + let preferred_sub_cluster = pending_ctx + .as_ref() + .and_then(|ctx| ctx.preferred_sub_cluster.clone()); + let self_node_id = inner.view.cluster_manager().get_self_info().id.clone(); + let req_remote_target = req + .peer_id + .as_deref() + .is_some_and(|peer| peer != self_node_id.as_str()); + let has_remote_append = pending_ctx + .as_ref() + .and_then(|ctx| ctx.peer_id.as_ref()) + .is_some(); + if pending_ctx.is_some() && req_remote_target != has_remote_append { + let err = KvError::Api(ApiError::InvalidArgument { + detail: format!( + "external_put_transfer_end peer_id mismatches pending ctx: key={} put_id=({},{}) req_remote_target={} ctx_remote_target={}", + req.key, put_id.0, put_id.1, req_remote_target, has_remote_append + ), + }); + if let Err(revoke_err) = inner.put_revoke(&req.key, put_id).await { + tracing::warn!( + "external_put_transfer_end put_revoke failed after peer_id mismatch: key={} put_id=({},{}) err={}", + req.key, + put_id.0, + put_id.1, + revoke_err + ); + } + inner + .external_pending_puts + .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + return Ok(ExternalPutTransferEndResp::from_error(&err)); + } + + // Delegate transfer to owner put_transfer (offset-based) then end + // For remote target, ignore caller's target_offset (staging) and use stashed remote ctx. + let (peer_id_for_transfer, target_off_for_transfer, target_base_for_transfer) = + if let Some(peer) = req.peer_id.clone() { + if peer == self_node_id.as_ref() { + (None, req.target_offset, None) + } else { + match pending_ctx.as_ref() { + Some(ctx) if ctx.peer_id.is_some() => ( + ctx.peer_id.clone(), + ctx.target_offset, + Some(ctx.target_base_addr), + ), + None => match req.target_base_addr { + Some(target_base_addr) => { + (Some(peer.into()), req.target_offset, Some(target_base_addr)) + } + None => { + let err = KvError::Unreachable( + crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::RpcDecodeError { + rpc_input_json: format!( + "missing pending remote put ctx and caller target_base_addr; key={}, put_id=({},{}), peer_id={}", + req.key, put_id.0, put_id.1, peer + ), + }, + ); + return Ok(ExternalPutTransferEndResp::from_error(&err)); + } + }, + Some(_) => match req.target_base_addr { + Some(target_base_addr) => { + (Some(peer.into()), req.target_offset, Some(target_base_addr)) + } + None => { + let err = KvError::Unreachable( + crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::RpcDecodeError { + rpc_input_json: format!( + "pending local ctx conflicted with remote external_put_transfer_end; key={}, put_id=({},{}), peer_id={}", + req.key, put_id.0, put_id.1, peer + ), + }, + ); + return Ok(ExternalPutTransferEndResp::from_error(&err)); + } + }, + } } } else { (None, req.target_offset, None) @@ -561,34 +1561,54 @@ impl HandlerForExternalClient for ClientKvApi { ); let transfer_started_at = Instant::now(); - if let Err(e) = inner - .put_transfer( - &req.key, - put_id, - req.src_offset, - target_off_for_transfer, - req.len, - peer_id_for_transfer, - target_base_for_transfer, - ) - .await - { - tracing::error!("Failed to transfer data: {}", e); - // On transfer failure, revoke the put to release resources - if let Err(revoke_err) = inner.put_revoke(&req.key, put_id).await { - tracing::warn!( - "put_revoke also failed after transfer error: {}", - revoke_err - ); + let mut put_locality_recorded = false; + if req.write_through { + let transfer_result = inner + .put_transfer( + &req.key, + put_id, + req.src_offset, + target_off_for_transfer, + req.len, + peer_id_for_transfer, + target_base_for_transfer, + ) + .await; + match transfer_result { + Ok(breakdown) => { + let breakdown_transfer_us = breakdown.submit_blocking_us + + breakdown.create_xfer_req_us + + breakdown.post_xfer_req_us + + breakdown.poll_wait_us; + inner.record_put_locality( + breakdown.remote_transfer, + req.len, + breakdown_transfer_us, + ); + put_locality_recorded = true; + } + Err(e) => { + tracing::error!("Failed to transfer data: {}", e); + // On transfer failure, revoke the put to release resources + if let Err(revoke_err) = inner.put_revoke(&req.key, put_id).await { + tracing::warn!( + "put_revoke also failed after transfer error: {}", + revoke_err + ); + } + // Cleanup pending ctx on failure + inner + .external_pending_puts + .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + return Ok(crate::rpcresp_kvresult_convert::FromError::from_error(&e)); + } } - // Cleanup pending ctx on failure - inner - .external_pending_puts - .invalidate(&(req.key.clone(), put_id.0, put_id.1)); - return Ok(crate::rpcresp_kvresult_convert::FromError::from_error(&e)); } let put_transfer_total_us = duration_to_i64_us(transfer_started_at.elapsed()); + if req.write_through && !put_locality_recorded { + inner.record_put_locality(false, req.len, 0); + } if inner.skip_put_end_commit_enabled() { inner @@ -620,8 +1640,41 @@ impl HandlerForExternalClient for ClientKvApi { } let end_started_at = Instant::now(); - let put_end_stats = match inner.put_end(&req.key, put_id, req.lease_id).await { - Ok(stats) => stats, + let publish_local_cache = !req.write_through || !req_remote_target; + let local_cache_publish = if publish_local_cache { + match local_committed_cache_publish( + "external_put_transfer_end", + &req.key, + put_id, + pending_ctx.as_ref(), + req.src_offset, + req.len, + ) { + Ok(publish) => Some(publish), + Err(err) => { + if let Err(revoke_err) = inner.put_revoke(&req.key, put_id).await { + tracing::warn!( + "external_put_transfer_end put_revoke failed after local cache publish precheck error: key={} put_id=({},{}) err={}", + req.key, + put_id.0, + put_id.1, + revoke_err + ); + } + inner + .external_pending_puts + .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + return Ok(crate::rpcresp_kvresult_convert::FromError::from_error(&err)); + } + } + } else { + None + }; + let put_end = match inner + .put_end_with_local_cache_publish(&req.key, put_id, req.lease_id, publish_local_cache) + .await + { + Ok(end) => end, Err(e) => { tracing::error!("Failed to end put operation: {}", e); inner @@ -630,12 +1683,56 @@ impl HandlerForExternalClient for ClientKvApi { return Ok(crate::rpcresp_kvresult_convert::FromError::from_error(&e)); } }; + let put_end_stats = put_end.stats; let put_end_total_us = duration_to_i64_us(end_started_at.elapsed()); - // Success; cleanup pending ctx + if publish_local_cache { + let Some(holder_id) = put_end.local_cache_holder_id else { + let err = KvError::Api(ApiError::Unknown { + detail: format!( + "external_put_transfer_end missing local cache holder after local commit: key={} put_id=({},{})", + req.key, put_id.0, put_id.1 + ), + }); + inner + .external_pending_puts + .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + return Ok(crate::rpcresp_kvresult_convert::FromError::from_error(&err)); + }; + let publish = local_cache_publish + .as_ref() + .expect("publish_local_cache precheck must provide local cache publish info"); + inner + .install_local_committed_memory_info( + &req.key, + put_id, + publish.src_offset, + publish.len, + holder_id, + ) + .await?; + } inner .external_pending_puts .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + if !req.write_through && (has_remote_append || req_remote_target) { + if let Err(err) = inner + .enqueue_write_back_remote_append( + &req.key, + put_id, + preferred_sub_cluster.as_deref(), + ) + .await + { + tracing::warn!( + "write-back external_put_transfer_end enqueue failed after local commit: key={} put_id=({},{}) err={}", + req.key, + put_id.0, + put_id.1, + err + ); + } + } Ok(ExternalPutTransferEndResp { error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, @@ -658,6 +1755,420 @@ impl HandlerForExternalClient for ClientKvApi { }) } + async fn external_batch_put_transfer_end( + &self, + req: ExternalBatchPutTransferEndReq, + ) -> KvResult { + if self.is_side_transfer_worker() { + return Err(Self::side_transfer_unsupported( + "external_batch_put_transfer_end", + )); + } + let inner = self.inner(); + + self.validate_requester_owner_status_updated(req.started_time)?; + + if req.items.is_empty() { + return Ok(ExternalBatchPutTransferEndResp { + items: Vec::new(), + error_code: OK, + error_json: String::new(), + }); + } + + #[derive(Clone)] + struct DonePending { + idx: usize, + key: String, + put_id: crate::master_kv_router::put::PutIDForAKey, + lease_id: Option, + len: u64, + put_locality: Option<(bool, i64)>, + remember_local_snapshot: bool, + publish_local_cache: bool, + local_cache_publish: Option, + enqueue_write_back_append: bool, + preferred_sub_cluster: Option, + } + + let mut results: Vec> = + (0..req.items.len()).map(|_| None).collect(); + let mut done_pending = Vec::new(); + let mut revoke_pending = Vec::new(); + let mut transfer_futures = Vec::new(); + + for (idx, item) in req.items.into_iter().enumerate() { + let Some(put_id) = item.put_id else { + let err = KvError::Unreachable( + crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::RpcDecodeError { + rpc_input_json: format!( + "missing put_id in external_batch_put_transfer_end; key={}", + item.key + ), + }, + ); + results[idx] = Some(ExternalBatchPutTransferEndItemResp::from_error(&err)); + continue; + }; + + let pending_ctx = inner + .external_pending_puts + .get(&(item.key.clone(), put_id.0, put_id.1)) + .map(|ctx| ctx.clone()); + let preferred_sub_cluster = pending_ctx + .as_ref() + .and_then(|ctx| ctx.preferred_sub_cluster.clone()); + let has_remote_append = pending_ctx + .as_ref() + .and_then(|ctx| ctx.peer_id.as_ref()) + .is_some(); + if item.peer_id.is_some() != has_remote_append { + let err = KvError::Api(ApiError::InvalidArgument { + detail: format!( + "external_batch_put_transfer_end peer_id mismatches pending ctx: key={} put_id=({},{}) req_remote_target={} ctx_remote_target={}", + item.key, + put_id.0, + put_id.1, + item.peer_id.is_some(), + has_remote_append + ), + }); + results[idx] = Some(ExternalBatchPutTransferEndItemResp::from_error(&err)); + revoke_pending.push(BatchPutRevokeItemReq { + key: item.key.clone(), + put_id, + }); + inner + .external_pending_puts + .invalidate(&(item.key.clone(), put_id.0, put_id.1)); + continue; + } + let remember_local_snapshot = !item.write_through || item.peer_id.is_none(); + let publish_local_cache = remember_local_snapshot; + let enqueue_write_back_append = !item.write_through && item.peer_id.is_some(); + let local_cache_publish = if publish_local_cache { + match local_committed_cache_publish( + "external_batch_put_transfer_end", + &item.key, + put_id, + pending_ctx.as_ref(), + item.src_offset, + item.len, + ) { + Ok(publish) => Some(publish), + Err(err) => { + results[idx] = Some(ExternalBatchPutTransferEndItemResp::from_error(&err)); + revoke_pending.push(BatchPutRevokeItemReq { + key: item.key.clone(), + put_id, + }); + inner.external_pending_puts.invalidate(&( + item.key.clone(), + put_id.0, + put_id.1, + )); + continue; + } + } + } else { + None + }; + + let transfer_args = if let Some(peer) = item.peer_id.clone() { + match pending_ctx.as_ref() { + Some(ctx) if ctx.peer_id.is_some() => { + Ok((ctx.peer_id.clone(), ctx.target_offset, Some(ctx.target_base_addr))) + } + None => match item.target_base_addr { + Some(target_base_addr) => { + Ok((Some(peer.into()), item.target_offset, Some(target_base_addr))) + } + None => Err(KvError::Unreachable( + crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::RpcDecodeError { + rpc_input_json: format!( + "missing pending remote put ctx and caller target_base_addr in external_batch_put_transfer_end; key={}, put_id=({},{}), peer_id={}", + item.key, put_id.0, put_id.1, peer + ), + }, + )), + }, + Some(_) => match item.target_base_addr { + Some(target_base_addr) => { + Ok((Some(peer.into()), item.target_offset, Some(target_base_addr))) + } + None => Err(KvError::Unreachable( + crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::RpcDecodeError { + rpc_input_json: format!( + "pending local ctx conflicted with remote external_batch_put_transfer_end; key={}, put_id=({},{}), peer_id={}", + item.key, put_id.0, put_id.1, peer + ), + }, + )), + }, + } + } else { + Ok((None, item.target_offset, None)) + }; + let (peer_id_for_transfer, target_off_for_transfer, target_base_for_transfer) = + match transfer_args { + Ok(v) => v, + Err(err) => { + results[idx] = Some(ExternalBatchPutTransferEndItemResp::from_error(&err)); + continue; + } + }; + + if !item.write_through { + done_pending.push(DonePending { + idx, + key: item.key, + put_id, + lease_id: item.lease_id, + len: item.len, + put_locality: Some((false, 0)), + remember_local_snapshot, + publish_local_cache, + local_cache_publish, + enqueue_write_back_append, + preferred_sub_cluster, + }); + continue; + } + + transfer_futures.push(async move { + let transfer_started_at = Instant::now(); + let transfer_result = inner + .put_transfer( + &item.key, + put_id, + item.src_offset, + target_off_for_transfer, + item.len, + peer_id_for_transfer, + target_base_for_transfer, + ) + .await; + ( + idx, + item.key, + item.len, + put_id, + item.lease_id, + remember_local_snapshot, + publish_local_cache, + local_cache_publish, + preferred_sub_cluster, + duration_to_i64_us(transfer_started_at.elapsed()), + transfer_result, + ) + }); + } + + let transfer_concurrency = req.transfer_concurrency.max(1); + let mut transfer_stream = + stream::iter(transfer_futures).buffer_unordered(transfer_concurrency); + while let Some(joined) = transfer_stream.next().await { + match joined { + ( + idx, + key, + len, + put_id, + lease_id, + remember_local_snapshot, + publish_local_cache, + local_cache_publish, + preferred_sub_cluster, + wall_transfer_us, + Ok(breakdown), + ) => { + let breakdown_transfer_us = breakdown.submit_blocking_us + + breakdown.create_xfer_req_us + + breakdown.post_xfer_req_us + + breakdown.poll_wait_us; + let transfer_us = breakdown_transfer_us.max(wall_transfer_us); + done_pending.push(DonePending { + idx, + key, + put_id, + lease_id, + len, + put_locality: Some((breakdown.remote_transfer, transfer_us)), + remember_local_snapshot, + publish_local_cache, + local_cache_publish, + enqueue_write_back_append: false, + preferred_sub_cluster, + }); + } + ( + idx, + key, + _len, + put_id, + _lease_id, + _remember_local_snapshot, + _publish_local_cache, + _local_cache_publish, + _preferred_sub_cluster, + _wall_transfer_us, + Err(err), + ) => { + results[idx] = Some(ExternalBatchPutTransferEndItemResp::from_error(&err)); + revoke_pending.push(BatchPutRevokeItemReq { + key: key.clone(), + put_id, + }); + inner + .external_pending_puts + .invalidate(&(key, put_id.0, put_id.1)); + } + } + } + + if !revoke_pending.is_empty() { + if let Err(err) = inner.batch_put_revoke(revoke_pending).await { + tracing::warn!( + "external_batch_put_transfer_end batch_put_revoke failed after transfer errors: {}", + err + ); + } + } + + if inner.skip_put_end_commit_enabled() { + for pending in done_pending { + inner.external_pending_puts.invalidate(&( + pending.key.clone(), + pending.put_id.0, + pending.put_id.1, + )); + if let Some((remote, transfer_us)) = pending.put_locality { + inner.record_put_locality(remote, pending.len, transfer_us); + } + results[pending.idx] = Some(ExternalBatchPutTransferEndItemResp { + error_code: OK, + error_json: String::new(), + }); + } + return Ok(ExternalBatchPutTransferEndResp { + items: results + .into_iter() + .map(|item| { + item.unwrap_or_else(|| ExternalBatchPutTransferEndItemResp { + error_code: OK, + error_json: String::new(), + }) + }) + .collect(), + error_code: OK, + error_json: String::new(), + }); + } + + let done_resp = inner + .batch_put_done( + done_pending + .iter() + .map(|pending| BatchPutDoneItemReq { + key: pending.key.clone(), + put_id: pending.put_id, + lease_id: pending.lease_id, + committed_slot: None, + publish_local_cache: pending.publish_local_cache, + }) + .collect(), + ) + .await?; + if done_resp.items.len() != done_pending.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external_batch_put_transfer_end done response length mismatch: expected={} got={}", + done_pending.len(), + done_resp.items.len() + ), + })); + } + + for (pending, done_item) in done_pending.into_iter().zip(done_resp.items.into_iter()) { + inner.external_pending_puts.invalidate(&( + pending.key.clone(), + pending.put_id.0, + pending.put_id.1, + )); + if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( + done_item.error_code, + done_item.error_json.clone(), + ) { + results[pending.idx] = Some(ExternalBatchPutTransferEndItemResp::from_error(&err)); + continue; + } + if let Some((remote, transfer_us)) = pending.put_locality { + inner.record_put_locality(remote, pending.len, transfer_us); + } + if pending.publish_local_cache { + let Some(holder_id) = done_item.local_cache_holder_id else { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external_batch_put_transfer_end missing local cache holder after local commit: key={} put_id=({},{})", + pending.key, pending.put_id.0, pending.put_id.1 + ), + })); + }; + let publish = pending + .local_cache_publish + .as_ref() + .expect("publish_local_cache precheck must provide local cache publish info"); + inner + .install_local_committed_memory_info( + &pending.key, + pending.put_id, + publish.src_offset, + publish.len, + holder_id, + ) + .await?; + } else if pending.remember_local_snapshot { + inner.remember_local_snapshot(&pending.key, pending.put_id); + } + if pending.enqueue_write_back_append { + if let Err(err) = inner + .enqueue_write_back_remote_append( + &pending.key, + pending.put_id, + pending.preferred_sub_cluster.as_deref(), + ) + .await + { + tracing::warn!( + "external_batch_put_transfer_end write-back enqueue failed after local commit: key={} put_id=({},{}) err={}", + pending.key, + pending.put_id.0, + pending.put_id.1, + err + ); + } + } + results[pending.idx] = Some(ExternalBatchPutTransferEndItemResp { + error_code: OK, + error_json: String::new(), + }); + } + + Ok(ExternalBatchPutTransferEndResp { + items: results + .into_iter() + .map(|item| { + item.unwrap_or_else(|| ExternalBatchPutTransferEndItemResp { + error_code: OK, + error_json: String::new(), + }) + }) + .collect(), + error_code: OK, + error_json: String::new(), + }) + } + async fn external_put_commit( &self, req: ExternalPutCommitReq, @@ -675,10 +2186,76 @@ impl HandlerForExternalClient for ClientKvApi { ); return Ok(ExternalPutCommitResp::from_error(&err)); }; + let pending_ctx = inner + .external_pending_puts + .get(&(req.key.clone(), put_id.0, put_id.1)) + .map(|ctx| ctx.clone()); + if let Some(ctx) = pending_ctx.as_ref() { + let has_remote_append = ctx.peer_id.is_some(); + if req.remote_target != has_remote_append { + let err = KvError::Api(ApiError::InvalidArgument { + detail: format!( + "external_put_commit remote_target mismatches pending ctx: key={} put_id=({},{}) req_remote_target={} ctx_remote_target={}", + req.key, put_id.0, put_id.1, req.remote_target, has_remote_append + ), + }); + if let Err(revoke_err) = inner.put_revoke(&req.key, put_id).await { + tracing::warn!( + "external_put_commit put_revoke failed after remote_target mismatch: key={} put_id=({},{}) err={}", + req.key, + put_id.0, + put_id.1, + revoke_err + ); + } + inner + .external_pending_puts + .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + return Ok(ExternalPutCommitResp::from_error(&err)); + } + } + let remember_local_snapshot = !req.write_through || !req.remote_target; + let enqueue_write_back_append = !req.write_through && req.remote_target; + let preferred_sub_cluster = pending_ctx + .as_ref() + .and_then(|ctx| ctx.preferred_sub_cluster.clone()); let end_started_at = Instant::now(); - let put_end_stats = match inner.put_end(&req.key, put_id, req.lease_id).await { - Ok(stats) => stats, + let publish_local_cache = remember_local_snapshot; + let local_cache_publish = if publish_local_cache { + match local_committed_cache_publish( + "external_put_commit", + &req.key, + put_id, + pending_ctx.as_ref(), + req.src_offset, + req.len, + ) { + Ok(publish) => Some(publish), + Err(err) => { + if let Err(revoke_err) = inner.put_revoke(&req.key, put_id).await { + tracing::warn!( + "external_put_commit put_revoke failed after local cache publish precheck error: key={} put_id=({},{}) err={}", + req.key, + put_id.0, + put_id.1, + revoke_err + ); + } + inner + .external_pending_puts + .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + return Ok(ExternalPutCommitResp::from_error(&err)); + } + } + } else { + None + }; + let put_end = match inner + .put_end_with_local_cache_publish(&req.key, put_id, req.lease_id, publish_local_cache) + .await + { + Ok(end) => end, Err(e) => { inner .external_pending_puts @@ -686,10 +2263,55 @@ impl HandlerForExternalClient for ClientKvApi { return Ok(ExternalPutCommitResp::from_error(&e)); } }; + let put_end_stats = put_end.stats; let put_end_total_us = duration_to_i64_us(end_started_at.elapsed()); + if publish_local_cache { + let Some(holder_id) = put_end.local_cache_holder_id else { + let err = KvError::Api(ApiError::Unknown { + detail: format!( + "external_put_commit missing local cache holder after local commit: key={} put_id=({},{})", + req.key, put_id.0, put_id.1 + ), + }); + inner + .external_pending_puts + .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + return Ok(ExternalPutCommitResp::from_error(&err)); + }; + let publish = local_cache_publish + .as_ref() + .expect("publish_local_cache precheck must provide local cache publish info"); + inner + .install_local_committed_memory_info( + &req.key, + put_id, + publish.src_offset, + publish.len, + holder_id, + ) + .await?; + } inner .external_pending_puts .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + if enqueue_write_back_append { + if let Err(err) = inner + .enqueue_write_back_remote_append( + &req.key, + put_id, + preferred_sub_cluster.as_deref(), + ) + .await + { + tracing::warn!( + "write-back external_put_commit enqueue failed after local commit: key={} put_id=({},{}) err={}", + req.key, + put_id.0, + put_id.1, + err + ); + } + } Ok(ExternalPutCommitResp { error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, @@ -707,6 +2329,262 @@ impl HandlerForExternalClient for ClientKvApi { }) } + async fn external_batch_put_commit( + &self, + req: ExternalBatchPutCommitReq, + ) -> KvResult { + if self.is_side_transfer_worker() { + return Err(Self::side_transfer_unsupported("external_batch_put_commit")); + } + let inner = self.inner(); + + self.validate_requester_owner_status_updated(req.started_time)?; + + if req.items.is_empty() { + return Ok(ExternalBatchPutCommitResp { + items: Vec::new(), + error_code: OK, + error_json: String::new(), + }); + } + + #[derive(Clone)] + struct DonePending { + idx: usize, + key: String, + put_id: crate::master_kv_router::put::PutIDForAKey, + lease_id: Option, + remember_local_snapshot: bool, + publish_local_cache: bool, + local_cache_publish: Option, + enqueue_write_back_append: bool, + preferred_sub_cluster: Option, + } + + let mut results: Vec> = + (0..req.items.len()).map(|_| None).collect(); + let mut done_pending = Vec::new(); + let mut revoke_pending = Vec::new(); + + for (idx, item) in req.items.into_iter().enumerate() { + let Some(put_id) = item.put_id else { + let err = KvError::Unreachable( + crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::RpcDecodeError { + rpc_input_json: format!( + "missing put_id in external_batch_put_commit; key={}", + item.key + ), + }, + ); + results[idx] = Some(ExternalBatchPutCommitItemResp::from_error(&err)); + continue; + }; + let pending_ctx = inner + .external_pending_puts + .get(&(item.key.clone(), put_id.0, put_id.1)) + .map(|ctx| ctx.clone()); + if let Some(ctx) = pending_ctx.as_ref() { + let has_remote_append = ctx.peer_id.is_some(); + if item.remote_target != has_remote_append { + let err = KvError::Api(ApiError::InvalidArgument { + detail: format!( + "external_batch_put_commit remote_target mismatches pending ctx: key={} put_id=({},{}) req_remote_target={} ctx_remote_target={}", + item.key, put_id.0, put_id.1, item.remote_target, has_remote_append + ), + }); + results[idx] = Some(ExternalBatchPutCommitItemResp::from_error(&err)); + revoke_pending.push(BatchPutRevokeItemReq { + key: item.key.clone(), + put_id, + }); + inner + .external_pending_puts + .invalidate(&(item.key.clone(), put_id.0, put_id.1)); + continue; + } + } + let remember_local_snapshot = !item.write_through || !item.remote_target; + let publish_local_cache = remember_local_snapshot; + let local_cache_publish = if publish_local_cache { + match local_committed_cache_publish( + "external_batch_put_commit", + &item.key, + put_id, + pending_ctx.as_ref(), + item.src_offset, + item.len, + ) { + Ok(publish) => Some(publish), + Err(err) => { + results[idx] = Some(ExternalBatchPutCommitItemResp::from_error(&err)); + revoke_pending.push(BatchPutRevokeItemReq { + key: item.key.clone(), + put_id, + }); + inner.external_pending_puts.invalidate(&( + item.key.clone(), + put_id.0, + put_id.1, + )); + continue; + } + } + } else { + None + }; + let preferred_sub_cluster = pending_ctx + .as_ref() + .and_then(|ctx| ctx.preferred_sub_cluster.clone()); + done_pending.push(DonePending { + idx, + key: item.key.clone(), + put_id, + lease_id: item.lease_id, + remember_local_snapshot, + publish_local_cache, + local_cache_publish, + enqueue_write_back_append: !item.write_through && item.remote_target, + preferred_sub_cluster, + }); + } + + if !revoke_pending.is_empty() { + if let Err(err) = inner.batch_put_revoke(revoke_pending).await { + tracing::warn!( + "external_batch_put_commit batch_put_revoke failed after local cache publish precheck errors: {}", + err + ); + } + } + + if inner.skip_put_end_commit_enabled() { + for pending in done_pending { + inner.external_pending_puts.invalidate(&( + pending.key.clone(), + pending.put_id.0, + pending.put_id.1, + )); + results[pending.idx] = Some(ExternalBatchPutCommitItemResp { + error_code: OK, + error_json: String::new(), + }); + } + return Ok(ExternalBatchPutCommitResp { + items: results + .into_iter() + .map(|item| { + item.unwrap_or_else(|| ExternalBatchPutCommitItemResp { + error_code: OK, + error_json: String::new(), + }) + }) + .collect(), + error_code: OK, + error_json: String::new(), + }); + } + + let done_resp = inner + .batch_put_done( + done_pending + .iter() + .map(|pending| BatchPutDoneItemReq { + key: pending.key.clone(), + put_id: pending.put_id, + lease_id: pending.lease_id, + committed_slot: None, + publish_local_cache: pending.publish_local_cache, + }) + .collect(), + ) + .await?; + if done_resp.items.len() != done_pending.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external_batch_put_commit done response length mismatch: expected={} got={}", + done_pending.len(), + done_resp.items.len() + ), + })); + } + + for (pending, done_item) in done_pending.into_iter().zip(done_resp.items.into_iter()) { + inner.external_pending_puts.invalidate(&( + pending.key.clone(), + pending.put_id.0, + pending.put_id.1, + )); + if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( + done_item.error_code, + done_item.error_json.clone(), + ) { + results[pending.idx] = Some(ExternalBatchPutCommitItemResp::from_error(&err)); + continue; + } + if pending.publish_local_cache { + let Some(holder_id) = done_item.local_cache_holder_id else { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external_batch_put_commit missing local cache holder after local commit: key={} put_id=({},{})", + pending.key, pending.put_id.0, pending.put_id.1 + ), + })); + }; + let publish = pending + .local_cache_publish + .as_ref() + .expect("publish_local_cache precheck must provide local cache publish info"); + inner + .install_local_committed_memory_info( + &pending.key, + pending.put_id, + publish.src_offset, + publish.len, + holder_id, + ) + .await?; + } else if pending.remember_local_snapshot { + inner.remember_local_snapshot(&pending.key, pending.put_id); + } + if pending.enqueue_write_back_append { + if let Err(err) = inner + .enqueue_write_back_remote_append( + &pending.key, + pending.put_id, + pending.preferred_sub_cluster.as_deref(), + ) + .await + { + tracing::warn!( + "external_batch_put_commit write-back enqueue failed after local commit: key={} put_id=({},{}) err={}", + pending.key, + pending.put_id.0, + pending.put_id.1, + err + ); + } + } + results[pending.idx] = Some(ExternalBatchPutCommitItemResp { + error_code: OK, + error_json: String::new(), + }); + } + + Ok(ExternalBatchPutCommitResp { + items: results + .into_iter() + .map(|item| { + item.unwrap_or_else(|| ExternalBatchPutCommitItemResp { + error_code: OK, + error_json: String::new(), + }) + }) + .collect(), + error_code: OK, + error_json: String::new(), + }) + } + async fn external_put_revoke( &self, req: ExternalPutRevokeReq, @@ -775,4 +2653,46 @@ impl HandlerForExternalClient for ClientKvApi { }), } } + + async fn external_batch_is_exist( + &self, + req: ExternalBatchIsExistReq, + ) -> KvResult { + if self.is_side_transfer_worker() { + return Err(Self::side_transfer_unsupported("external_batch_is_exist")); + } + let inner = self.inner(); + + self.validate_requester_owner_status_updated(req.started_time)?; + + match inner + .batch_is_exist(req.keys, req.allow_local_snapshot) + .await + { + Ok(exists_list) => Ok(ExternalBatchIsExistResp { + error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, + exists_list, + error_json: String::new(), + }), + Err(e) => Ok(ExternalBatchIsExistResp { + exists_list: Vec::new(), + ..ExternalBatchIsExistResp::from_error(&e) + }), + } + } + + async fn external_observability_snapshot( + &self, + req: ExternalObservabilitySnapshotReq, + ) -> KvResult { + if self.is_side_transfer_worker() { + return Err(Self::side_transfer_unsupported( + "external_observability_snapshot", + )); + } + self.validate_requester_owner_status_updated(req.started_time)?; + Ok(ExternalObservabilitySnapshotResp::success( + self.inner().locality_snapshot(), + )) + } } diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs index f309dd0..88cafa3 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs @@ -1,5 +1,4 @@ -use super::ClientKvApiInner; -use crate::client_kv_api::CachedValue; +use super::{ClientKvApiInner, GetCachedInfo, KvMetrics}; use crate::cluster_manager::app_logic_ext::ClusterManagerAppLogicExt; use crate::memholder::{MemoryInfo, UserMemHolder, UserMemHolderExposeKind}; // no StageScope; timestamps-based metrics only @@ -12,6 +11,8 @@ use crate::observe_kvope::{ use crate::{ cluster_manager::NodeID, master_kv_router::msg_pack::{ + BatchGetDoneReq, BatchGetDoneResp, BatchGetRevokeReq, BatchGetRevokeResp, + BatchGetStartItemResp, BatchGetStartReq, BatchGetStartResp, BatchIsExistReq, GetAllocationMode, GetDoneReq, GetDoneResp, GetMetaReq, GetMetaResp, GetRevokeReq, GetStartReq, GetStartResp, }, @@ -20,7 +21,10 @@ use crate::{ rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, KvResult, OK}, }; use chrono::Utc; +use futures::stream::{self, StreamExt}; +use limit_thirdparty::tokio; use std::sync::Arc; +use std::time::Instant; #[derive(Debug, Clone)] pub struct RemoteGetInfo { @@ -47,57 +51,293 @@ impl std::fmt::Display for RemoteGetInfo { } } +impl RemoteGetInfo { + pub fn data_len(&self) -> usize { + self.data_len + } + + pub fn is_remote_transfer(&self) -> bool { + self.peer_is_src_or_target + } +} + impl ClientKvApiInner { - /// becaused we cached local kv metadata, so we make `MemHolder` with Arc here - pub async fn get( + pub async fn batch_get_finish_started( &self, - key: &str, - ) -> KvResult, Option)>> { + keys: Vec, + start_items: Vec, + transfer_concurrency: usize, + ) -> KvResult, Option)>>>> { if !self.view.register_shutdown_poller().is_running() { return Err(KvError::Api(ApiError::SystemShutdown { - detail: "ClientKvApi is shutting down; rejecting get".to_string(), + detail: "ClientKvApi is shutting down; rejecting batch_get_finish_started" + .to_string(), + })); + } + if keys.len() != start_items.len() { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "batch_get_finish_started length mismatch: keys={} start_items={}", + keys.len(), + start_items.len() + ), })); } + if keys.is_empty() { + return Ok(Vec::new()); + } + + #[derive(Clone)] + struct DonePending { + idx: usize, + key: String, + start_item: BatchGetStartItemResp, + peer_is_remote: bool, + transfer_us: i64, + } + + let transfer_concurrency = transfer_concurrency.max(1); let metrics = self.metrics_handle(); let client_id = self.client_id_str(); let node_role = self.node_role(); + let self_node_id = self.view.cluster_manager().get_self_info().id.clone(); - if let Some(cached_info) = self.get_cached_info.get(key) { - if let CachedValue::LocalReplica(memory_info) = &cached_info.value { - tracing::debug!( - "cache hit for key: {} with putid({},{}), directly return", + let mut results: Vec< + Option, Option)>>>, + > = (0..keys.len()).map(|_| None).collect(); + let mut done_pending = Vec::new(); + let mut revoke_get_ids = Vec::new(); + let mut transfer_futures = Vec::new(); + + for (idx, (key, start_item)) in keys.into_iter().zip(start_items.into_iter()).enumerate() { + if start_item.error_code == codes_api::API_KEY_NOT_FOUND { + results[idx] = Some(Ok(None)); + continue; + } + if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( + start_item.error_code, + start_item.error_json.clone(), + ) { + results[idx] = Some(Err(err)); + continue; + } + + let peer_id = if start_item.node_id == self_node_id { + None + } else { + Some(start_item.node_id.clone()) + }; + let peer_is_remote = peer_id.is_some(); + let get_id = start_item.get_id; + let src_addr = start_item.src_addr; + let target_addr = start_item.target_addr; + let len = start_item.len; + + if peer_id.is_none() && src_addr == target_addr { + done_pending.push(DonePending { + idx, key, - cached_info.put_time_ms, - cached_info.put_version - ); - let user_mem_holder = Arc::new(UserMemHolder::new( - memory_info.clone(), - self.get_or_init_all_memholder_refcount(), - UserMemHolderExposeKind::SegPtr, - )); - obe_get_cache_hit( - &metrics, - &client_id, - &node_role, + start_item, + peer_is_remote, + transfer_us: 0, + }); + continue; + } + + transfer_futures.push(async move { + let transfer_started_at = Instant::now(); + let transfer_result = self + .view + .client_transfer_engine() + .transfer_data_no_copy(peer_id, true, src_addr, target_addr, len, None) + .await + .map_err(|err| { + KvError::Api(ApiError::Transfer { + from_addr: src_addr, + to_addr: target_addr, + len, + error: err.to_string(), + }) + }); + let transfer_us = transfer_started_at + .elapsed() + .as_micros() + .min(i64::MAX as u128) as i64; + ( + idx, key, - memory_info.len as u64, + start_item, + peer_is_remote, + get_id, + transfer_us, + transfer_result, + ) + }); + } + + let mut transfer_stream = + stream::iter(transfer_futures).buffer_unordered(transfer_concurrency); + while let Some(joined) = transfer_stream.next().await { + match joined { + (idx, key, start_item, peer_is_remote, _get_id, transfer_us, Ok(_breakdown)) => { + done_pending.push(DonePending { + idx, + key, + start_item, + peer_is_remote, + transfer_us, + }); + } + (idx, _key, _start_item, _peer_is_remote, get_id, _transfer_us, Err(err)) => { + results[idx] = Some(Err(err)); + revoke_get_ids.push(get_id); + } + } + } + + if !revoke_get_ids.is_empty() { + if let Err(err) = self.batch_get_revoke(revoke_get_ids).await { + tracing::warn!("batch_get_revoke failed after transfer errors: {}", err); + } + } + + let done_resp = self + .batch_get_done( + done_pending + .iter() + .map(|pending| pending.start_item.get_id) + .collect(), + ) + .await?; + if done_resp.items.len() != done_pending.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "batch_get_done response length mismatch: expected={} got={}", + done_pending.len(), + done_resp.items.len() + ), + })); + } + let master_node_id: NodeID = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await? + .into(); + + for (pending, done_item) in done_pending.into_iter().zip(done_resp.items.into_iter()) { + if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( + done_item.error_code, + done_item.error_json.clone(), + ) { + results[pending.idx] = Some(Err(err)); + continue; + } + let expose_kind = if done_item.allocation_mode == GetAllocationMode::Temporary { + UserMemHolderExposeKind::OwnedCopy + } else { + UserMemHolderExposeKind::SegPtr + }; + let offset = pending.start_item.target_addr - pending.start_item.target_base_addr; + let data_len = pending.start_item.len as usize; + metrics.record_l2_hit_locality(pending.peer_is_remote, data_len as u64); + metrics.record_get_io_locality( + pending.peer_is_remote, + data_len as u64, + pending.transfer_us, + ); + let memory_info = Arc::new( + MemoryInfo::new( + offset, + pending.start_item.len as u32, + done_item.holder_id, + pending.key.clone(), + master_node_id.clone(), + self.view.clone(), + ) + .await, + ); + let get_info = RemoteGetInfo { + get_id: pending.start_item.get_id, + data_len, + src_addr: pending.start_item.src_addr, + target_addr: pending.start_item.target_addr, + node_id: pending.start_item.node_id.clone().into(), + peer_is_src_or_target: pending.peer_is_remote, + }; + if done_item.allocation_mode != GetAllocationMode::Temporary { + self.get_cached_info.insert( + pending.key.clone(), + GetCachedInfo { + put_time_ms: pending.start_item.put_id.0, + put_version: pending.start_item.put_id.1, + mem_holder: memory_info.clone(), + }, ); - return Ok(Some((user_mem_holder, None))); + self.remember_local_snapshot(&pending.key, pending.start_item.put_id); + metrics.observe_cache_value_size(&client_id, node_role.as_str(), data_len as u64); } + let user_mem_holder = Arc::new(UserMemHolder::new( + memory_info, + self.get_or_init_all_memholder_refcount(), + expose_kind, + )); + results[pending.idx] = Some(Ok(Some((user_mem_holder, Some(get_info))))); } - let lock = self.get_remote_kv_lock.get_lock(key.to_owned()); - let _guard = lock.lock().await; + Ok(results + .into_iter() + .map(|item| { + item.unwrap_or_else(|| { + Err(KvError::Api(ApiError::Unknown { + detail: "batch_get_finish_started result slot was not populated" + .to_string(), + })) + }) + }) + .collect()) + } - // Recheck after acquiring the miss lock so concurrent cache-fillers can collapse here - // without forcing every cache hit through the async lock path. - if let Some(cached_info) = self.get_cached_info.get(key) { - if let CachedValue::LocalReplica(memory_info) = &cached_info.value { + pub async fn batch_get( + &self, + keys: Vec, + transfer_concurrency: usize, + ) -> KvResult, Option)>>>> { + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting batch_get".to_string(), + })); + } + if keys.is_empty() { + return Ok(Vec::new()); + } + + #[derive(Clone)] + struct DonePending { + idx: usize, + key: String, + start_item: crate::master_kv_router::msg_pack::BatchGetStartItemResp, + peer_is_remote: bool, + transfer_us: i64, + } + + let transfer_concurrency = transfer_concurrency.max(1); + let metrics = self.metrics_handle(); + let client_id = self.client_id_str(); + let node_role = self.node_role(); + let self_node_id = self.view.cluster_manager().get_self_info().id.clone(); + + let mut results: Vec< + Option, Option)>>>, + > = (0..keys.len()).map(|_| None).collect(); + let mut missing_indices = Vec::new(); + let mut missing_keys = Vec::new(); + + for (idx, key) in keys.iter().enumerate() { + if let Some(memory_info) = self.local_visible_mem_holder(key) { tracing::debug!( - "cache hit after miss-lock for key: {} with putid({},{}), directly return", - key, - cached_info.put_time_ms, - cached_info.put_version + "batch_get local visible hit for key: {}, directly return", + key ); let user_mem_holder = Arc::new(UserMemHolder::new( memory_info.clone(), @@ -111,8 +351,368 @@ impl ClientKvApiInner { key, memory_info.len as u64, ); - return Ok(Some((user_mem_holder, None))); + metrics.record_get_io_locality(false, memory_info.len as u64, 0); + results[idx] = Some(Ok(Some((user_mem_holder, None)))); + } else { + obe_get_cache_miss(&metrics, &client_id, &node_role, key); + missing_indices.push(idx); + missing_keys.push(key.clone()); + } + } + + if missing_keys.is_empty() { + return Ok(results + .into_iter() + .map(|item| { + item.unwrap_or_else(|| { + Err(KvError::Api(ApiError::Unknown { + detail: "batch_get result slot was not populated".to_string(), + })) + }) + }) + .collect()); + } + + let start_resp = self.batch_get_start(missing_keys.clone()).await?; + if start_resp.items.len() != missing_keys.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "batch_get_start response length mismatch: expected={} got={}", + missing_keys.len(), + start_resp.items.len() + ), + })); + } + + let mut done_pending = Vec::new(); + let mut revoke_get_ids = Vec::new(); + let mut transfer_futures = Vec::new(); + + for ((idx, key), start_item) in missing_indices + .into_iter() + .zip(missing_keys.into_iter()) + .zip(start_resp.items.into_iter()) + { + if start_item.error_code == codes_api::API_KEY_NOT_FOUND { + results[idx] = Some(Ok(None)); + continue; + } + if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( + start_item.error_code, + start_item.error_json.clone(), + ) { + results[idx] = Some(Err(err)); + continue; + } + + let peer_id = if start_item.node_id == self_node_id { + None + } else { + Some(start_item.node_id.clone()) + }; + let peer_is_remote = peer_id.is_some(); + let get_id = start_item.get_id; + let src_addr = start_item.src_addr; + let target_addr = start_item.target_addr; + let len = start_item.len; + + if peer_id.is_none() && src_addr == target_addr { + done_pending.push(DonePending { + idx, + key, + start_item, + peer_is_remote, + transfer_us: 0, + }); + continue; + } + + transfer_futures.push(async move { + let transfer_started_at = Instant::now(); + let transfer_result = self + .view + .client_transfer_engine() + .transfer_data_no_copy(peer_id, true, src_addr, target_addr, len, None) + .await + .map_err(|err| { + KvError::Api(ApiError::Transfer { + from_addr: src_addr, + to_addr: target_addr, + len, + error: err.to_string(), + }) + }); + let transfer_us = transfer_started_at + .elapsed() + .as_micros() + .min(i64::MAX as u128) as i64; + ( + idx, + key, + start_item, + peer_is_remote, + get_id, + transfer_us, + transfer_result, + ) + }); + } + + let mut transfer_stream = + stream::iter(transfer_futures).buffer_unordered(transfer_concurrency); + while let Some(joined) = transfer_stream.next().await { + match joined { + (idx, key, start_item, peer_is_remote, _get_id, transfer_us, Ok(_breakdown)) => { + done_pending.push(DonePending { + idx, + key, + start_item, + peer_is_remote, + transfer_us, + }); + } + (idx, _key, _start_item, _peer_is_remote, get_id, _transfer_us, Err(err)) => { + results[idx] = Some(Err(err)); + revoke_get_ids.push(get_id); + } + } + } + + if !revoke_get_ids.is_empty() { + if let Err(err) = self.batch_get_revoke(revoke_get_ids).await { + tracing::warn!("batch_get_revoke failed after transfer errors: {}", err); + } + } + + let done_resp = self + .batch_get_done( + done_pending + .iter() + .map(|pending| pending.start_item.get_id) + .collect(), + ) + .await?; + if done_resp.items.len() != done_pending.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "batch_get_done response length mismatch: expected={} got={}", + done_pending.len(), + done_resp.items.len() + ), + })); + } + let master_node_id: NodeID = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await? + .into(); + + for (pending, done_item) in done_pending.into_iter().zip(done_resp.items.into_iter()) { + if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( + done_item.error_code, + done_item.error_json.clone(), + ) { + results[pending.idx] = Some(Err(err)); + continue; + } + let expose_kind = if done_item.allocation_mode == GetAllocationMode::Temporary { + UserMemHolderExposeKind::OwnedCopy + } else { + UserMemHolderExposeKind::SegPtr + }; + let offset = pending.start_item.target_addr - pending.start_item.target_base_addr; + let data_len = pending.start_item.len as usize; + metrics.record_l2_hit_locality(pending.peer_is_remote, data_len as u64); + metrics.record_get_io_locality( + pending.peer_is_remote, + data_len as u64, + pending.transfer_us, + ); + let memory_info = Arc::new( + MemoryInfo::new( + offset, + pending.start_item.len as u32, + done_item.holder_id, + pending.key.clone(), + master_node_id.clone(), + self.view.clone(), + ) + .await, + ); + let get_info = RemoteGetInfo { + get_id: pending.start_item.get_id, + data_len, + src_addr: pending.start_item.src_addr, + target_addr: pending.start_item.target_addr, + node_id: pending.start_item.node_id.clone().into(), + peer_is_src_or_target: pending.peer_is_remote, + }; + if done_item.allocation_mode != GetAllocationMode::Temporary { + self.get_cached_info.insert( + pending.key.clone(), + GetCachedInfo { + put_time_ms: pending.start_item.put_id.0, + put_version: pending.start_item.put_id.1, + mem_holder: memory_info.clone(), + }, + ); + self.remember_local_snapshot(&pending.key, pending.start_item.put_id); + metrics.observe_cache_value_size(&client_id, node_role.as_str(), data_len as u64); } + let user_mem_holder = Arc::new(UserMemHolder::new( + memory_info, + self.get_or_init_all_memholder_refcount(), + expose_kind, + )); + results[pending.idx] = Some(Ok(Some((user_mem_holder, Some(get_info))))); + } + + Ok(results + .into_iter() + .map(|item| { + item.unwrap_or_else(|| { + Err(KvError::Api(ApiError::Unknown { + detail: "batch_get result slot was not populated".to_string(), + })) + }) + }) + .collect()) + } + + pub async fn batch_is_exist( + &self, + keys: Vec, + allow_local_snapshot: bool, + ) -> KvResult> { + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting batch_is_exist".to_string(), + })); + } + if keys.is_empty() { + return Ok(Vec::new()); + } + + let mut results = vec![false; keys.len()]; + let mut missing_indices = Vec::new(); + let mut missing_keys = Vec::new(); + for (idx, key) in keys.iter().enumerate() { + if allow_local_snapshot && self.has_local_snapshot(key) { + results[idx] = true; + continue; + } + missing_indices.push(idx); + missing_keys.push(key.clone()); + } + if missing_keys.is_empty() { + return Ok(results); + } + + let req = MsgPack { + serialize_part: BatchIsExistReq { keys: missing_keys }, + raw_bytes: Vec::new(), + }; + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let resp = self + .rpc_caller_batch_is_exist + .call(self.view.p2p_module(), master_node_id.into(), req, None, 0) + .await + .map_err(KvError::from)?; + let resp_part = resp.serialize_part; + crate::rpcresp_kvresult_convert::try_from_code( + resp_part.error_code, + resp_part.error_json.clone(), + )?; + if resp_part.exists_list.len() != missing_indices.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "batch_is_exist response length mismatch: expected={} got={}", + missing_indices.len(), + resp_part.exists_list.len() + ), + })); + } + for (idx, exists) in missing_indices + .into_iter() + .zip(resp_part.exists_list.into_iter()) + { + results[idx] = exists; + } + Ok(results) + } + + pub async fn is_exist_with_local_snapshot( + &self, + key: &str, + allow_local_snapshot: bool, + ) -> KvResult { + let mut results = self + .batch_is_exist(vec![key.to_string()], allow_local_snapshot) + .await?; + Ok(results.pop().unwrap_or(false)) + } + + /// becaused we cached local kv metadata, so we make `MemHolder` with Arc here + pub async fn get( + &self, + key: &str, + ) -> KvResult, Option)>> { + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting get".to_string(), + })); + } + let metrics = self.metrics_handle(); + let client_id = self.client_id_str(); + let node_role = self.node_role(); + + if let Some(memory_info) = self.local_visible_mem_holder(key) { + // exist, directly return + tracing::debug!("local visible cache hit for key: {}, directly return", key); + // Build a fresh UserMemHolder from cached MemoryInfo + let user_mem_holder = Arc::new(UserMemHolder::new( + memory_info.clone(), + self.get_or_init_all_memholder_refcount(), + UserMemHolderExposeKind::SegPtr, + )); + obe_get_cache_hit( + &metrics, + &client_id, + &node_role, + key, + memory_info.len as u64, + ); + return Ok(Some((user_mem_holder, None))); + } + + let lock = self.get_remote_kv_lock.get_lock(key.to_owned()); + let _guard = lock.lock().await; + + // Recheck after acquiring the miss lock so concurrent cache-fillers can collapse here + // without forcing every cache hit through the async lock path. + if let Some(memory_info) = self.local_visible_mem_holder(key) { + tracing::debug!( + "local visible cache hit after miss-lock for key: {}, directly return", + key + ); + let user_mem_holder = Arc::new(UserMemHolder::new( + memory_info.clone(), + self.get_or_init_all_memholder_refcount(), + UserMemHolderExposeKind::SegPtr, + )); + obe_get_cache_hit( + &metrics, + &client_id, + &node_role, + key, + memory_info.len as u64, + ); + return Ok(Some((user_mem_holder, None))); } obe_get_cache_miss(&metrics, &client_id, &node_role, key); @@ -333,7 +933,15 @@ impl ClientKvApiInner { }; if done_resp.allocation_mode != GetAllocationMode::Temporary { - self.cache_local_replica_after_get(key, put_id, memory_info.clone()); + self.get_cached_info.insert( + key.to_string(), + GetCachedInfo { + put_time_ms: put_id.0, + put_version: put_id.1, + mem_holder: memory_info.clone(), + }, + ); + self.remember_local_snapshot(key, put_id); metrics.observe_cache_value_size(&client_id, node_role.as_str(), data_len as u64); } let user_mem_holder = Arc::new(UserMemHolder::new( @@ -347,28 +955,7 @@ impl ClientKvApiInner { } pub async fn is_exist(&self, key: &str) -> KvResult { - if !self.view.register_shutdown_poller().is_running() { - return Err(KvError::Api(ApiError::SystemShutdown { - detail: "ClientKvApi is shutting down; rejecting is_exist".to_string(), - })); - } - let resp = self.get_meta(key).await?; - if resp.error_code != OK { - // If error code indicates key not found, return false - if resp.error_code - == crate::rpcresp_kvresult_convert::msg_and_error::codes_api::API_KEY_NOT_FOUND - { - return Ok(false); - } - // For other errors, propagate the error - crate::rpcresp_kvresult_convert::try_from_code( - resp.error_code, - resp.error_json.clone(), - )?; - unreachable!("error path should have returned above"); - } - - Ok(resp.exists) + self.is_exist_with_local_snapshot(key, false).await } /// Get metadata for a key without transferring data @@ -433,6 +1020,33 @@ impl ClientKvApiInner { Ok(resp.serialize_part) } + pub async fn batch_get_start(&self, keys: Vec) -> KvResult { + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting batch_get_start".to_string(), + })); + } + let req = MsgPack { + serialize_part: BatchGetStartReq { keys }, + raw_bytes: Vec::new(), + }; + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let resp = self + .rpc_caller_batch_get_start + .call(self.view.p2p_module(), master_node_id.into(), req, None, 0) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + Ok(resp.serialize_part) + } + /// 撤销 Get 操作,释放已分配的资源 pub async fn get_revoke(&self, get_id: u64) -> KvResult<()> { let req = MsgPack { @@ -457,6 +1071,35 @@ impl ClientKvApiInner { Ok(()) } + pub async fn batch_get_revoke(&self, get_ids: Vec) -> KvResult { + if get_ids.is_empty() { + return Ok(BatchGetRevokeResp { + items: Vec::new(), + error_code: OK, + error_json: String::new(), + }); + } + let req = MsgPack { + serialize_part: BatchGetRevokeReq { get_ids }, + raw_bytes: Vec::new(), + }; + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let resp = self + .rpc_caller_batch_get_revoke + .call(self.view.p2p_module(), master_node_id.into(), req, None, 0) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + Ok(resp.serialize_part) + } + /// 完成 Get 操作,清理资源 pub async fn get_done(&self, get_id: u64) -> KvResult { let req = MsgPack { @@ -480,4 +1123,34 @@ impl ClientKvApiInner { Ok(resp.serialize_part) } + + pub async fn batch_get_done(&self, get_ids: Vec) -> KvResult { + if get_ids.is_empty() { + return Ok(BatchGetDoneResp { + items: Vec::new(), + error_code: OK, + error_json: String::new(), + server_process_us: 0, + }); + } + let req = MsgPack { + serialize_part: BatchGetDoneReq { get_ids }, + raw_bytes: Vec::new(), + }; + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let resp = self + .rpc_caller_batch_get_done + .call(self.view.p2p_module(), master_node_id.into(), req, None, 0) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + Ok(resp.serialize_part) + } } diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/local_reserve_rebalance.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/local_reserve_rebalance.rs new file mode 100644 index 0000000..016f735 --- /dev/null +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/local_reserve_rebalance.rs @@ -0,0 +1,308 @@ +use super::{ + ClientKvApiInner, ClientKvApiView, OwnerLocalReserveClassState, OwnerLocalReservePoolState, +}; +use crate::OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES; +use limit_thirdparty::tokio; +use std::time::{Duration, Instant}; + +const OWNER_LOCAL_RESERVE_REBALANCE_INTERVAL: Duration = Duration::from_millis(200); +const OWNER_LOCAL_RESERVE_SHRINK_IDLE_COOLDOWN: Duration = Duration::from_secs(5); +const OWNER_LOCAL_RESERVE_SHRINK_GROW_COOLDOWN: Duration = Duration::from_secs(1); +const OWNER_LOCAL_RESERVE_DEFAULT_SOFT_WAIT_TIMEOUT: Duration = Duration::from_millis(10); +const OWNER_LOCAL_RESERVE_DEFAULT_HARD_TIMEOUT: Duration = Duration::from_secs(1); +const OWNER_LOCAL_RESERVE_GROW_FACTOR_NUM: usize = 2; +const OWNER_LOCAL_RESERVE_MIN_GRANTS_PER_CLASS: usize = 0; + +#[derive(Debug, Clone, Copy)] +struct RebalanceClassSnapshot { + slot_size: u64, + slots_per_grant: u32, + used_slots: usize, + grant_count: usize, + pending_slot_demand: usize, +} + +fn owner_local_reserve_round_up_grants(bytes: u64) -> u64 { + let quantum = OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES; + if bytes == 0 { + return 0; + } + let rem = bytes % quantum; + if rem == 0 { + bytes + } else { + bytes.checked_add(quantum - rem).unwrap_or(u64::MAX) + } +} + +fn owner_local_reserve_target_bytes( + slot_size: u64, + used_slots: usize, + pending_slot_demand: usize, +) -> u64 { + let required_slots = used_slots.saturating_add(pending_slot_demand); + let required_bytes = (required_slots as u64).saturating_mul(slot_size); + let doubled_used = (used_slots as u64) + .saturating_mul(slot_size) + .saturating_mul(OWNER_LOCAL_RESERVE_GROW_FACTOR_NUM as u64); + required_bytes.max(doubled_used) +} + +fn owner_local_reserve_target_grant_count( + slot_size: u64, + used_slots: usize, + pending_slot_demand: usize, +) -> usize { + let target_bytes = owner_local_reserve_target_bytes(slot_size, used_slots, pending_slot_demand); + let rounded = owner_local_reserve_round_up_grants(target_bytes); + if rounded == 0 { + return 0; + } + (rounded / OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES) as usize +} + +fn snapshot_rebalance_classes(pool: &OwnerLocalReservePoolState) -> Vec { + pool.classes + .values() + .map(|class_state| RebalanceClassSnapshot { + slot_size: class_state.slot_size, + slots_per_grant: class_state.slots_per_grant, + used_slots: class_state.used_slot_count(), + grant_count: class_state.grant_count(), + pending_slot_demand: class_state.pending_slot_demand, + }) + .collect() +} + +pub(crate) fn owner_local_reserve_timeout_config(inner: &ClientKvApiInner) -> (Duration, Duration) { + let soft_wait_timeout = inner + .test_spec_config + .owner_local_reserve_soft_wait_timeout_ms + .map(Duration::from_millis) + .unwrap_or(OWNER_LOCAL_RESERVE_DEFAULT_SOFT_WAIT_TIMEOUT); + let hard_timeout = inner + .test_spec_config + .owner_local_reserve_hard_timeout_ms + .map(Duration::from_millis) + .unwrap_or(OWNER_LOCAL_RESERVE_DEFAULT_HARD_TIMEOUT); + (soft_wait_timeout, hard_timeout) +} + +async fn try_refill_once(inner: &ClientKvApiInner, snapshot: RebalanceClassSnapshot) { + if snapshot.pending_slot_demand == 0 { + return; + } + if snapshot.slot_size > OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES { + tracing::error!( + "owner local reserve refill rejected oversized slot_size={} quantum={} pending_slots={}", + snapshot.slot_size, + OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES, + snapshot.pending_slot_demand + ); + return; + } + let target_grants = owner_local_reserve_target_grant_count( + snapshot.slot_size, + snapshot.used_slots, + snapshot.pending_slot_demand, + ); + if snapshot.grant_count >= target_grants { + return; + } + let additional_grants = target_grants - snapshot.grant_count; + for _ in 0..additional_grants { + let grant = match inner.reserve_local_grant().await { + Ok(grant) => grant, + Err(err) => { + tracing::warn!( + "owner local reserve refill failed: slot_size={} pending_slots={} err={}", + snapshot.slot_size, + snapshot.pending_slot_demand, + err + ); + return; + } + }; + if grant.len != OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES { + tracing::warn!( + "owner local reserve refill got unexpected grant size: requested={} got={}", + OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES, + grant.len + ); + if let Err(release_err) = inner.release_local_grant(grant.grant_id).await { + tracing::warn!( + "owner local reserve refill failed to release mismatched grant_id={} err={}", + grant.grant_id, + release_err + ); + } + return; + } + let detached_grant = super::OwnerLocalReserveGrantState::new( + grant.grant_id, + grant.base_addr, + grant.addr, + grant.len, + snapshot.slot_size, + snapshot.slots_per_grant, + ); + { + let mut pool = inner.owner_local_reserve_pool.lock(); + let class_state = pool.classes.entry(snapshot.slot_size).or_insert_with(|| { + OwnerLocalReserveClassState::new(snapshot.slot_size, snapshot.slots_per_grant) + }); + class_state.last_grow_at = Some(Instant::now()); + class_state.grants.push(detached_grant); + } + inner + .owner_local_reserve_rebalance_notify() + .notify_waiters(); + } +} + +async fn try_shrink_once(inner: &ClientKvApiInner, snapshot: RebalanceClassSnapshot) { + let detached = { + let mut pool = inner.owner_local_reserve_pool.lock(); + let Some(class_state) = pool.classes.get_mut(&snapshot.slot_size) else { + return; + }; + if class_state.pending_slot_demand > 0 { + return; + } + let grow_cooldown_ok = class_state + .last_grow_at + .map(|last_grow_at| last_grow_at.elapsed() >= OWNER_LOCAL_RESERVE_SHRINK_GROW_COOLDOWN) + .unwrap_or(true); + if !grow_cooldown_ok { + return; + } + let shrink_keep_grants = owner_local_reserve_target_grant_count( + class_state.slot_size, + class_state.used_slot_count(), + class_state.pending_slot_demand, + ) + .max(OWNER_LOCAL_RESERVE_MIN_GRANTS_PER_CLASS); + if class_state.grants.len() <= shrink_keep_grants { + return; + } + let should_detach_tail = class_state + .grants + .last() + .map(|grant| { + grant.is_fully_free() + && grant + .fully_free_since + .map(|since| since.elapsed() >= OWNER_LOCAL_RESERVE_SHRINK_IDLE_COOLDOWN) + .unwrap_or(false) + }) + .unwrap_or(false); + if !should_detach_tail { + return; + } + Some( + class_state + .grants + .pop() + .expect("tail grant must exist when shrinking local reserve"), + ) + }; + + let Some(grant) = detached else { + return; + }; + + if let Err(err) = inner.release_local_grant(grant.grant_id).await { + tracing::warn!( + "owner local reserve shrink failed to release grant_id={} err={}", + grant.grant_id, + err + ); + let mut pool = inner.owner_local_reserve_pool.lock(); + let class_state = pool.classes.entry(snapshot.slot_size).or_insert_with(|| { + OwnerLocalReserveClassState::new(snapshot.slot_size, snapshot.slots_per_grant) + }); + class_state.grants.push(grant); + } +} + +async fn owner_local_reserve_rebalance_once(view: &ClientKvApiView) { + let inner = view.client_kv_api().inner(); + let snapshots = { + let pool = inner.owner_local_reserve_pool.lock(); + snapshot_rebalance_classes(&pool) + }; + for snapshot in snapshots { + try_refill_once(inner, snapshot).await; + try_shrink_once(inner, snapshot).await; + } +} + +pub fn spawn_owner_local_reserve_rebalance_actor(view: ClientKvApiView) { + let view_task = view.clone(); + view.spawn("owner_local_reserve_rebalance_actor", async move { + let shutdown_poller = view_task.register_shutdown_poller(); + let mut shutdown_waiter = view_task.register_shutdown_waiter(); + let notify = view_task + .client_kv_api() + .inner() + .owner_local_reserve_rebalance_notify(); + let mut tick = tokio::time::interval(OWNER_LOCAL_RESERVE_REBALANCE_INTERVAL); + + loop { + tokio::select! { + biased; + _ = shutdown_waiter.wait() => { + tracing::info!("owner local reserve rebalance actor stopped by shutdown"); + return; + } + _ = tick.tick() => {} + _ = notify.notified() => {} + } + + if !shutdown_poller.is_running() { + tracing::info!("owner local reserve rebalance actor stopped by shutdown"); + return; + } + + owner_local_reserve_rebalance_once(&view_task).await; + } + }); +} + +pub async fn wait_owner_local_reserve_ready( + inner: &ClientKvApiInner, + slot_size: u64, + slots_per_grant: u32, + key_count: usize, + soft_wait_timeout: Duration, + hard_deadline: Instant, +) -> bool { + let notify = inner.owner_local_reserve_rebalance_notify(); + let mut shutdown_waiter = inner.view.register_shutdown_waiter(); + loop { + let notified = notify.notified(); + { + let mut pool = inner.owner_local_reserve_pool.lock(); + let class_state = pool + .classes + .entry(slot_size) + .or_insert_with(|| OwnerLocalReserveClassState::new(slot_size, slots_per_grant)); + if class_state.free_slot_count() >= key_count { + return true; + } + } + + let Some(remaining_hard) = hard_deadline.checked_duration_since(Instant::now()) else { + return false; + }; + let wait_budget = remaining_hard.min(soft_wait_timeout); + + tokio::select! { + _ = shutdown_waiter.wait() => return false, + _ = tokio::time::sleep(wait_budget) => { + inner.owner_local_reserve_rebalance_notify().notify_waiters(); + } + _ = notified => {} + } + } +} diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs index dec19f5..7f723f0 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs @@ -1,15 +1,25 @@ use crate::client_kv_api::delete::handle_batch_delete_client_kv_meta_cache; +use crate::client_kv_api::local_reserve_rebalance::spawn_owner_local_reserve_rebalance_actor; use crate::client_kv_api::msg_pack::{ - ExternalDeleteAckReq, ExternalDeleteAckResp, ExternalDeleteReq, ExternalDeleteResp, - ExternalGetReq, ExternalGetResp, ExternalIsExistReq, ExternalIsExistResp, ExternalPutCommitReq, - ExternalPutCommitResp, ExternalPutRevokeReq, ExternalPutRevokeResp, ExternalPutStartReq, - ExternalPutStartResp, ExternalPutTransferEndReq, ExternalPutTransferEndResp, SyncKvToFileReq, - SyncKvToFileResp, TestPutPhaseTrace, + ExternalBatchGetCancelReq, ExternalBatchGetCancelResp, ExternalBatchGetReq, + ExternalBatchGetResp, ExternalBatchGetStartReq, ExternalBatchGetStartResp, + ExternalBatchGetTransferReq, ExternalBatchGetTransferResp, ExternalBatchIsExistReq, + ExternalBatchIsExistResp, ExternalBatchPutCommitReq, ExternalBatchPutCommitResp, + ExternalBatchPutStartReq, ExternalBatchPutStartResp, ExternalBatchPutTransferEndReq, + ExternalBatchPutTransferEndResp, ExternalDeleteAckReq, ExternalDeleteAckResp, + ExternalDeleteReq, ExternalDeleteResp, ExternalGetReq, ExternalGetResp, ExternalIsExistReq, + ExternalIsExistResp, ExternalObservabilitySnapshotReq, ExternalObservabilitySnapshotResp, + ExternalPutCommitReq, ExternalPutCommitResp, ExternalPutRevokeReq, ExternalPutRevokeResp, + ExternalPutStartReq, ExternalPutStartResp, ExternalPutTransferEndReq, + ExternalPutTransferEndResp, SyncKvToFileReq, SyncKvToFileResp, TestPutPhaseTrace, }; -use crate::cluster_manager::NodeIDString; +use crate::cluster_manager::{NodeID, NodeIDString}; use crate::config::TestSpecConfig; use crate::master_kv_router::msg_pack::{ - BatchDeleteAckReq, BatchDeleteClientKvMetaCacheReq, DeleteClientKvMetaCacheItem, + BatchDeleteAckReq, BatchDeleteClientKvMetaCacheReq, BatchGetDoneReq, BatchGetRevokeReq, + BatchGetStartItemResp, BatchGetStartReq, BatchIsExistReq, BatchPreparePutKeysReq, + BatchPutDoneReq, BatchPutRevokeReq, BatchPutStartReq, BatchReleasePutKeyReservationsReq, + CountPrefixReq, DeleteClientKvMetaCacheItem, }; use crate::master_lease_manager::msg_pack::{AllocateClientLeaseReq, ClientLeaseKeepaliveReq}; use crate::memholder::{AllMemholderRefCount, MemoryInfo, UserMemHolder}; @@ -20,28 +30,37 @@ use crate::memholder::{ use crate::{ client_seg_pool::{ClientSegPool, ClientSegPoolAccessTrait, ResolveSideTransferLaneReq}, client_transfer_engine::{ClientTransferEngine, ClientTransferEngineAccessTrait}, - cluster_manager::{ClusterEvent, ClusterManager, ClusterManagerAccessTrait}, + cluster_manager::{ + app_logic_ext::{ClusterManagerAppLogicExt, ClusterManagerExtError}, + ClusterEvent, ClusterManager, ClusterManagerAccessTrait, + }, master_kv_router::msg_pack::{ - DeleteReq, GetDoneReq, GetMetaReq, GetRevokeReq, GetStartReq, PutDoneReq, PutRevokeReq, - PutStartReq, + DeleteAckReq, DeleteReq, GetDoneReq, GetMetaReq, GetRevokeReq, GetStartReq, + MemHolderKeepAliveReq, PutAppendDoneReq, PutAppendRevokeReq, PutAppendStartReq, PutDoneReq, + PutRevokeReq, PutStartReq, ReleaseLocalGrantReq, ReserveLocalGrantReq, }, metric_reporter::{MetricReporter, MetricReporterAccessTrait}, - metrics::{MetricsHandle, OperationKind, RequestStage}, + metrics::{KvLocalitySnapshot, MetricsHandle, OperationKind, RequestStage}, p2p::{ msg_pack::{RPCCaller, RPCHandler}, p2p_module::{P2pModule, P2pModuleAccessTrait}, }, - rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, KvResult}, + rpcresp_kvresult_convert::msg_and_error::{ApiError, ErrorCode, KvError, KvResult}, }; use async_trait::async_trait; +use crossbeam::queue::SegQueue; use dashmap::DashMap; -use fluxon_framework::{LogicalModule, define_module}; +use fluxon_framework::{define_module, LogicalModule}; +use fluxon_framework_compiled::upgrade_view_guard::UpgradeViewGuard; use fluxon_util::map_lock::AMapLock; use limit_thirdparty::tokio; -use parking_lot::Mutex; +use parking_lot::{Mutex, RwLock}; +use std::collections::HashMap; +use std::collections::HashSet; +use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Weak; use std::sync::{Arc, OnceLock}; -use std::time::Duration; +use std::time::{Duration, Instant}; use tracing::warn; /// Information about a memholder held by external client @@ -52,26 +71,107 @@ pub struct ExternalHoldingGetInfo { pub memory_info: Arc, // The actual memholder being held } +#[derive(Clone, Debug, Default)] +pub struct OwnerRuntimeObserveSnapshot { + pub external_get_holding_entries: u64, + pub external_get_holding_bytes: u64, + pub external_pending_put_entries: u64, +} + pub use get::RemoteGetInfo; +pub use put::OwnerReservedPutItem; pub mod external_api; +mod local_reserve_rebalance; pub use external_api::HandlerForExternalClient; pub type TestObservePutPhaseSink = Arc>>; +pub type ExternalGetStartTransferOutput = + Vec, Option)>>>; -#[derive(Debug, Clone)] -enum CachedValue { - MetadataOnly, - LocalReplica(Arc), +pub enum ExternalGetStartOwnerItem { + Local { + memory_info: Arc, + }, + Started { + key: String, + item: BatchGetStartItemResp, + }, } -impl CachedValue { - fn rank(&self) -> u8 { - match self { - Self::MetadataOnly => 0, - Self::LocalReplica(_) => 1, +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +pub struct ExternalGetStartDedupKey { + pub keys: Vec, + pub atomic_group_lens: Vec, + pub prefix_best_effort: bool, +} + +#[derive(Clone, Debug)] +pub struct ExternalGetStartPrefixResult { + pub raw_prefix_hit_len: usize, + pub transferable_len: usize, + pub first_miss_index: Option, + pub first_error_kind: Option, +} + +#[derive(Clone)] +pub enum ExternalGetStartSharedItemResult { + Hit { + memholder: Arc, + }, + Miss, + Error { + error_code: ErrorCode, + error_json: String, + }, +} + +pub enum ExternalGetStartSharedPhase { + Starting, + Running { + prefix: ExternalGetStartPrefixResult, + keys: Vec, + }, + Ready { + prefix: ExternalGetStartPrefixResult, + keys: Vec, + items: Vec, + }, + Failed { + error_code: ErrorCode, + error_json: String, + }, +} + +pub struct ExternalGetStartSharedState { + pub waiter_count: usize, + pub phase: ExternalGetStartSharedPhase, +} + +pub struct ExternalGetStartSharedOp { + pub dedup_key: ExternalGetStartDedupKey, + pub transfer_concurrency: usize, + pub state: Mutex, + pub notify: Arc, +} + +impl ExternalGetStartSharedOp { + pub fn new(dedup_key: ExternalGetStartDedupKey, transfer_concurrency: usize) -> Self { + Self { + dedup_key, + transfer_concurrency, + state: Mutex::new(ExternalGetStartSharedState { + waiter_count: 1, + phase: ExternalGetStartSharedPhase::Starting, + }), + notify: Arc::new(limit_thirdparty::tokio::sync::Notify::new()), } } } +pub struct ExternalGetStartEntry { + pub req_node_id: String, + pub shared_op: Arc, +} + /// Optional arguments for put operations #[derive(Clone, Debug)] pub enum PutOptionalArg { @@ -79,6 +179,10 @@ pub enum PutOptionalArg { LeaseId(u64), /// Ask the master to fail-fast when the same key already has an inflight put. RejectIfInflightSameKey, + /// Ask the master to fail-fast when the key already has a committed live replica. + RejectIfExistSameKey, + /// Keep the legacy synchronous remote-placement semantics. + WriteThrough, /// Prefer placing the target allocation on a kvclient within this sub_cluster. PreferredSubCluster(String), /// Hidden test-only side-channel for collecting per-put phase timings. @@ -98,6 +202,8 @@ impl PutOptionalArgs { self.0.iter().rev().find_map(|a| match a { PutOptionalArg::LeaseId(id) => Some(*id), PutOptionalArg::RejectIfInflightSameKey + | PutOptionalArg::RejectIfExistSameKey + | PutOptionalArg::WriteThrough | PutOptionalArg::PreferredSubCluster(_) | PutOptionalArg::TestObservePutPhases(_) => None, }) @@ -109,12 +215,26 @@ impl PutOptionalArgs { .any(|arg| matches!(arg, PutOptionalArg::RejectIfInflightSameKey)) } + pub fn reject_if_exist_same_key(&self) -> bool { + self.0 + .iter() + .any(|arg| matches!(arg, PutOptionalArg::RejectIfExistSameKey)) + } + + pub fn write_through(&self) -> bool { + self.0 + .iter() + .any(|arg| matches!(arg, PutOptionalArg::WriteThrough)) + } + /// Get the last provided preferred_sub_cluster if any. pub fn preferred_sub_cluster(&self) -> Option<&str> { self.0.iter().rev().find_map(|a| match a { PutOptionalArg::PreferredSubCluster(sc) => Some(sc.as_str()), PutOptionalArg::LeaseId(_) | PutOptionalArg::RejectIfInflightSameKey + | PutOptionalArg::RejectIfExistSameKey + | PutOptionalArg::WriteThrough | PutOptionalArg::TestObservePutPhases(_) => None, }) } @@ -124,6 +244,8 @@ impl PutOptionalArgs { PutOptionalArg::TestObservePutPhases(sink) => Some(sink.clone()), PutOptionalArg::LeaseId(_) | PutOptionalArg::RejectIfInflightSameKey + | PutOptionalArg::RejectIfExistSameKey + | PutOptionalArg::WriteThrough | PutOptionalArg::PreferredSubCluster(_) => None, }) } @@ -274,6 +396,7 @@ pub enum KvMetrics { transfer_poll_wait_us: i64, transfer_poll_iters: i64, transfer_used_fast_path: bool, + transfer_used_nixl: bool, transfer_local_noop: bool, transfer_remote_transfer: bool, }, @@ -343,6 +466,104 @@ async fn handle_external_get( } } +async fn handle_external_batch_get( + view: &ClientKvApiView, + msg: &MsgPack, +) -> MsgPack { + let req = msg.serialize_part.clone(); + let dbg_len = req.keys.len(); + let resp = view + .client_kv_api() + .external_batch_get(req) + .await + .unwrap_or_else(|e| { + tracing::error!( + "handle_external_batch_get error: {e}; batch_len={batch_len}", + batch_len = dbg_len + ); + let mut r: ExternalBatchGetResp = + crate::rpcresp_kvresult_convert::FromError::from_error(&e); + r.items = Vec::new(); + r + }); + MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + } +} + +async fn handle_external_batch_get_start( + view: &ClientKvApiView, + msg: &MsgPack, +) -> MsgPack { + let req = msg.serialize_part.clone(); + let dbg_len = req.keys.len(); + let resp = view + .client_kv_api() + .external_batch_get_start(req) + .await + .unwrap_or_else(|e| { + tracing::error!( + "handle_external_batch_get_start error: {e}; batch_len={batch_len}", + batch_len = dbg_len + ); + crate::rpcresp_kvresult_convert::FromError::from_error(&e) + }); + MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + } +} + +async fn handle_external_batch_get_transfer( + view: &ClientKvApiView, + msg: &MsgPack, +) -> MsgPack { + let req = msg.serialize_part.clone(); + let dbg_handle = req.handle; + let resp = view + .client_kv_api() + .external_batch_get_transfer(req) + .await + .unwrap_or_else(|e| { + tracing::error!( + "handle_external_batch_get_transfer error: {e}; handle={handle}", + handle = dbg_handle + ); + let mut r: ExternalBatchGetTransferResp = + crate::rpcresp_kvresult_convert::FromError::from_error(&e); + r.items = Vec::new(); + r + }); + MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + } +} + +async fn handle_external_batch_get_cancel( + view: &ClientKvApiView, + msg: &MsgPack, +) -> MsgPack { + let req = msg.serialize_part.clone(); + let dbg_handle = req.handle; + let resp = view + .client_kv_api() + .external_batch_get_cancel(req) + .await + .unwrap_or_else(|e| { + tracing::error!( + "handle_external_batch_get_cancel error: {e}; handle={handle}", + handle = dbg_handle + ); + crate::rpcresp_kvresult_convert::FromError::from_error(&e) + }); + MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + } +} + async fn handle_external_put_start( view: &ClientKvApiView, msg: &MsgPack, @@ -375,6 +596,33 @@ async fn handle_external_put_start( raw_bytes: Vec::new(), } } + +async fn handle_external_batch_put_start( + view: &ClientKvApiView, + msg: &MsgPack, +) -> MsgPack { + let req = msg.serialize_part.clone(); + let dbg_len = req.items.len(); + let resp = view + .client_kv_api() + .external_batch_put_start(req) + .await + .unwrap_or_else(|e| { + tracing::error!( + "handle_external_batch_put_start error: {e}; batch_len={batch_len}", + batch_len = dbg_len + ); + let mut r: ExternalBatchPutStartResp = + crate::rpcresp_kvresult_convert::FromError::from_error(&e); + r.items = Vec::new(); + r + }); + MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + } +} + async fn handle_external_put_transfer_end( view: &ClientKvApiView, msg: &MsgPack, @@ -401,6 +649,32 @@ async fn handle_external_put_transfer_end( } } +async fn handle_external_batch_put_transfer_end( + view: &ClientKvApiView, + msg: &MsgPack, +) -> MsgPack { + let req = msg.serialize_part.clone(); + let dbg_len = req.items.len(); + let resp = view + .client_kv_api() + .external_batch_put_transfer_end(req) + .await + .unwrap_or_else(|e| { + tracing::error!( + "handle_external_batch_put_transfer_end error: {e}; batch_len={batch_len}", + batch_len = dbg_len + ); + let mut r: ExternalBatchPutTransferEndResp = + crate::rpcresp_kvresult_convert::FromError::from_error(&e); + r.items = Vec::new(); + r + }); + MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + } +} + async fn handle_external_put_commit( view: &ClientKvApiView, msg: &MsgPack, @@ -426,6 +700,32 @@ async fn handle_external_put_commit( } } +async fn handle_external_batch_put_commit( + view: &ClientKvApiView, + msg: &MsgPack, +) -> MsgPack { + let req = msg.serialize_part.clone(); + let dbg_len = req.items.len(); + let resp = view + .client_kv_api() + .external_batch_put_commit(req) + .await + .unwrap_or_else(|e| { + tracing::error!( + "handle_external_batch_put_commit error: {e}; batch_len={batch_len}", + batch_len = dbg_len + ); + let mut r: ExternalBatchPutCommitResp = + crate::rpcresp_kvresult_convert::FromError::from_error(&e); + r.items = Vec::new(); + r + }); + MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + } +} + async fn handle_external_put_revoke( view: &ClientKvApiView, msg: &MsgPack, @@ -551,6 +851,51 @@ async fn handle_external_is_exist( } } +async fn handle_external_batch_is_exist( + view: &ClientKvApiView, + msg: &MsgPack, +) -> MsgPack { + let req = msg.serialize_part.clone(); + let dbg_len = req.keys.len(); + let resp = view + .client_kv_api() + .external_batch_is_exist(req) + .await + .unwrap_or_else(|e| { + tracing::error!( + "handle_external_batch_is_exist error: {e}; batch_len={batch_len}", + batch_len = dbg_len + ); + let mut r: ExternalBatchIsExistResp = + crate::rpcresp_kvresult_convert::FromError::from_error(&e); + r.exists_list = Vec::new(); + r + }); + MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + } +} + +async fn handle_external_observability_snapshot( + view: &ClientKvApiView, + msg: &MsgPack, +) -> MsgPack { + let req = msg.serialize_part.clone(); + let resp = view + .client_kv_api() + .external_observability_snapshot(req) + .await + .unwrap_or_else(|e| { + tracing::error!("handle_external_observability_snapshot error: {e}"); + crate::rpcresp_kvresult_convert::FromError::from_error(&e) + }); + MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + } +} + fn write_all_at(file: &std::fs::File, mut buf: &[u8], mut offset: u64) -> std::io::Result<()> { use std::io::{Error, ErrorKind}; use std::os::unix::fs::FileExt; @@ -737,7 +1082,38 @@ pub struct ClientKvApi(ClientKvApiInner); pub struct GetCachedInfo { put_time_ms: u64, put_version: u32, - value: CachedValue, + mem_holder: Arc, +} + +#[derive(Debug)] +pub struct PrecommitLocalVisibleInfo { + mem_holder: Arc, +} + +#[derive(Debug)] +pub(crate) struct LocalSnapshotInfo { + put_time_ms: u64, + put_version: u32, +} + +impl GetCachedInfo { + fn version_matches(&self, put_time_ms: u64, put_version: u32) -> bool { + if self.put_time_ms == put_time_ms { + self.put_version <= put_version + } else { + self.put_time_ms <= put_time_ms + } + } +} + +impl LocalSnapshotInfo { + fn version_matches(&self, put_time_ms: u64, put_version: u32) -> bool { + if self.put_time_ms == put_time_ms { + self.put_version <= put_version + } else { + self.put_time_ms <= put_time_ms + } + } } struct ClientKvApiViewHolder { @@ -782,6 +1158,16 @@ pub struct ClientKvApiInner { /// key -> value info on this node /// we can only remove value if it's put_time_ms and put_version match remote eviction command get_cached_info: DashMap, + /// key -> locally readable resident slot before backend put_start/put_done finishes. + precommit_local_visible_info: DashMap, + /// key -> local replica version remembered from local put/get durable-replica success. + /// This authority is positive-only: hit means "can answer exists=true immediately when + /// allow_local_snapshot is enabled"; miss does not imply non-existence. + local_snapshot_info: DashMap, + /// KvOwner-managed resident staging grants for hostless put_start. + owner_local_reserve_pool: Mutex, + /// Wake the background reserve actor after demand/free-slot changes. + owner_local_reserve_rebalance_notify: Arc, /// Shared delete actor input for owner -> external weak-index invalidation. pub external_invalidate_delete: EnsureMemholderMgmtDeleteHandle, @@ -792,6 +1178,9 @@ pub struct ClientKvApiInner { // record external_client get_holding info (owned, flattened manager) pub external_get_holding: OwnerExternalMemMgr, + pub external_get_start_registry: DashMap>, + pub external_get_start_by_key: DashMap>, + next_external_get_start_handle: AtomicU64, /// Weak handle to a shared refcount tracker for all UserMemHolder of this client. /// /// - A strong `Arc` is given to every `UserMemHolder` created by this client. @@ -804,109 +1193,567 @@ pub struct ClientKvApiInner { #[cfg(test)] test_record: crate::client_kv_api::client_test_record::ClientTestRecord, - rpc_caller_get_start: RPCCaller, - rpc_caller_get_revoke: RPCCaller, - rpc_caller_get_done: RPCCaller, - rpc_caller_put_start: RPCCaller, - rpc_caller_put_revoke: RPCCaller, - rpc_caller_put_done: RPCCaller, - rpc_caller_delete: RPCCaller, - rpc_caller_batch_delete_ack: RPCCaller, - rpc_caller_get_meta: RPCCaller, - _rpc_caller_allocate_client_lease: RPCCaller, - _rpc_caller_client_lease_keepalive: RPCCaller, - rpc_caller_external_put_commit: RPCCaller, - rpc_caller_external_put_revoke: RPCCaller, - rpc_caller_resolve_side_transfer_lane: RPCCaller, + rpc_caller_get_start: RPCCaller, + rpc_caller_get_revoke: RPCCaller, + rpc_caller_get_done: RPCCaller, + rpc_caller_batch_get_start: RPCCaller, + rpc_caller_batch_get_revoke: RPCCaller, + rpc_caller_batch_get_done: RPCCaller, + rpc_caller_put_start: RPCCaller, + rpc_caller_put_revoke: RPCCaller, + rpc_caller_put_done: RPCCaller, + rpc_caller_batch_put_start: RPCCaller, + rpc_caller_batch_put_revoke: RPCCaller, + rpc_caller_batch_put_done: RPCCaller, + rpc_caller_batch_prepare_put_keys: RPCCaller, + rpc_caller_batch_release_put_key_reservations: RPCCaller, + rpc_caller_put_append_start: RPCCaller, + rpc_caller_put_append_revoke: RPCCaller, + rpc_caller_put_append_done: RPCCaller, + rpc_caller_reserve_local_grant: RPCCaller, + rpc_caller_release_local_grant: RPCCaller, + rpc_caller_delete: RPCCaller, + rpc_caller_batch_delete_ack: RPCCaller, + rpc_caller_batch_is_exist: RPCCaller, + rpc_caller_get_meta: RPCCaller, + rpc_caller_allocate_client_lease: RPCCaller, + rpc_caller_client_lease_keepalive: RPCCaller, + rpc_caller_external_put_commit: RPCCaller, + rpc_caller_external_put_revoke: RPCCaller, + rpc_caller_resolve_side_transfer_lane: RPCCaller, + + /// Default lease id recorded for inspection/convenience, but NOT auto-applied. + /// Callers must explicitly pass `Some(lease_id)` to attach a put to a lease. + default_lease_id: parking_lot::RwLock>, + /// External put (remote target) pending context keyed by (key, put_time_ms, put_version). + /// 注意:put_id (time_ms,version) 在不同 key 上并不全局唯一,因此必须携带 key 作为索引的一部分,避免碰撞。 + /// 使用 moka::sync::SegmentedCache 并设置 30 分钟 TTL,避免异常路径未清理导致的泄漏;不设置容量上限,纯 TTL 控制。 + external_pending_puts: moka::sync::SegmentedCache<(String, u64, u32), ExternalPendingPutCtx>, + write_back_append_tx: tokio::sync::ampsc::Sender, + write_back_append_rx: Mutex>>, +} + +impl ClientKvApiInner { + fn view(&self) -> &ClientKvApiView { + &self.view + } + + pub(crate) fn release_local_reserve_route_for_memory_info(&self, memory_info: &MemoryInfo) { + let Some((slot_size, grant_id, slot_index)) = memory_info.local_reserve_resident_slot_ref() + else { + return; + }; + if let Err(err) = + self.owner_release_local_reserve_committed_slot_route(slot_size, grant_id, slot_index) + { + tracing::warn!( + "failed to release local reserve committed slot route: key={} slot_size={} grant_id={} slot_index={} err={}", + memory_info.key, + slot_size, + grant_id, + slot_index, + err + ); + } + } + + pub(crate) fn short_circuit_put_payload_path_enabled(&self) -> bool { + self.test_spec_config.short_circuit_put_payload_path + } + + pub(crate) fn skip_put_end_commit_enabled(&self) -> bool { + self.test_spec_config.skip_put_end_commit + } + + pub(crate) fn remember_local_snapshot( + &self, + key: &str, + put_id: crate::master_kv_router::put::PutIDForAKey, + ) { + self.local_snapshot_info.insert( + key.to_string(), + LocalSnapshotInfo { + put_time_ms: put_id.0, + put_version: put_id.1, + }, + ); + } + + pub(crate) fn has_local_snapshot(&self, key: &str) -> bool { + self.precommit_local_visible_info.contains_key(key) + || self.get_cached_info.contains_key(key) + || self.local_snapshot_info.contains_key(key) + } + + pub(crate) fn remove_local_snapshot_if( + &self, + key: &str, + put_time_ms: u64, + put_version: u32, + ) -> bool { + self.local_snapshot_info + .remove_if(key, |_, v| v.version_matches(put_time_ms, put_version)) + .is_some() + } + + pub(crate) fn local_visible_mem_holder(&self, key: &str) -> Option> { + if let Some(info) = self.precommit_local_visible_info.get(key) { + return Some(info.mem_holder.clone()); + } + self.get_cached_info + .get(key) + .map(|info| info.mem_holder.clone()) + } + + pub async fn build_local_reserve_resident_memory_info( + &self, + key: &str, + addr: u64, + len: u32, + slot_size: u64, + grant_id: u64, + slot_index: u32, + ) -> Arc { + let resident_owner_node_id: NodeID = self.view.cluster_manager().get_self_info().id.into(); + Arc::new( + MemoryInfo::new_local_reserve_resident( + addr, + len, + key.to_string(), + resident_owner_node_id, + self.view.clone(), + slot_size, + grant_id, + slot_index, + ) + .await, + ) + } + + pub async fn install_local_committed_memory_info( + &self, + key: &str, + put_id: crate::master_kv_router::put::PutIDForAKey, + offset: u64, + len: u32, + holder_id: u64, + ) -> KvResult<()> { + let master_node_id: NodeID = self.view.cluster_manager().get_self_info().id.into(); + let memory_info = Arc::new( + MemoryInfo::new( + offset, + len, + holder_id, + key.to_string(), + master_node_id, + self.view.clone(), + ) + .await, + ); + let replaced = self.get_cached_info.insert( + key.to_string(), + GetCachedInfo { + put_time_ms: put_id.0, + put_version: put_id.1, + mem_holder: memory_info, + }, + ); + if let Some(previous) = replaced { + self.release_local_reserve_route_for_memory_info(previous.mem_holder.as_ref()); + } + self.remember_local_snapshot(key, put_id); + Ok(()) + } + + pub fn install_precommit_local_visible_memory_info( + &self, + key: &str, + memory_info: Arc, + ) { + let (slot_size, grant_id, slot_index) = memory_info + .local_reserve_resident_slot_ref() + .expect("resident memory_info must carry local reserve slot ref"); + self.owner_mark_local_reserve_slot_pending_visible(slot_size, grant_id, slot_index) + .expect("marking local reserve slot pending visible must succeed"); + self.owner_retain_local_reserve_resident_slot_holder(slot_size, grant_id, slot_index) + .expect("retaining local reserve resident holder must succeed"); + let replaced = self.precommit_local_visible_info.insert( + key.to_string(), + PrecommitLocalVisibleInfo { + mem_holder: memory_info.clone(), + }, + ); + assert!( + replaced.is_none(), + "precommit local visible cache must not be replaced for the same key" + ); + } + + pub fn remove_precommit_local_reserve_resident_slot_if_same( + &self, + key: &str, + expected_mem_holder: &Arc, + ) -> bool { + self.precommit_local_visible_info + .remove_if(key, |_, info| { + Arc::ptr_eq(&info.mem_holder, expected_mem_holder) + }) + .is_some() + } + + pub fn promote_precommit_local_reserve_resident_slot_if_same( + &self, + key: &str, + put_id: crate::master_kv_router::put::PutIDForAKey, + memory_info: Arc, + ) -> KvResult<()> { + let is_same_pending = self + .precommit_local_visible_info + .get(key) + .map(|info| Arc::ptr_eq(&info.mem_holder, &memory_info)) + .unwrap_or(false); + if !is_same_pending { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "precommit local visible cache missing while promoting key={}", + key + ), + })); + } + let (slot_size, grant_id, slot_index) = memory_info + .local_reserve_resident_slot_ref() + .expect("resident memory_info must carry local reserve slot ref"); + self.owner_promote_local_reserve_pending_slot_to_committed( + slot_size, grant_id, slot_index, + )?; + let removed = self + .precommit_local_visible_info + .remove_if(key, |_, info| Arc::ptr_eq(&info.mem_holder, &memory_info)) + .is_some(); + if !removed { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "precommit local visible cache disappeared while promoting key={}", + key + ), + })); + } + let replaced = self.get_cached_info.insert( + key.to_string(), + GetCachedInfo { + put_time_ms: put_id.0, + put_version: put_id.1, + mem_holder: memory_info, + }, + ); + if let Some(previous) = replaced { + self.release_local_reserve_route_for_memory_info(previous.mem_holder.as_ref()); + } + self.remember_local_snapshot(key, put_id); + Ok(()) + } +} + +#[derive(Debug, Clone)] +pub struct ExternalPendingPutCtx { + pub peer_id: Option, + pub src_offset: u64, + pub target_base_addr: u64, + pub target_offset: u64, + pub len: u64, + pub preferred_sub_cluster: Option, +} + +#[derive(Clone)] +pub(crate) struct WriteBackAppendJob { + pub key: String, + pub put_id: crate::master_kv_router::put::PutIDForAKey, + pub holder: Arc, + pub preferred_sub_cluster: Option, +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub(crate) enum OwnerLocalReserveSlotState { + Free, + Prepared, + PendingLocalVisible { + holder_ref_count: u32, + }, + Committed { + route_live: bool, + holder_ref_count: u32, + }, +} + +#[derive(Debug, Clone)] +pub struct OwnerLocalReserveSlotRef { + pub grant_id: u64, + pub slot_index: u32, + pub ptr: u64, + pub base_addr: u64, +} + +#[derive(Debug, Clone)] +pub struct OwnerLocalReserveSlotLease { + pub value_len: u64, + pub slot_size: u64, + pub slots: Vec, +} + +impl OwnerLocalReserveSlotLease { + pub fn value_ptrs(&self) -> Vec { + self.slots.iter().map(|slot| slot.ptr).collect() + } +} + +#[derive(Debug, Clone)] +pub(crate) struct OwnerLocalReserveGrantState { + pub grant_id: u64, + pub base_addr: u64, + pub addr: u64, + pub len: u64, + pub slot_size: u64, + pub slot_count: u32, + pub slot_states: Vec, + pub free_slots: Vec, + pub fully_free_since: Option, +} + +impl OwnerLocalReserveGrantState { + pub fn new( + grant_id: u64, + base_addr: u64, + addr: u64, + len: u64, + slot_size: u64, + slot_count: u32, + ) -> Self { + let mut free_slots = Vec::with_capacity(slot_count as usize); + for slot_index in (0..slot_count).rev() { + free_slots.push(slot_index); + } + Self { + grant_id, + base_addr, + addr, + len, + slot_size, + slot_count, + slot_states: vec![OwnerLocalReserveSlotState::Free; slot_count as usize], + free_slots, + fully_free_since: Some(Instant::now()), + } + } + + pub fn claim_prepared_slot(&mut self) -> Option { + let slot_index = self.free_slots.pop()?; + let state = self + .slot_states + .get_mut(slot_index as usize) + .expect("slot state index out of range"); + assert!( + matches!(*state, OwnerLocalReserveSlotState::Free), + "claim_prepared_slot expects a free slot" + ); + *state = OwnerLocalReserveSlotState::Prepared; + self.fully_free_since = None; + Some(OwnerLocalReserveSlotRef { + grant_id: self.grant_id, + slot_index, + ptr: self.addr + self.slot_size * slot_index as u64, + base_addr: self.base_addr, + }) + } + + pub fn mark_prepared_slot_pending_visible(&mut self, slot_index: u32) { + let state = self + .slot_states + .get_mut(slot_index as usize) + .expect("slot state index out of range"); + assert!( + matches!(*state, OwnerLocalReserveSlotState::Prepared), + "mark_prepared_slot_pending_visible expects a prepared slot" + ); + *state = OwnerLocalReserveSlotState::PendingLocalVisible { + holder_ref_count: 0, + }; + self.fully_free_since = None; + } + + pub fn promote_pending_visible_slot_to_committed(&mut self, slot_index: u32) { + let state = self + .slot_states + .get_mut(slot_index as usize) + .expect("slot state index out of range"); + let holder_ref_count = match *state { + OwnerLocalReserveSlotState::PendingLocalVisible { holder_ref_count } => { + holder_ref_count + } + _ => { + unreachable!("promote_pending_visible_slot_to_committed expects a pending slot"); + } + }; + *state = OwnerLocalReserveSlotState::Committed { + route_live: true, + holder_ref_count, + }; + self.fully_free_since = None; + } - /// Default lease id recorded for inspection/convenience, but NOT auto-applied. - /// Callers must explicitly pass `Some(lease_id)` to attach a put to a lease. - default_lease_id: parking_lot::RwLock>, - /// External put (remote target) pending context keyed by (key, put_time_ms, put_version). - /// 注意:put_id (time_ms,version) 在不同 key 上并不全局唯一,因此必须携带 key 作为索引的一部分,避免碰撞。 - /// 使用 moka::sync::SegmentedCache 并设置 30 分钟 TTL,避免异常路径未清理导致的泄漏;不设置容量上限,纯 TTL 控制。 - external_pending_puts: moka::sync::SegmentedCache<(String, u64, u32), ExternalPendingPutCtx>, -} + pub fn release_prepared_slot(&mut self, slot_index: u32) { + let state = self + .slot_states + .get_mut(slot_index as usize) + .expect("slot state index out of range"); + assert!( + matches!(*state, OwnerLocalReserveSlotState::Prepared), + "release_prepared_slot expects a prepared slot" + ); + *state = OwnerLocalReserveSlotState::Free; + self.free_slots.push(slot_index); + if self.is_fully_free() { + self.fully_free_since = Some(Instant::now()); + } + } -impl ClientKvApiInner { - fn should_replace_cached_info( - current: &GetCachedInfo, - put_time_ms: u64, - put_version: u32, - new_value_rank: u8, - ) -> bool { - if current.put_time_ms != put_time_ms { - return current.put_time_ms <= put_time_ms; + pub fn retain_resident_slot_holder(&mut self, slot_index: u32) { + let state = self + .slot_states + .get_mut(slot_index as usize) + .expect("slot state index out of range"); + match state { + OwnerLocalReserveSlotState::PendingLocalVisible { holder_ref_count } + | OwnerLocalReserveSlotState::Committed { + holder_ref_count, .. + } => { + *holder_ref_count = holder_ref_count + .checked_add(1) + .expect("retain_resident_slot_holder overflow"); + } + _ => { + unreachable!("retain_resident_slot_holder expects a resident slot"); + } } - if current.put_version != put_version { - return current.put_version <= put_version; + } + + pub fn release_resident_slot_holder(&mut self, slot_index: u32) { + let state = self + .slot_states + .get_mut(slot_index as usize) + .expect("slot state index out of range"); + match state { + OwnerLocalReserveSlotState::PendingLocalVisible { holder_ref_count } => { + assert!( + *holder_ref_count > 0, + "release_resident_slot_holder expects holder_ref_count > 0" + ); + *holder_ref_count -= 1; + if *holder_ref_count == 0 { + *state = OwnerLocalReserveSlotState::Free; + self.free_slots.push(slot_index); + if self.is_fully_free() { + self.fully_free_since = Some(Instant::now()); + } + } + } + OwnerLocalReserveSlotState::Committed { + route_live, + holder_ref_count, + } => { + *holder_ref_count = holder_ref_count + .checked_sub(1) + .expect("release_resident_slot_holder expects holder_ref_count > 0"); + if !*route_live && *holder_ref_count == 0 { + *state = OwnerLocalReserveSlotState::Free; + self.free_slots.push(slot_index); + if self.is_fully_free() { + self.fully_free_since = Some(Instant::now()); + } + } + } + _ => { + unreachable!("release_resident_slot_holder expects a resident slot"); + } } - current.value.rank() < new_value_rank - } - - fn upsert_cached_info(&self, key: &str, candidate: GetCachedInfo) { - match self.get_cached_info.entry(key.to_string()) { - dashmap::mapref::entry::Entry::Occupied(mut entry) => { - if Self::should_replace_cached_info( - entry.get(), - candidate.put_time_ms, - candidate.put_version, - candidate.value.rank(), - ) { - entry.insert(candidate); + } + + pub fn release_committed_slot_route(&mut self, slot_index: u32) { + let state = self + .slot_states + .get_mut(slot_index as usize) + .expect("slot state index out of range"); + match state { + OwnerLocalReserveSlotState::Committed { + route_live, + holder_ref_count, + } => { + assert!( + *route_live, + "release_committed_slot_route expects a live route" + ); + *route_live = false; + if *holder_ref_count == 0 { + *state = OwnerLocalReserveSlotState::Free; + self.free_slots.push(slot_index); + if self.is_fully_free() { + self.fully_free_since = Some(Instant::now()); + } } } - dashmap::mapref::entry::Entry::Vacant(entry) => { - entry.insert(candidate); + _ => { + unreachable!("release_committed_slot_route expects a committed slot"); } } } - pub(crate) fn cache_metadata_only_after_put( - &self, - key: &str, - put_id: crate::master_kv_router::put::PutIDForAKey, - ) { - self.upsert_cached_info( - key, - GetCachedInfo { - put_time_ms: put_id.0, - put_version: put_id.1, - value: CachedValue::MetadataOnly, - }, - ); + pub fn is_fully_free(&self) -> bool { + self.free_slots.len() == self.slot_count as usize } - pub(crate) fn cache_local_replica_after_get( - &self, - key: &str, - put_id: crate::master_kv_router::put::PutIDForAKey, - memory_info: Arc, - ) { - self.upsert_cached_info( - key, - GetCachedInfo { - put_time_ms: put_id.0, - put_version: put_id.1, - value: CachedValue::LocalReplica(memory_info), - }, - ); + pub fn used_slot_count(&self) -> usize { + self.slot_count as usize - self.free_slots.len() } +} - pub(crate) fn short_circuit_put_payload_path_enabled(&self) -> bool { - self.test_spec_config.short_circuit_put_payload_path +#[derive(Debug, Clone)] +pub(crate) struct OwnerLocalReserveClassState { + pub slot_size: u64, + pub slots_per_grant: u32, + pub grants: Vec, + pub last_grow_at: Option, + pub pending_slot_demand: usize, +} + +impl OwnerLocalReserveClassState { + pub fn new(slot_size: u64, slots_per_grant: u32) -> Self { + Self { + slot_size, + slots_per_grant, + grants: Vec::new(), + last_grow_at: None, + pending_slot_demand: 0, + } } - pub(crate) fn skip_put_end_commit_enabled(&self) -> bool { - self.test_spec_config.skip_put_end_commit + pub fn free_slot_count(&self) -> usize { + self.grants.iter().map(|grant| grant.free_slots.len()).sum() + } + + pub fn used_slot_count(&self) -> usize { + self.grants + .iter() + .map(|grant| grant.used_slot_count()) + .sum() + } + + pub fn grant_count(&self) -> usize { + self.grants.len() } } -#[derive(Debug, Clone)] -pub struct ExternalPendingPutCtx { - pub peer_id: NodeIDString, - pub target_base_addr: u64, - pub target_offset: u64, +#[derive(Debug, Default)] +pub(crate) struct OwnerLocalReservePoolState { + pub classes: HashMap, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] @@ -1071,12 +1918,46 @@ impl MetricsSet { } } +fn format_metrics_snapshot_prometheus( + client_id: &str, + timestamp_ms: i64, + metrics: &std::collections::HashMap, +) -> String { + let mut result = String::new(); + + for (metric_name, metric_set) in metrics { + result.push_str(&metric_set.to_prometheus_format(metric_name, client_id)); + result.push_str(&metric_set.to_prometheus_timeline_format(client_id)); + } + + result.push_str(&format!( + "kvcache_metrics_report_timestamp{{client=\"{}\"}} {}\n", + client_id, timestamp_ms + )); + + result +} + impl ClientKvApiInner { pub fn get_holding_len(&self) -> usize { self.external_get_holding.total() } + + pub fn runtime_observe_snapshot(&self) -> OwnerRuntimeObserveSnapshot { + let mut external_get_holding_bytes = 0u64; + for entry in self.external_get_holding.inner().iter() { + external_get_holding_bytes = + external_get_holding_bytes.saturating_add(entry.value().memory_info.len as u64); + } + OwnerRuntimeObserveSnapshot { + external_get_holding_entries: self.external_get_holding.total() as u64, + external_get_holding_bytes, + external_pending_put_entries: self.external_pending_puts.entry_count(), + } + } + pub fn get_cache_len(&self) -> usize { - self.get_cached_info.len() + self.precommit_local_visible_info.len() + self.get_cached_info.len() } fn metrics_handle(&self) -> Arc { self.metrics @@ -1085,6 +1966,15 @@ impl ClientKvApiInner { .expect("metrics handle not initialized") } + pub fn locality_snapshot(&self) -> KvLocalitySnapshot { + self.metrics_handle().get_locality_snapshot() + } + + pub fn record_put_locality(&self, remote: bool, bytes: u64, transfer_us: i64) { + self.metrics_handle() + .record_put_io_locality(remote, bytes, transfer_us); + } + fn client_id_str(&self) -> String { self.view.cluster_manager().get_self_info().id.to_string() } @@ -1506,18 +2396,84 @@ impl ClientKvApiInner { new_ref } + + pub(crate) fn owner_local_reserve_rebalance_notify( + &self, + ) -> Arc { + self.owner_local_reserve_rebalance_notify.clone() + } + + pub(crate) fn owner_local_reserve_register_pending_demand( + &self, + slot_size: u64, + slots_per_grant: u32, + demand_slots: usize, + ) { + let mut pool = self.owner_local_reserve_pool.lock(); + let class_state = pool + .classes + .entry(slot_size) + .or_insert_with(|| OwnerLocalReserveClassState::new(slot_size, slots_per_grant)); + class_state.pending_slot_demand = + class_state.pending_slot_demand.saturating_add(demand_slots); + } + + pub(crate) fn owner_local_reserve_consume_pending_demand( + &self, + slot_size: u64, + slots_per_grant: u32, + demand_slots: usize, + ) { + let mut pool = self.owner_local_reserve_pool.lock(); + let class_state = pool + .classes + .entry(slot_size) + .or_insert_with(|| OwnerLocalReserveClassState::new(slot_size, slots_per_grant)); + class_state.pending_slot_demand = + class_state.pending_slot_demand.saturating_sub(demand_slots); + } } impl ClientKvApi { pub fn inner(&self) -> &ClientKvApiInner { &self.0 } + fn spawn_runtime_observe_reporter(&self) { + let view = self.0.view.clone_view(); + let view_task = view.clone(); + view.spawn("client_runtime_observe_reporter", async move { + let mut interval = tokio::time::interval(Duration::from_secs(30)); + let mut shutdown_waiter = view_task.register_shutdown_waiter(); + loop { + tokio::select! { + _ = shutdown_waiter.wait() => break, + _ = interval.tick() => { + let snapshot = view_task.client_kv_api().inner().runtime_observe_snapshot(); + let metrics = view_task.metric_reporter().metrics(); + metrics.set_kv_holding_entries( + "owner_external_get_holding", + snapshot.external_get_holding_entries, + ); + metrics.set_kv_holding_bytes( + "owner_external_get_holding", + snapshot.external_get_holding_bytes, + ); + metrics.set_kv_external_pending_put_entries( + snapshot.external_pending_put_entries, + ); + } + } + } + }); + } + pub fn attach_view(&self, view: ClientKvApiView) { self.0.view.attach(view); } pub async fn construct(arg: ClientKvApiNewArg) -> Result { tracing::info!("Constructing ClientKvApi in Client mode (PreView)"); + let (write_back_append_tx, write_back_append_rx) = tokio::sync::ampsc::channel(1024); let inner = ClientKvApiInner { view: ClientKvApiViewHolder::new(), @@ -1526,6 +2482,12 @@ impl ClientKvApi { all_memholder_refcount: OnceLock::new(), get_remote_kv_lock: AMapLock::new(Duration::from_secs(60)), get_cached_info: DashMap::new(), + precommit_local_visible_info: DashMap::new(), + local_snapshot_info: DashMap::new(), + owner_local_reserve_pool: Mutex::new(OwnerLocalReservePoolState::default()), + owner_local_reserve_rebalance_notify: Arc::new( + limit_thirdparty::tokio::sync::Notify::new(), + ), external_invalidate_delete: EnsureMemholderMgmtDeleteHandle::new( OwnerExternalMemMgr::DELETE_SUBMIT_QUEUE_CAPACITY, ), @@ -1534,6 +2496,9 @@ impl ClientKvApi { ), owner_delete_ack_mgr: OwnerDeleteAckMemMgr::default(), external_get_holding: OwnerExternalMemMgr::default(), + external_get_start_registry: DashMap::new(), + external_get_start_by_key: DashMap::new(), + next_external_get_start_handle: AtomicU64::new(1), external_pending_puts: moka::sync::Cache::builder() .time_to_live(Duration::from_secs(30 * 60)) .segments(16) @@ -1543,18 +2508,34 @@ impl ClientKvApi { rpc_caller_get_start: RPCCaller::new(), rpc_caller_get_revoke: RPCCaller::new(), rpc_caller_get_done: RPCCaller::new(), + rpc_caller_batch_get_start: RPCCaller::new(), + rpc_caller_batch_get_revoke: RPCCaller::new(), + rpc_caller_batch_get_done: RPCCaller::new(), rpc_caller_put_start: RPCCaller::new(), rpc_caller_put_revoke: RPCCaller::new(), rpc_caller_put_done: RPCCaller::new(), + rpc_caller_batch_put_start: RPCCaller::new(), + rpc_caller_batch_put_revoke: RPCCaller::new(), + rpc_caller_batch_put_done: RPCCaller::new(), + rpc_caller_batch_prepare_put_keys: RPCCaller::new(), + rpc_caller_batch_release_put_key_reservations: RPCCaller::new(), + rpc_caller_put_append_start: RPCCaller::new(), + rpc_caller_put_append_revoke: RPCCaller::new(), + rpc_caller_put_append_done: RPCCaller::new(), + rpc_caller_reserve_local_grant: RPCCaller::new(), + rpc_caller_release_local_grant: RPCCaller::new(), rpc_caller_delete: RPCCaller::new(), rpc_caller_batch_delete_ack: RPCCaller::new(), + rpc_caller_batch_is_exist: RPCCaller::new(), rpc_caller_get_meta: RPCCaller::new(), - _rpc_caller_allocate_client_lease: RPCCaller::new(), - _rpc_caller_client_lease_keepalive: RPCCaller::new(), + rpc_caller_allocate_client_lease: RPCCaller::new(), + rpc_caller_client_lease_keepalive: RPCCaller::new(), rpc_caller_external_put_commit: RPCCaller::new(), rpc_caller_external_put_revoke: RPCCaller::new(), rpc_caller_resolve_side_transfer_lane: RPCCaller::new(), default_lease_id: parking_lot::RwLock::new(None), + write_back_append_tx, + write_back_append_rx: Mutex::new(Some(write_back_append_rx)), }; Ok(Self(inner)) } @@ -1570,13 +2551,55 @@ impl ClientKvApi { inner.rpc_caller_get_start.regist(inner.view.p2p_module()); inner.rpc_caller_get_revoke.regist(inner.view.p2p_module()); inner.rpc_caller_get_done.regist(inner.view.p2p_module()); + inner + .rpc_caller_batch_get_start + .regist(inner.view.p2p_module()); + inner + .rpc_caller_batch_get_revoke + .regist(inner.view.p2p_module()); + inner + .rpc_caller_batch_get_done + .regist(inner.view.p2p_module()); inner.rpc_caller_put_start.regist(inner.view.p2p_module()); inner.rpc_caller_put_revoke.regist(inner.view.p2p_module()); inner.rpc_caller_put_done.regist(inner.view.p2p_module()); + inner + .rpc_caller_batch_put_start + .regist(inner.view.p2p_module()); + inner + .rpc_caller_batch_put_revoke + .regist(inner.view.p2p_module()); + inner + .rpc_caller_batch_put_done + .regist(inner.view.p2p_module()); + inner + .rpc_caller_batch_prepare_put_keys + .regist(inner.view.p2p_module()); + inner + .rpc_caller_batch_release_put_key_reservations + .regist(inner.view.p2p_module()); + inner + .rpc_caller_put_append_start + .regist(inner.view.p2p_module()); + inner + .rpc_caller_put_append_revoke + .regist(inner.view.p2p_module()); + inner + .rpc_caller_put_append_done + .regist(inner.view.p2p_module()); + inner + .rpc_caller_reserve_local_grant + .regist(inner.view.p2p_module()); + inner + .rpc_caller_release_local_grant + .regist(inner.view.p2p_module()); inner.rpc_caller_delete.regist(inner.view.p2p_module()); inner .rpc_caller_batch_delete_ack .regist(inner.view.p2p_module()); + inner + .rpc_caller_batch_is_exist + .regist(inner.view.p2p_module()); inner.rpc_caller_get_meta.regist(inner.view.p2p_module()); inner .rpc_caller_external_put_commit @@ -1592,25 +2615,84 @@ impl ClientKvApi { // Register master-only metric RPC callers crate::metrics::client::init_for_p2p_owner(inner.view.p2p_module()); RPCCaller::::new().regist(inner.view.p2p_module()); + RPCCaller::::new().regist(inner.view.p2p_module()); RPCCaller::::new().regist(inner.view.p2p_module()); + spawn_owner_local_reserve_rebalance_actor(inner.view.clone_view()); + self.spawn_runtime_observe_reporter(); // External RPC handlers let view_ext = inner.view.clone_view(); RPCHandler::::new().regist(inner.view.p2p_module(), move |resp, msg| { let view = view_ext.clone(); let view_task = view.clone(); - let _ = view.spawn("rpc_external_get", async move { + view.spawn("rpc_external_get", async move { let result = handle_external_get(&view_task, &msg).await; let _ = resp.send_resp(result).await; }); Ok(()) }); + let view_ext = inner.view.clone_view(); + RPCHandler::::new().regist( + inner.view.p2p_module(), + move |resp, msg| { + let view = view_ext.clone(); + let view_task = view.clone(); + view.spawn("rpc_external_batch_get", async move { + let result = handle_external_batch_get(&view_task, &msg).await; + let _ = resp.send_resp(result).await; + }); + Ok(()) + }, + ); + + let view_ext = inner.view.clone_view(); + RPCHandler::::new().regist( + inner.view.p2p_module(), + move |resp, msg| { + let view = view_ext.clone(); + let view_task = view.clone(); + view.spawn("rpc_external_batch_get_start", async move { + let result = handle_external_batch_get_start(&view_task, &msg).await; + let _ = resp.send_resp(result).await; + }); + Ok(()) + }, + ); + + let view_ext = inner.view.clone_view(); + RPCHandler::::new().regist( + inner.view.p2p_module(), + move |resp, msg| { + let view = view_ext.clone(); + let view_task = view.clone(); + view.spawn("rpc_external_batch_get_transfer", async move { + let result = handle_external_batch_get_transfer(&view_task, &msg).await; + let _ = resp.send_resp(result).await; + }); + Ok(()) + }, + ); + + let view_ext = inner.view.clone_view(); + RPCHandler::::new().regist( + inner.view.p2p_module(), + move |resp, msg| { + let view = view_ext.clone(); + let view_task = view.clone(); + view.spawn("rpc_external_batch_get_cancel", async move { + let result = handle_external_batch_get_cancel(&view_task, &msg).await; + let _ = resp.send_resp(result).await; + }); + Ok(()) + }, + ); + let view_ext = inner.view.clone_view(); RPCHandler::::new().regist(inner.view.p2p_module(), move |resp, msg| { let view = view_ext.clone(); let view_task = view.clone(); - let _ = view.spawn("rpc_external_put_start", async move { + view.spawn("rpc_external_put_start", async move { let req = msg.serialize_part.clone(); tracing::info!( "rpc_external_put_start received: self={} peer={} task_id={} key={} len={} started_time={}", @@ -1644,13 +2726,27 @@ impl ClientKvApi { Ok(()) }); + let view_ext = inner.view.clone_view(); + RPCHandler::::new().regist( + inner.view.p2p_module(), + move |resp, msg| { + let view = view_ext.clone(); + let view_task = view.clone(); + view.spawn("rpc_external_batch_put_start", async move { + let result = handle_external_batch_put_start(&view_task, &msg).await; + let _ = resp.send_resp(result).await; + }); + Ok(()) + }, + ); + let view_ext = inner.view.clone_view(); RPCHandler::::new().regist( inner.view.p2p_module(), move |resp, msg| { let view = view_ext.clone(); let view_task = view.clone(); - let _ = view.spawn("rpc_external_put_transfer_end", async move { + view.spawn("rpc_external_put_transfer_end", async move { let result = handle_external_put_transfer_end(&view_task, &msg).await; let _ = resp.send_resp(result).await; }); @@ -1658,13 +2754,27 @@ impl ClientKvApi { }, ); + let view_ext = inner.view.clone_view(); + RPCHandler::::new().regist( + inner.view.p2p_module(), + move |resp, msg| { + let view = view_ext.clone(); + let view_task = view.clone(); + view.spawn("rpc_external_batch_put_transfer_end", async move { + let result = handle_external_batch_put_transfer_end(&view_task, &msg).await; + let _ = resp.send_resp(result).await; + }); + Ok(()) + }, + ); + let view_ext = inner.view.clone_view(); RPCHandler::::new().regist( inner.view.p2p_module(), move |resp, msg| { let view = view_ext.clone(); let view_task = view.clone(); - let _ = view.spawn("rpc_external_put_commit", async move { + view.spawn("rpc_external_put_commit", async move { let result = handle_external_put_commit(&view_task, &msg).await; let _ = resp.send_resp(result).await; }); @@ -1672,13 +2782,27 @@ impl ClientKvApi { }, ); + let view_ext = inner.view.clone_view(); + RPCHandler::::new().regist( + inner.view.p2p_module(), + move |resp, msg| { + let view = view_ext.clone(); + let view_task = view.clone(); + view.spawn("rpc_external_batch_put_commit", async move { + let result = handle_external_batch_put_commit(&view_task, &msg).await; + let _ = resp.send_resp(result).await; + }); + Ok(()) + }, + ); + let view_ext = inner.view.clone_view(); RPCHandler::::new().regist( inner.view.p2p_module(), move |resp, msg| { let view = view_ext.clone(); let view_task = view.clone(); - let _ = view.spawn("rpc_external_put_revoke", async move { + view.spawn("rpc_external_put_revoke", async move { let result = handle_external_put_revoke(&view_task, &msg).await; let _ = resp.send_resp(result).await; }); @@ -1690,7 +2814,7 @@ impl ClientKvApi { RPCHandler::::new().regist(inner.view.p2p_module(), move |resp, msg| { let view = view_ext.clone(); let view_task = view.clone(); - let _ = view.spawn("rpc_external_delete", async move { + view.spawn("rpc_external_delete", async move { let result = handle_external_delete(&view_task, &msg).await; let _ = resp.send_resp(result).await; }); @@ -1703,7 +2827,7 @@ impl ClientKvApi { move |resp, msg| { let view = view_ext.clone(); let view_task = view.clone(); - let _ = view.spawn("rpc_external_is_exist", async move { + view.spawn("rpc_external_is_exist", async move { let result = handle_external_is_exist(&view_task, &msg).await; let _ = resp.send_resp(result).await; }); @@ -1711,13 +2835,41 @@ impl ClientKvApi { }, ); + let view_ext = inner.view.clone_view(); + RPCHandler::::new().regist( + inner.view.p2p_module(), + move |resp, msg| { + let view = view_ext.clone(); + let view_task = view.clone(); + view.spawn("rpc_external_batch_is_exist", async move { + let result = handle_external_batch_is_exist(&view_task, &msg).await; + let _ = resp.send_resp(result).await; + }); + Ok(()) + }, + ); + + let view_ext = inner.view.clone_view(); + RPCHandler::::new().regist( + inner.view.p2p_module(), + move |resp, msg| { + let view = view_ext.clone(); + let view_task = view.clone(); + view.spawn("rpc_external_observability_snapshot", async move { + let result = handle_external_observability_snapshot(&view_task, &msg).await; + let _ = resp.send_resp(result).await; + }); + Ok(()) + }, + ); + let view_ext = inner.view.clone_view(); RPCHandler::::new().regist( inner.view.p2p_module(), move |resp, msg| { let view = view_ext.clone(); let view_task = view.clone(); - let _ = view.spawn("rpc_external_delete_ack", async move { + view.spawn("rpc_external_delete_ack", async move { let result = handle_external_delete_ack(&view_task, &msg).await; let _ = resp.send_resp(result).await; }); @@ -1731,7 +2883,7 @@ impl ClientKvApi { RPCHandler::::new().regist(inner.view.p2p_module(), move |resp, msg| { let view = view_ext.clone(); let view_task = view.clone(); - let _ = view.spawn("rpc_sync_kv_to_file", async move { + view.spawn("rpc_sync_kv_to_file", async move { let result = handle_sync_kv_to_file_client(&view_task, &msg).await; let _ = resp.send_resp(result).await; }); @@ -1746,7 +2898,7 @@ impl ClientKvApi { let req_node_id = resp.node_id().clone(); let view = view.clone(); let view_task = view.clone(); - let _ = view.spawn("rpc_batch_delete_client_kv_meta_cache", async move { + view.spawn("rpc_batch_delete_client_kv_meta_cache", async move { let ack = handle_batch_delete_client_kv_meta_cache(&view_task, msg, req_node_id) .await; @@ -1773,11 +2925,17 @@ impl ClientKvApi { .expect("delete_ack_batch rx already taken, that's impossible"); delete::spawn_owner_delete_ack_batch(inner.view.clone_view(), delete_ack_batch_rx); + if let Some(write_back_append_rx) = inner.write_back_append_rx.lock().take() { + put::spawn_write_back_append_actor(inner.view.clone_view(), write_back_append_rx); + } else { + tracing::warn!("write_back_append_rx already taken for ClientKvApi"); + } + // Spawn cluster listener to clean up get_holding when external_client leaves let view = inner.view.clone_view(); let view2 = view.clone(); let view_task = view2.clone(); - let _ = view.spawn("client_cluster_listener", async move { + view.spawn("client_cluster_listener", async move { let mut listen_cluster_event = view_task.cluster_manager().listen(); let mut shutdown_waiter = view_task.register_shutdown_waiter(); @@ -1917,9 +3075,8 @@ impl ClientKvApi { tracing::info!("------------------------------------------------------------"); } - #[cfg(any(test, feature = "test_bins"))] pub fn has_cached_key(&self, key: &str) -> bool { - self.inner().get_cached_info.contains_key(key) + self.inner().has_local_snapshot(key) } // Removed is_client_mode(): ClientKvApi is owner-only and always constructed. diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs index 55f0970..c53c634 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs @@ -1,9 +1,9 @@ use crate::master_kv_router::put::PutIDForAKey; use crate::p2p::msg_pack::{MsgPackSerializePart, RPCReq}; -use crate::rpcresp_kvresult_convert::msg_and_error::ErrorCode; +use crate::rpcresp_kvresult_convert::msg_and_error::{ErrorCode, OK}; use bitcode::{Decode, Encode}; -use crate::memholder::ExternalMemHolderInfo; +use crate::memholder::{ExternalMemHolder, ExternalMemHolderInfo}; #[derive(Default, Debug, Clone, Encode, Decode)] pub struct TestPutPhaseTrace { @@ -89,6 +89,371 @@ impl MsgPackSerializePart for ExternalGetResp { } } +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchGetReq { + pub keys: Vec, + pub req_node_id: String, + /// Owner node_start_time observed by external when request starts + pub started_time: i64, + pub transfer_concurrency: usize, +} +impl MsgPackSerializePart for ExternalBatchGetReq { + fn msg_id(&self) -> u32 { + 4020 + } +} +impl RPCReq for ExternalBatchGetReq { + type Resp = ExternalBatchGetResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchGetItemResp { + pub error_code: ErrorCode, + pub error_json: String, + pub external_memholder_info: Option, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchGetResp { + pub items: Vec, + pub error_code: ErrorCode, + pub error_json: String, +} +impl MsgPackSerializePart for ExternalBatchGetResp { + fn msg_id(&self) -> u32 { + 4021 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchGetStartReq { + pub keys: Vec, + pub req_node_id: String, + /// Owner node_start_time observed by external when request starts + pub started_time: i64, + pub prefix_best_effort: bool, + pub atomic_group_lens: Option>, + pub transfer_concurrency: usize, +} +impl MsgPackSerializePart for ExternalBatchGetStartReq { + fn msg_id(&self) -> u32 { + 4030 + } +} +impl RPCReq for ExternalBatchGetStartReq { + type Resp = ExternalBatchGetStartResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchGetStartResp { + pub error_code: ErrorCode, + pub error_json: String, + pub handle: u64, + pub raw_prefix_hit_len: usize, +} +impl MsgPackSerializePart for ExternalBatchGetStartResp { + fn msg_id(&self) -> u32 { + 4031 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchGetTransferReq { + pub handle: u64, + pub req_node_id: String, + /// Owner node_start_time observed by external when request starts + pub started_time: i64, +} +impl MsgPackSerializePart for ExternalBatchGetTransferReq { + fn msg_id(&self) -> u32 { + 4032 + } +} +impl RPCReq for ExternalBatchGetTransferReq { + type Resp = ExternalBatchGetTransferResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchGetTransferResp { + pub items: Vec, + pub error_code: ErrorCode, + pub error_json: String, +} +impl MsgPackSerializePart for ExternalBatchGetTransferResp { + fn msg_id(&self) -> u32 { + 4033 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchGetCancelReq { + pub handle: u64, + pub req_node_id: String, + /// Owner node_start_time observed by external when request starts + pub started_time: i64, +} +impl MsgPackSerializePart for ExternalBatchGetCancelReq { + fn msg_id(&self) -> u32 { + 4034 + } +} +impl RPCReq for ExternalBatchGetCancelReq { + type Resp = ExternalBatchGetCancelResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchGetCancelResp { + pub error_code: ErrorCode, + pub error_json: String, +} +impl MsgPackSerializePart for ExternalBatchGetCancelResp { + fn msg_id(&self) -> u32 { + 4035 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchPutStartItemReq { + pub key: String, + pub len: u64, + pub reject_if_inflight_same_key: bool, + pub reject_if_exist_same_key: bool, + pub write_through: bool, + pub preferred_sub_cluster: Option, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchPutStartReq { + pub items: Vec, + /// Owner node_start_time observed by external when request starts + pub started_time: i64, +} +impl MsgPackSerializePart for ExternalBatchPutStartReq { + fn msg_id(&self) -> u32 { + 4022 + } +} +impl RPCReq for ExternalBatchPutStartReq { + type Resp = ExternalBatchPutStartResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchPutStartItemResp { + pub error_code: ErrorCode, + pub src_offset: u64, + pub target_offset: u64, + pub transfer_target_offset: Option, + pub peer_id: Option, + pub src_base_addr: u64, + pub target_base_addr: u64, + pub error_json: String, + pub put_id: Option, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchPutStartResp { + pub items: Vec, + pub error_code: ErrorCode, + pub error_json: String, +} +impl MsgPackSerializePart for ExternalBatchPutStartResp { + fn msg_id(&self) -> u32 { + 4023 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchPutTransferEndItemReq { + pub key: String, + pub len: u64, + pub src_offset: u64, + pub target_offset: u64, + pub peer_id: Option, + pub target_base_addr: Option, + pub put_id: Option, + pub write_through: bool, + pub lease_id: Option, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchPutTransferEndReq { + pub items: Vec, + /// Owner node_start_time observed by external when request starts + pub started_time: i64, + pub transfer_concurrency: usize, +} +impl MsgPackSerializePart for ExternalBatchPutTransferEndReq { + fn msg_id(&self) -> u32 { + 4024 + } +} +impl RPCReq for ExternalBatchPutTransferEndReq { + type Resp = ExternalBatchPutTransferEndResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchPutTransferEndItemResp { + pub error_code: ErrorCode, + pub error_json: String, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchPutTransferEndResp { + pub items: Vec, + pub error_code: ErrorCode, + pub error_json: String, +} +impl MsgPackSerializePart for ExternalBatchPutTransferEndResp { + fn msg_id(&self) -> u32 { + 4025 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchPutCommitItemReq { + pub key: String, + pub len: u64, + pub src_offset: u64, + pub remote_target: bool, + pub put_id: Option, + pub lease_id: Option, + pub write_through: bool, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchPutCommitReq { + pub items: Vec, + /// Owner node_start_time observed by the caller when request starts + pub started_time: i64, +} +impl MsgPackSerializePart for ExternalBatchPutCommitReq { + fn msg_id(&self) -> u32 { + 4026 + } +} +impl RPCReq for ExternalBatchPutCommitReq { + type Resp = ExternalBatchPutCommitResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchPutCommitItemResp { + pub error_code: ErrorCode, + pub error_json: String, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchPutCommitResp { + pub items: Vec, + pub error_code: ErrorCode, + pub error_json: String, +} +impl MsgPackSerializePart for ExternalBatchPutCommitResp { + fn msg_id(&self) -> u32 { + 4027 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalIoLocalitySnapshot { + pub op_count: u64, + pub bytes: u64, + pub transfer_us: u64, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalObservabilitySnapshotReq { + /// Owner node_start_time observed by external when request starts. + pub started_time: i64, +} +impl MsgPackSerializePart for ExternalObservabilitySnapshotReq { + fn msg_id(&self) -> u32 { + 4028 + } +} +impl RPCReq for ExternalObservabilitySnapshotReq { + type Resp = ExternalObservabilitySnapshotResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalObservabilitySnapshotResp { + pub error_code: ErrorCode, + pub error_json: String, + pub l2_local_hit_pages: u64, + pub l2_local_hit_bytes: u64, + pub l2_remote_hit_pages: u64, + pub l2_remote_hit_bytes: u64, + pub put_local: ExternalIoLocalitySnapshot, + pub put_remote: ExternalIoLocalitySnapshot, + pub get_local: ExternalIoLocalitySnapshot, + pub get_remote: ExternalIoLocalitySnapshot, +} +impl ExternalObservabilitySnapshotResp { + pub fn success(snapshot: crate::metrics::KvLocalitySnapshot) -> Self { + Self { + error_code: OK, + error_json: String::new(), + l2_local_hit_pages: snapshot.l2_local_hit_pages, + l2_local_hit_bytes: snapshot.l2_local_hit_bytes, + l2_remote_hit_pages: snapshot.l2_remote_hit_pages, + l2_remote_hit_bytes: snapshot.l2_remote_hit_bytes, + put_local: ExternalIoLocalitySnapshot { + op_count: snapshot.put_local.op_count, + bytes: snapshot.put_local.bytes, + transfer_us: snapshot.put_local.transfer_us, + }, + put_remote: ExternalIoLocalitySnapshot { + op_count: snapshot.put_remote.op_count, + bytes: snapshot.put_remote.bytes, + transfer_us: snapshot.put_remote.transfer_us, + }, + get_local: ExternalIoLocalitySnapshot { + op_count: snapshot.get_local.op_count, + bytes: snapshot.get_local.bytes, + transfer_us: snapshot.get_local.transfer_us, + }, + get_remote: ExternalIoLocalitySnapshot { + op_count: snapshot.get_remote.op_count, + bytes: snapshot.get_remote.bytes, + transfer_us: snapshot.get_remote.transfer_us, + }, + } + } + + pub fn into_snapshot(self) -> crate::metrics::KvLocalitySnapshot { + crate::metrics::KvLocalitySnapshot { + l2_local_hit_pages: self.l2_local_hit_pages, + l2_local_hit_bytes: self.l2_local_hit_bytes, + l2_remote_hit_pages: self.l2_remote_hit_pages, + l2_remote_hit_bytes: self.l2_remote_hit_bytes, + put_local: crate::metrics::KvIoLocalitySnapshot { + op_count: self.put_local.op_count, + bytes: self.put_local.bytes, + transfer_us: self.put_local.transfer_us, + }, + put_remote: crate::metrics::KvIoLocalitySnapshot { + op_count: self.put_remote.op_count, + bytes: self.put_remote.bytes, + transfer_us: self.put_remote.transfer_us, + }, + get_local: crate::metrics::KvIoLocalitySnapshot { + op_count: self.get_local.op_count, + bytes: self.get_local.bytes, + transfer_us: self.get_local.transfer_us, + }, + get_remote: crate::metrics::KvIoLocalitySnapshot { + op_count: self.get_remote.op_count, + bytes: self.get_remote.bytes, + transfer_us: self.get_remote.transfer_us, + }, + } + } +} +impl MsgPackSerializePart for ExternalObservabilitySnapshotResp { + fn msg_id(&self) -> u32 { + 4029 + } +} + // #[derive(Default, Debug, Clone, Encode, Decode)] // pub struct ExternalPutReq { // pub key: String, @@ -114,6 +479,8 @@ pub struct ExternalPutStartReq { pub key: String, pub len: u64, pub reject_if_inflight_same_key: bool, + pub reject_if_exist_same_key: bool, + pub write_through: bool, /// Prefer placing the target allocation on any kvclient within this sub_cluster. pub preferred_sub_cluster: Option, /// Owner node_start_time observed by external when request starts @@ -159,6 +526,7 @@ pub struct ExternalPutTransferEndReq { pub peer_id: Option, pub target_base_addr: Option, pub put_id: Option, + pub write_through: bool, /// Optional lease to attach this key to when committing pub lease_id: Option, /// Owner node_start_time observed by external when request starts @@ -190,8 +558,12 @@ impl MsgPackSerializePart for ExternalPutTransferEndResp { #[derive(Default, Debug, Clone, Encode, Decode)] pub struct ExternalPutCommitReq { pub key: String, + pub len: u64, + pub src_offset: u64, + pub remote_target: bool, pub put_id: Option, pub lease_id: Option, + pub write_through: bool, /// Owner node_start_time observed by the caller when request starts pub started_time: i64, pub test_observe_put_phases: bool, @@ -297,6 +669,34 @@ impl MsgPackSerializePart for ExternalIsExistResp { } } +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchIsExistReq { + pub keys: Vec, + pub allow_local_snapshot: bool, + /// Owner node_start_time observed by external when request starts + pub started_time: i64, +} +impl MsgPackSerializePart for ExternalBatchIsExistReq { + fn msg_id(&self) -> u32 { + crate::rpcresp_kvresult_convert::msg_and_error::MsgId::ExternalBatchIsExistReq as u32 + } +} +impl RPCReq for ExternalBatchIsExistReq { + type Resp = ExternalBatchIsExistResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchIsExistResp { + pub error_code: ErrorCode, + pub exists_list: Vec, + pub error_json: String, +} +impl MsgPackSerializePart for ExternalBatchIsExistResp { + fn msg_id(&self) -> u32 { + crate::rpcresp_kvresult_convert::msg_and_error::MsgId::ExternalBatchIsExistResp as u32 + } +} + #[derive(Default, Debug, Clone, Encode, Decode)] pub struct ExternalDeleteAckReq { pub key: String, @@ -326,10 +726,17 @@ impl MsgPackSerializePart for ExternalDeleteAckResp { } // --- RPC: Owner -> External to invalidate weak-index cache for keys --- +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalInvalidateWeakIndexItem { + pub key: String, +} + #[derive(Default, Debug, Clone, Encode, Decode)] pub struct ExternalInvalidateWeakIndexReq { - /// Keys whose weak cache entries should be invalidated on external client + /// Keys whose weak cache entries should be invalidated on external client. + /// Kept for compatibility with older senders; new senders should use `items`. pub keys: Vec, + pub items: Vec, } impl MsgPackSerializePart for ExternalInvalidateWeakIndexReq { fn msg_id(&self) -> u32 { diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs index 374ed71..225decf 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs @@ -1,7 +1,12 @@ -use super::ClientKvApiInner; -use crate::cluster_manager::NodeIDString; +use super::{ + local_reserve_rebalance::{owner_local_reserve_timeout_config, wait_owner_local_reserve_ready}, + ClientKvApiInner, OwnerLocalReserveClassState, OwnerLocalReserveGrantState, + OwnerLocalReservePoolState, OwnerLocalReserveSlotLease, WriteBackAppendJob, +}; use crate::cluster_manager::app_logic_ext::ClusterManagerAppLogicExt; +use crate::cluster_manager::NodeIDString; use crate::master_kv_router::put::PutIDForAKey; +use crate::OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES; // no StageScope; timestamps-based metrics only use crate::memholder::kvclient_encode::{calc_flat_dict_encoded_len, write_flat_dict_ptrs_to_ptr}; use crate::observe_kvope::{ @@ -9,12 +14,24 @@ use crate::observe_kvope::{ obe_put_transfer_error, }; use crate::{ - master_kv_router::msg_pack::{PutDoneReq, PutRevokeReq, PutStartReq, PutStartResp}, + client_kv_api::ClientKvApiView, + master_kv_router::msg_pack::{ + BatchPreparePutKeyItemReq, BatchPreparePutKeysReq, BatchPreparePutKeysResp, + BatchPutDoneItemReq, BatchPutDoneReq, BatchPutDoneResp, BatchPutRevokeItemReq, + BatchPutRevokeReq, BatchPutRevokeResp, BatchPutStartItemReq, BatchPutStartReq, + BatchPutStartResp, BatchReleasePutKeyReservationsReq, BatchReleasePutKeyReservationsResp, + PutAppendDoneReq, PutAppendDoneResp, PutAppendRevokeReq, PutAppendStartReq, + PutAppendStartResp, PutDoneReq, PutRevokeReq, PutStartReq, PutStartResp, + ReleaseLocalGrantReq, ReserveLocalGrantReq, ReserveLocalGrantResp, + }, p2p::msg_pack::MsgPack, + p2p::p2p_module::RpcTransportPolicy, rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, KvResult}, }; use chrono::Utc; use fluxon_commu::TransferBreakdown; +use futures::stream::{self, StreamExt}; +use limit_thirdparty::tokio; use std::time::Instant; use tracing::info; @@ -22,19 +39,1016 @@ fn duration_to_i64_us(duration: std::time::Duration) -> i64 { duration.as_micros().min(i64::MAX as u128) as i64 } +const OWNER_LOCAL_RESERVE_MIN_SLOT_SIZE_BYTES: u64 = 4 * 1024; +fn owner_local_reserve_slot_size(value_len: u64) -> KvResult { + let normalized = value_len.max(OWNER_LOCAL_RESERVE_MIN_SLOT_SIZE_BYTES); + let slot_size = normalized.checked_next_power_of_two().ok_or_else(|| { + KvError::Api(ApiError::InvalidArgument { + detail: format!( + "value_len={} exceeds resident local reserve slot size range", + value_len + ), + }) + })?; + if slot_size > OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "value_len={} requires slot_size={} larger than local reserve grant quantum={}", + value_len, slot_size, OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES + ), + })); + } + Ok(slot_size) +} + +fn owner_local_reserve_slots_per_grant(slot_size: u64) -> u32 { + let slots = (OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES / slot_size).max(1); + slots.min(u32::MAX as u64) as u32 +} + +fn owner_local_reserve_install_grant( + pool: &mut OwnerLocalReservePoolState, + slot_size: u64, + slots_per_grant: u32, + grant: OwnerLocalReserveGrantState, +) { + let class_state = pool + .classes + .entry(slot_size) + .or_insert_with(|| OwnerLocalReserveClassState::new(slot_size, slots_per_grant)); + assert!( + class_state.slot_size == slot_size, + "slot_size drift detected while installing local reserve grant" + ); + assert!( + class_state.slots_per_grant == slots_per_grant, + "slots_per_grant drift detected while installing local reserve grant" + ); + class_state.grants.push(grant); +} + +fn owner_local_reserve_try_claim( + pool: &mut OwnerLocalReservePoolState, + slot_size: u64, + slots_per_grant: u32, + value_len: u64, + key_count: usize, +) -> Option { + let class_state = pool + .classes + .entry(slot_size) + .or_insert_with(|| OwnerLocalReserveClassState::new(slot_size, slots_per_grant)); + if class_state.free_slot_count() < key_count { + return None; + } + let mut slots = Vec::with_capacity(key_count); + for grant in class_state.grants.iter_mut() { + while slots.len() < key_count { + match grant.claim_prepared_slot() { + Some(slot) => slots.push(slot), + None => break, + } + } + if slots.len() == key_count { + break; + } + } + assert!( + slots.len() == key_count, + "free_slot_count check and claim path diverged" + ); + Some(OwnerLocalReserveSlotLease { + value_len, + slot_size, + slots, + }) +} + +#[derive(Debug, Clone)] +pub struct OwnerReservedPutItem { + pub key: String, + pub put_id: PutIDForAKey, + pub src_addr: u64, + pub src_base_addr: u64, + pub target_addr: u64, + pub target_base_addr: u64, + pub value_len: u64, + pub lease_id: Option, + pub peer_node_id: Option, + pub write_through: bool, + pub remember_local_snapshot: bool, + pub enqueue_write_back_append: bool, + pub preferred_sub_cluster: Option, +} + #[derive(Debug, Clone, Copy, Default)] pub struct PutEndStats { pub master_put_end_rpc_us: i64, pub master_put_end_server_us: i64, } +pub struct PutEndWithLocalCachePublish { + pub stats: PutEndStats, + pub local_cache_holder_id: Option, +} + impl ClientKvApiInner { + pub async fn owner_claim_local_reserve_slot_lease( + &self, + value_len: u64, + key_count: usize, + ) -> KvResult { + let slot_size = owner_local_reserve_slot_size(value_len)?; + let slots_per_grant = owner_local_reserve_slots_per_grant(slot_size); + let (soft_wait_timeout, hard_wait_timeout) = owner_local_reserve_timeout_config(self); + let hard_deadline = Instant::now() + .checked_add(hard_wait_timeout) + .ok_or_else(|| { + KvError::Api(ApiError::Unknown { + detail: "owner local reserve hard timeout overflow".to_string(), + }) + })?; + let mut pending_demand_registered = false; + let claim_result = { + let mut pool = self.owner_local_reserve_pool.lock(); + let class_state = pool + .classes + .entry(slot_size) + .or_insert_with(|| OwnerLocalReserveClassState::new(slot_size, slots_per_grant)); + if class_state.free_slot_count() >= key_count { + Some(owner_local_reserve_try_claim( + &mut pool, + slot_size, + slots_per_grant, + value_len, + key_count, + )) + } else { + None + } + }; + if let Some(Some(lease)) = claim_result { + return Ok(lease); + } + self.owner_local_reserve_register_pending_demand(slot_size, slots_per_grant, key_count); + pending_demand_registered = true; + self.owner_local_reserve_rebalance_notify().notify_waiters(); + if !wait_owner_local_reserve_ready( + self, + slot_size, + slots_per_grant, + key_count, + soft_wait_timeout, + hard_deadline, + ) + .await + { + let soft_wait_timeout_ms = soft_wait_timeout.as_millis(); + let hard_wait_timeout_ms = hard_wait_timeout.as_millis(); + if pending_demand_registered { + self.owner_local_reserve_consume_pending_demand( + slot_size, + slots_per_grant, + key_count, + ); + } + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "owner local reserve refill timeout: slot_size={} key_count={} soft_wait_timeout_ms={} hard_timeout_ms={}", + slot_size, key_count, soft_wait_timeout_ms, hard_wait_timeout_ms + ), + })); + } + let claim_result = { + let mut pool = self.owner_local_reserve_pool.lock(); + let class_state = pool + .classes + .entry(slot_size) + .or_insert_with(|| OwnerLocalReserveClassState::new(slot_size, slots_per_grant)); + if class_state.free_slot_count() >= key_count { + Some(owner_local_reserve_try_claim( + &mut pool, + slot_size, + slots_per_grant, + value_len, + key_count, + )) + } else { + None + } + }; + if let Some(Some(lease)) = claim_result { + self.owner_local_reserve_consume_pending_demand(slot_size, slots_per_grant, key_count); + return Ok(lease); + } + self.owner_local_reserve_consume_pending_demand(slot_size, slots_per_grant, key_count); + Err(KvError::Api(ApiError::Unknown { + detail: format!( + "owner local reserve ready check returned without available slots: slot_size={} key_count={}", + slot_size, key_count + ), + })) + } + + pub async fn owner_release_local_reserve_slot_lease( + &self, + lease: OwnerLocalReserveSlotLease, + ) -> KvResult<()> { + { + let mut pool = self.owner_local_reserve_pool.lock(); + let Some(class_state) = pool.classes.get_mut(&lease.slot_size) else { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "resident local reserve class missing while releasing slot lease: slot_size={}", + lease.slot_size + ), + })); + }; + for slot_ref in &lease.slots { + let Some(grant) = class_state + .grants + .iter_mut() + .find(|grant| grant.grant_id == slot_ref.grant_id) + else { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "resident local reserve grant missing while releasing slot lease: grant_id={}", + slot_ref.grant_id + ), + })); + }; + grant.release_prepared_slot(slot_ref.slot_index); + } + } + self.owner_local_reserve_rebalance_notify().notify_waiters(); + Ok(()) + } + + pub fn owner_mark_local_reserve_slot_pending_visible( + &self, + slot_size: u64, + grant_id: u64, + slot_index: u32, + ) -> KvResult<()> { + let mut pool = self.owner_local_reserve_pool.lock(); + let Some(class_state) = pool.classes.get_mut(&slot_size) else { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "local reserve class missing while marking pending slot: slot_size={}", + slot_size + ), + })); + }; + let Some(grant) = class_state + .grants + .iter_mut() + .find(|grant| grant.grant_id == grant_id) + else { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "local reserve grant missing while marking pending slot: grant_id={}", + grant_id + ), + })); + }; + grant.mark_prepared_slot_pending_visible(slot_index); + Ok(()) + } + + pub fn owner_promote_local_reserve_pending_slot_to_committed( + &self, + slot_size: u64, + grant_id: u64, + slot_index: u32, + ) -> KvResult<()> { + let mut pool = self.owner_local_reserve_pool.lock(); + let Some(class_state) = pool.classes.get_mut(&slot_size) else { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "local reserve class missing while promoting pending slot: slot_size={}", + slot_size + ), + })); + }; + let Some(grant) = class_state + .grants + .iter_mut() + .find(|grant| grant.grant_id == grant_id) + else { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "local reserve grant missing while promoting pending slot: grant_id={}", + grant_id + ), + })); + }; + grant.promote_pending_visible_slot_to_committed(slot_index); + Ok(()) + } + + pub fn owner_retain_local_reserve_resident_slot_holder( + &self, + slot_size: u64, + grant_id: u64, + slot_index: u32, + ) -> KvResult<()> { + let mut pool = self.owner_local_reserve_pool.lock(); + let Some(class_state) = pool.classes.get_mut(&slot_size) else { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "local reserve class missing while retaining resident slot holder: slot_size={}", + slot_size + ), + })); + }; + let Some(grant) = class_state + .grants + .iter_mut() + .find(|grant| grant.grant_id == grant_id) + else { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "local reserve grant missing while retaining resident slot holder: grant_id={}", + grant_id + ), + })); + }; + grant.retain_resident_slot_holder(slot_index); + Ok(()) + } + + pub fn owner_release_local_reserve_resident_slot_holder( + &self, + slot_size: u64, + grant_id: u64, + slot_index: u32, + ) -> KvResult<()> { + { + let mut pool = self.owner_local_reserve_pool.lock(); + let Some(class_state) = pool.classes.get_mut(&slot_size) else { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "local reserve class missing while releasing resident slot holder: slot_size={}", + slot_size + ), + })); + }; + let Some(grant) = class_state + .grants + .iter_mut() + .find(|grant| grant.grant_id == grant_id) + else { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "local reserve grant missing while releasing resident slot holder: grant_id={}", + grant_id + ), + })); + }; + grant.release_resident_slot_holder(slot_index); + } + self.owner_local_reserve_rebalance_notify().notify_waiters(); + Ok(()) + } + + pub fn owner_release_local_reserve_committed_slot_route( + &self, + slot_size: u64, + grant_id: u64, + slot_index: u32, + ) -> KvResult<()> { + { + let mut pool = self.owner_local_reserve_pool.lock(); + let Some(class_state) = pool.classes.get_mut(&slot_size) else { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "local reserve class missing while releasing committed slot route: slot_size={}", + slot_size + ), + })); + }; + let Some(grant) = class_state + .grants + .iter_mut() + .find(|grant| grant.grant_id == grant_id) + else { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "local reserve grant missing while releasing committed slot route: grant_id={}", + grant_id + ), + })); + }; + grant.release_committed_slot_route(slot_index); + } + self.owner_local_reserve_rebalance_notify().notify_waiters(); + Ok(()) + } + + pub async fn owner_shutdown_local_reserve_pool(&self) -> KvResult<()> { + let grants = { + let mut pool = self.owner_local_reserve_pool.lock(); + let mut detached = Vec::new(); + for (_slot_size, class_state) in pool.classes.drain() { + detached.extend(class_state.grants); + } + detached + }; + let mut first_err = None; + for grant in grants { + if let Err(err) = self.release_local_grant(grant.grant_id).await { + if first_err.is_none() { + first_err = Some(err); + } else { + tracing::warn!( + "owner_shutdown_local_reserve_pool dropped additional release error after the first one: {}", + err + ); + } + } + } + if let Some(err) = first_err { + return Err(err); + } + Ok(()) + } + + pub async fn owner_batch_put_start_reserved( + &self, + start_items: Vec, + lease_id: Option, + ) -> KvResult> { + if start_items.is_empty() { + return Ok(Vec::new()); + } + if self.short_circuit_put_payload_path_enabled() { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: + "owner_batch_put_start_reserved does not support short_circuit_put_payload_path" + .to_string(), + })); + } + let self_node_id = self.view.cluster_manager().get_self_info().id.clone(); + let start_resp = self.batch_put_start(start_items.clone()).await?; + if start_resp.items.len() != start_items.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "batch_put_start response length mismatch: expected={} got={}", + start_items.len(), + start_resp.items.len() + ), + })); + } + + let mut prepared_items = Vec::with_capacity(start_items.len()); + let mut revoke_items = Vec::with_capacity(start_items.len()); + let mut first_error: Option = None; + + for (start_req, start_item) in start_items.into_iter().zip(start_resp.items.into_iter()) { + if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( + start_item.error_code, + start_item.error_json.clone(), + ) { + first_error = Some(err); + break; + } + let peer_node_id = if start_item.node_id == self_node_id { + None + } else { + Some(start_item.node_id.clone()) + }; + revoke_items.push(BatchPutRevokeItemReq { + key: start_req.key.clone(), + put_id: start_item.put_id, + }); + prepared_items.push(OwnerReservedPutItem { + key: start_req.key, + put_id: start_item.put_id, + src_addr: start_item.src_addr, + src_base_addr: start_item.src_base_addr, + target_addr: start_item.target_addr, + target_base_addr: start_item.target_base_addr, + value_len: start_req.len, + lease_id, + peer_node_id: peer_node_id.clone(), + write_through: start_req.write_through, + remember_local_snapshot: !start_req.write_through || peer_node_id.is_none(), + enqueue_write_back_append: !start_req.write_through && peer_node_id.is_some(), + preferred_sub_cluster: start_req.preferred_sub_cluster, + }); + } + + if let Some(err) = first_error { + if !revoke_items.is_empty() { + if let Err(revoke_err) = self.batch_put_revoke(revoke_items).await { + tracing::warn!( + "owner_batch_put_start_reserved batch_put_revoke failed after partial reserve: {}", + revoke_err + ); + } + } + return Err(err); + } + + Ok(prepared_items) + } + + pub async fn owner_batch_put_commit_reserved( + &self, + items: Vec, + transfer_concurrency: usize, + ) -> KvResult>> { + if items.is_empty() { + return Ok(Vec::new()); + } + + #[derive(Clone)] + struct DonePending { + idx: usize, + item: OwnerReservedPutItem, + } + + let transfer_concurrency = transfer_concurrency.max(1); + let metrics = self.metrics_handle(); + let mut results: Vec>> = (0..items.len()).map(|_| None).collect(); + let mut done_pending = Vec::with_capacity(items.len()); + let mut revoke_pending = Vec::new(); + let mut transfer_futures = Vec::new(); + + for (idx, item) in items.into_iter().enumerate() { + if !item.write_through { + metrics.record_put_io_locality(false, item.value_len, 0); + done_pending.push(DonePending { idx, item }); + continue; + } + if item.peer_node_id.is_none() && item.src_addr == item.target_addr { + metrics.record_put_io_locality(false, item.value_len, 0); + done_pending.push(DonePending { idx, item }); + continue; + } + + let src_offset = item.src_addr - item.src_base_addr; + let target_offset = if item.peer_node_id.is_some() { + item.target_addr - item.target_base_addr + } else { + item.target_addr - item.src_base_addr + }; + transfer_futures.push(async move { + let transfer_started_at = Instant::now(); + let transfer_result = self + .put_transfer( + &item.key, + item.put_id, + src_offset, + target_offset, + item.value_len, + item.peer_node_id.clone(), + item.peer_node_id.as_ref().map(|_| item.target_base_addr), + ) + .await; + ( + idx, + item, + duration_to_i64_us(transfer_started_at.elapsed()), + transfer_result, + ) + }); + } + + let mut transfer_stream = + stream::iter(transfer_futures).buffer_unordered(transfer_concurrency); + while let Some(joined) = transfer_stream.next().await { + match joined { + (idx, item, wall_transfer_us, Ok(breakdown)) => { + let breakdown_transfer_us = breakdown.submit_blocking_us + + breakdown.create_xfer_req_us + + breakdown.post_xfer_req_us + + breakdown.poll_wait_us; + let transfer_us = breakdown_transfer_us.max(wall_transfer_us); + metrics.record_put_io_locality( + breakdown.remote_transfer, + item.value_len, + transfer_us, + ); + done_pending.push(DonePending { idx, item }); + } + (idx, item, _wall_transfer_us, Err(err)) => { + results[idx] = Some(Err(err)); + revoke_pending.push(BatchPutRevokeItemReq { + key: item.key, + put_id: item.put_id, + }); + } + } + } + + if !revoke_pending.is_empty() { + if let Err(err) = self.batch_put_revoke(revoke_pending).await { + tracing::warn!( + "owner_batch_put_commit_reserved batch_put_revoke failed after transfer errors: {}", + err + ); + } + } + + if self.skip_put_end_commit_enabled() { + for pending in done_pending { + results[pending.idx] = Some(Ok(())); + } + return Ok(results + .into_iter() + .map(|item| { + item.unwrap_or_else(|| { + Err(KvError::Api(ApiError::Unknown { + detail: "owner_batch_put_commit_reserved result slot was not populated" + .to_string(), + })) + }) + }) + .collect()); + } + + let done_req_items = done_pending + .iter() + .map(|pending| BatchPutDoneItemReq { + key: pending.item.key.clone(), + put_id: pending.item.put_id, + lease_id: pending.item.lease_id, + committed_slot: None, + publish_local_cache: false, + }) + .collect::>(); + let done_resp = self.batch_put_done(done_req_items).await?; + if done_resp.items.len() != done_pending.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "batch_put_done response length mismatch: expected={} got={}", + done_pending.len(), + done_resp.items.len() + ), + })); + } + + for (pending, done_item) in done_pending.into_iter().zip(done_resp.items.into_iter()) { + if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( + done_item.error_code, + done_item.error_json.clone(), + ) { + results[pending.idx] = Some(Err(err)); + continue; + } + if pending.item.remember_local_snapshot { + self.remember_local_snapshot(&pending.item.key, pending.item.put_id); + } + if pending.item.enqueue_write_back_append { + if let Err(err) = self + .enqueue_write_back_remote_append( + &pending.item.key, + pending.item.put_id, + pending.item.preferred_sub_cluster.as_deref(), + ) + .await + { + tracing::warn!( + "owner_batch_put_commit_reserved write-back remote append enqueue failed after local commit: key={} put_id=({},{}) err={}", + pending.item.key, + pending.item.put_id.0, + pending.item.put_id.1, + err + ); + } + } + results[pending.idx] = Some(Ok(())); + } + + Ok(results + .into_iter() + .map(|item| { + item.unwrap_or_else(|| { + Err(KvError::Api(ApiError::Unknown { + detail: "owner_batch_put_commit_reserved result slot was not populated" + .to_string(), + })) + }) + }) + .collect()) + } + + pub async fn owner_batch_put_abort_reserved( + &self, + items: Vec, + ) -> KvResult<()> { + if items.is_empty() { + return Ok(()); + } + let revoke_items = items + .into_iter() + .map(|item| BatchPutRevokeItemReq { + key: item.key, + put_id: item.put_id, + }) + .collect::>(); + self.batch_put_revoke(revoke_items).await?; + Ok(()) + } + + pub async unsafe fn batch_put_flat_dict_ptrs( + &self, + keys: Vec, + ptrs_groups: Vec)>>, + opts: crate::client_kv_api::PutOptionalArgs, + transfer_concurrency: usize, + ) -> KvResult>> { + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting batch_put_flat_dict_ptrs" + .to_string(), + })); + } + if keys.len() != ptrs_groups.len() { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "batch_put_flat_dict_ptrs requires keys and ptrs_groups to have the same length: keys={} ptrs_groups={}", + keys.len(), + ptrs_groups.len() + ), + })); + } + if keys.is_empty() { + return Ok(Vec::new()); + } + let transfer_concurrency = transfer_concurrency.max(1); + let lease_id = opts.lease_id(); + let reject_if_inflight_same_key = opts.reject_if_inflight_same_key(); + let reject_if_exist_same_key = opts.reject_if_exist_same_key(); + let write_through = opts.write_through(); + let preferred_sub_cluster = opts.preferred_sub_cluster().map(|s| s.to_string()); + + let mut start_items = Vec::with_capacity(keys.len()); + let mut payload_lens = Vec::with_capacity(keys.len()); + for (key, ptrs) in keys.iter().zip(ptrs_groups.iter()) { + let payload_len = calc_flat_dict_encoded_len(ptrs)?; + payload_lens.push(payload_len); + start_items.push(BatchPutStartItemReq { + key: key.clone(), + len: payload_len, + reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, + preferred_sub_cluster: preferred_sub_cluster.clone(), + }); + } + + let start_resp = self.batch_put_start(start_items).await?; + if start_resp.items.len() != keys.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "batch_put_start response length mismatch: expected={} got={}", + keys.len(), + start_resp.items.len() + ), + })); + } + + #[derive(Clone)] + struct DonePending { + idx: usize, + key: String, + put_id: PutIDForAKey, + lease_id: Option, + remember_local_snapshot: bool, + enqueue_write_back_append: bool, + } + + let self_node_id = self.view.cluster_manager().get_self_info().id.clone(); + let mut results: Vec>> = (0..keys.len()).map(|_| None).collect(); + let mut done_pending = Vec::new(); + let mut revoke_pending = Vec::new(); + let mut transfer_futures = Vec::new(); + let short_circuit_payload = self.short_circuit_put_payload_path_enabled(); + let skip_put_end_commit = self.skip_put_end_commit_enabled(); + + for (idx, (((key, ptrs), payload_len), start_item)) in keys + .into_iter() + .zip(ptrs_groups.into_iter()) + .zip(payload_lens.into_iter()) + .zip(start_resp.items.into_iter()) + .enumerate() + { + if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( + start_item.error_code, + start_item.error_json.clone(), + ) { + results[idx] = Some(Err(err)); + continue; + } + + let put_id = start_item.put_id; + let peer_id = if start_item.node_id == self_node_id { + None + } else { + Some(start_item.node_id.clone()) + }; + let remember_local_snapshot = !write_through || peer_id.is_none(); + + if !short_circuit_payload { + unsafe { + write_flat_dict_ptrs_to_ptr(start_item.src_addr as *mut u8, &ptrs); + } + } + + if !write_through { + done_pending.push(DonePending { + idx, + key, + put_id, + lease_id, + remember_local_snapshot, + enqueue_write_back_append: !short_circuit_payload && peer_id.is_some(), + }); + continue; + } + + if short_circuit_payload + || (peer_id.is_none() && start_item.src_addr == start_item.target_addr) + { + done_pending.push(DonePending { + idx, + key, + put_id, + lease_id, + remember_local_snapshot, + enqueue_write_back_append: false, + }); + continue; + } + + let target_base_addr_opt = peer_id.as_ref().map(|_| start_item.target_base_addr); + let src_offset = start_item.src_addr - start_item.src_base_addr; + let target_offset = start_item.target_addr - start_item.target_base_addr; + transfer_futures.push(async move { + let transfer_result = self + .put_transfer( + &key, + put_id, + src_offset, + target_offset, + payload_len, + peer_id, + target_base_addr_opt, + ) + .await; + (idx, key, put_id, remember_local_snapshot, transfer_result) + }); + } + + let mut transfer_stream = + stream::iter(transfer_futures).buffer_unordered(transfer_concurrency); + while let Some(joined) = transfer_stream.next().await { + match joined { + (idx, key, put_id, remember_local_snapshot, Ok(_breakdown)) => { + done_pending.push(DonePending { + idx, + key, + put_id, + lease_id, + remember_local_snapshot, + enqueue_write_back_append: false, + }); + } + (idx, key, put_id, _remember_local_snapshot, Err(err)) => { + results[idx] = Some(Err(err)); + revoke_pending.push(BatchPutRevokeItemReq { key, put_id }); + } + } + } + + if !revoke_pending.is_empty() { + if let Err(err) = self.batch_put_revoke(revoke_pending).await { + tracing::warn!("batch_put_revoke failed after transfer errors: {}", err); + } + } + + if skip_put_end_commit { + for pending in done_pending { + results[pending.idx] = Some(Ok(())); + } + return Ok(results + .into_iter() + .map(|item| { + item.unwrap_or_else(|| { + Err(KvError::Api(ApiError::Unknown { + detail: "batch_put result slot was not populated".to_string(), + })) + }) + }) + .collect()); + } + + let done_req_items = done_pending + .iter() + .map(|pending| BatchPutDoneItemReq { + key: pending.key.clone(), + put_id: pending.put_id, + lease_id: pending.lease_id, + committed_slot: None, + publish_local_cache: false, + }) + .collect::>(); + let done_resp = self.batch_put_done(done_req_items).await?; + if done_resp.items.len() != done_pending.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "batch_put_done response length mismatch: expected={} got={}", + done_pending.len(), + done_resp.items.len() + ), + })); + } + for (pending, done_item) in done_pending.into_iter().zip(done_resp.items.into_iter()) { + if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( + done_item.error_code, + done_item.error_json.clone(), + ) { + results[pending.idx] = Some(Err(err)); + continue; + } + if pending.remember_local_snapshot { + self.remember_local_snapshot(&pending.key, pending.put_id); + } + if pending.enqueue_write_back_append { + if let Err(err) = self + .enqueue_write_back_remote_append( + &pending.key, + pending.put_id, + preferred_sub_cluster.as_deref(), + ) + .await + { + tracing::warn!( + "batch write-back remote append enqueue failed after local commit: key={} put_id=({},{}) err={}", + pending.key, + pending.put_id.0, + pending.put_id.1, + err + ); + } + } + results[pending.idx] = Some(Ok(())); + } + + Ok(results + .into_iter() + .map(|item| { + item.unwrap_or_else(|| { + Err(KvError::Api(ApiError::Unknown { + detail: "batch_put result slot was not populated".to_string(), + })) + }) + }) + .collect()) + } + + pub async fn enqueue_write_back_remote_append( + &self, + key: &str, + put_id: PutIDForAKey, + preferred_sub_cluster: Option<&str>, + ) -> KvResult<()> { + let Some((holder, _)) = self.get(key).await? else { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "write-back local commit did not produce a readable current replica: key={} put_id=({},{})", + key, put_id.0, put_id.1 + ), + })); + }; + self.write_back_append_tx + .send(WriteBackAppendJob { + key: key.to_string(), + put_id, + holder, + preferred_sub_cluster: preferred_sub_cluster.map(|s| s.to_string()), + }) + .await + .map_err(|err| { + KvError::Api(ApiError::Unknown { + detail: format!( + "write-back append actor queue send failed: key={} put_id=({},{}) err={}", + key, put_id.0, put_id.1, err + ), + }) + }) + } + async fn put_common( &self, key: &str, payload_len: u64, len_for_start: u32, reject_if_inflight_same_key: bool, + reject_if_exist_same_key: bool, + write_through: bool, preferred_sub_cluster: Option<&str>, lease_id: Option, _test_payload_len_u32: u32, @@ -57,6 +1071,8 @@ impl ClientKvApiInner { key, len_for_start, reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, preferred_sub_cluster, ) .await @@ -123,10 +1139,14 @@ impl ClientKvApiInner { skipped_breakdown.poll_wait_us, skipped_breakdown.poll_iters, skipped_breakdown.used_fast_path, + false, skipped_breakdown.local_noop, skipped_breakdown.remote_transfer, ); self.put_end(key, put_id, lease_id).await?; + if !write_through || peer_id.is_none() { + self.remember_local_snapshot(key, put_id); + } if let Some(tag) = info_complete_tag { info!("{tag} complete key={} bytes={}", key, payload_len); } @@ -150,6 +1170,31 @@ impl ClientKvApiInner { .await .unwrap() .allocated_addr; + if !write_through { + self.put_end(key, put_id, lease_id).await?; + self.remember_local_snapshot(key, put_id); + if peer_id.is_some() { + if let Err(err) = self + .enqueue_write_back_remote_append(key, put_id, preferred_sub_cluster) + .await + { + tracing::warn!( + "write-back remote append enqueue failed after local commit: key={} put_id=({},{}) err={}", + key, + put_id.0, + put_id.1, + err + ); + } + } + if let Some(tag) = info_complete_tag { + info!( + "{tag} local_commit_complete key={} bytes={}", + key, payload_len + ); + } + return Ok(()); + } let src_offset = abs_src - base_addr; let (target_offset, target_base_addr_opt) = match &peer_id { Some(_) => ( @@ -201,6 +1246,7 @@ impl ClientKvApiInner { transfer_breakdown.poll_wait_us, transfer_breakdown.poll_iters, transfer_breakdown.used_fast_path, + false, transfer_breakdown.local_noop, transfer_breakdown.remote_transfer, ); @@ -224,7 +1270,9 @@ impl ClientKvApiInner { } self.put_end(key, put_id, lease_id).await?; - self.cache_metadata_only_after_put(key, put_id); + if peer_id.is_none() { + self.remember_local_snapshot(key, put_id); + } if let Some(tag) = info_complete_tag { info!("{tag} complete key={} bytes={}", key, payload_len); } @@ -243,6 +1291,8 @@ impl ClientKvApiInner { ) -> KvResult<()> { let lease_id = opts.lease_id(); let reject_if_inflight_same_key = opts.reject_if_inflight_same_key(); + let reject_if_exist_same_key = opts.reject_if_exist_same_key(); + let write_through = opts.write_through(); let preferred_sub_cluster = opts.preferred_sub_cluster().map(|s| s.to_string()); let payload_len = calc_flat_dict_encoded_len(&ptrs)?; @@ -251,6 +1301,8 @@ impl ClientKvApiInner { payload_len, payload_len as u32, reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, preferred_sub_cluster.as_deref(), lease_id, payload_len as u32, @@ -276,6 +1328,8 @@ impl ClientKvApiInner { ) -> KvResult<()> { let lease_id = opts.lease_id(); let reject_if_inflight_same_key = opts.reject_if_inflight_same_key(); + let reject_if_exist_same_key = opts.reject_if_exist_same_key(); + let write_through = opts.write_through(); let preferred_sub_cluster = opts.preferred_sub_cluster().map(|s| s.to_string()); let payload_len = value.len() as u64; self.put_common( @@ -283,6 +1337,8 @@ impl ClientKvApiInner { payload_len, value.len() as u32, reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, preferred_sub_cluster.as_deref(), lease_id, value.len() as u32, @@ -361,11 +1417,12 @@ impl ClientKvApiInner { .transfer_data_no_copy(peer_id.clone(), false, abs_src, abs_target, len, None) .await?; tracing::debug!( - "put_transfer breakdown: key={}, put_id=({},{}) fast_path={} local_noop={} remote_transfer={} submit_blocking_us={} create_xfer_req_us={} post_xfer_req_us={} poll_wait_us={} poll_iters={}", + "put_transfer breakdown: key={}, put_id=({},{}) fast_path={} nixl={} local_noop={} remote_transfer={} submit_blocking_us={} create_xfer_req_us={} post_xfer_req_us={} poll_wait_us={} poll_iters={}", key, put_id.0, put_id.1, breakdown.used_fast_path, + false, breakdown.local_noop, breakdown.remote_transfer, breakdown.submit_blocking_us, @@ -401,6 +1458,8 @@ impl ClientKvApiInner { key: &str, len: u32, reject_if_inflight_same_key: bool, + reject_if_exist_same_key: bool, + write_through: bool, preferred_sub_cluster: Option<&str>, source_node_id: Option, ) -> KvResult<(PutStartResp, i64)> { @@ -409,6 +1468,8 @@ impl ClientKvApiInner { key: key.to_string(), len: len as u64, reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, preferred_sub_cluster: preferred_sub_cluster.map(|s| s.to_string()), source_node_id, }, @@ -458,18 +1519,88 @@ impl ClientKvApiInner { key: &str, len: u32, reject_if_inflight_same_key: bool, + reject_if_exist_same_key: bool, + write_through: bool, preferred_sub_cluster: Option<&str>, ) -> KvResult<(PutStartResp, i64)> { self.put_start_with_source_node( key, len, reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, preferred_sub_cluster, None, ) .await } + pub async fn reserve_local_grant(&self) -> KvResult { + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting reserve_local_grant".to_string(), + })); + } + let req = MsgPack { + serialize_part: ReserveLocalGrantReq::default(), + raw_bytes: Vec::new(), + }; + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let resp = self + .rpc_caller_reserve_local_grant + .call( + self.view.p2p_module(), + master_node_id.into(), + req, + Some(std::time::Duration::from_secs(60)), + 2, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + Ok(resp.serialize_part) + } + + pub async fn release_local_grant(&self, grant_id: u64) -> KvResult<()> { + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting release_local_grant".to_string(), + })); + } + let req = MsgPack { + serialize_part: ReleaseLocalGrantReq { grant_id }, + raw_bytes: Vec::new(), + }; + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let resp = self + .rpc_caller_release_local_grant + .call( + self.view.p2p_module(), + master_node_id.into(), + req, + Some(std::time::Duration::from_secs(60)), + 2, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + Ok(()) + } + /// 撤销 Put 操作,释放已分配的资源 pub async fn put_revoke(&self, key: &str, put_id: PutIDForAKey) -> KvResult<()> { if !self.view.register_shutdown_poller().is_running() { @@ -509,6 +1640,338 @@ impl ClientKvApiInner { Ok(()) } + pub async fn put_append_start( + &self, + key: &str, + put_id: PutIDForAKey, + len: u32, + preferred_sub_cluster: Option<&str>, + ) -> KvResult { + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting put_append_start".to_string(), + })); + } + let req = MsgPack { + serialize_part: PutAppendStartReq { + key: key.to_string(), + put_id, + len: len as u64, + preferred_sub_cluster: preferred_sub_cluster.map(|s| s.to_string()), + }, + raw_bytes: Vec::new(), + }; + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let resp = self + .rpc_caller_put_append_start + .call( + self.view.p2p_module(), + master_node_id.into(), + req, + Some(std::time::Duration::from_secs(60)), + 2, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + Ok(resp.serialize_part) + } + + pub async fn put_append_revoke(&self, key: &str, put_id: PutIDForAKey) -> KvResult<()> { + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting put_append_revoke".to_string(), + })); + } + let req = MsgPack { + serialize_part: PutAppendRevokeReq { + key: key.to_string(), + put_id, + }, + raw_bytes: Vec::new(), + }; + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let _resp = self + .rpc_caller_put_append_revoke + .call( + self.view.p2p_module(), + master_node_id.into(), + req, + Some(std::time::Duration::from_secs(60)), + 2, + ) + .await + .map_err(KvError::from)?; + Ok(()) + } + + pub async fn put_append_done( + &self, + key: &str, + put_id: PutIDForAKey, + ) -> KvResult { + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting put_append_done".to_string(), + })); + } + let req = MsgPack { + serialize_part: PutAppendDoneReq { + key: key.to_string(), + put_id, + }, + raw_bytes: Vec::new(), + }; + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let resp = self + .rpc_caller_put_append_done + .call( + self.view.p2p_module(), + master_node_id.into(), + req, + Some(std::time::Duration::from_secs(60)), + 0, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + Ok(resp.serialize_part) + } + + pub async fn batch_put_start( + &self, + items: Vec, + ) -> KvResult { + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting batch_put_start".to_string(), + })); + } + let req = MsgPack { + serialize_part: BatchPutStartReq { items }, + raw_bytes: Vec::new(), + }; + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let resp = self + .rpc_caller_batch_put_start + .call_with_transport_policy( + self.view.p2p_module(), + master_node_id.into(), + req, + Some(std::time::Duration::from_secs(60)), + RpcTransportPolicy::ForceTransport, + 2, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + Ok(resp.serialize_part) + } + + pub async fn batch_prepare_put_keys( + &self, + items: Vec, + ) -> KvResult { + if items.is_empty() { + return Ok(BatchPreparePutKeysResp { + reservation_ids: Vec::new(), + error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + }); + } + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting batch_prepare_put_keys" + .to_string(), + })); + } + let req = MsgPack { + serialize_part: BatchPreparePutKeysReq { items }, + raw_bytes: Vec::new(), + }; + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let resp = self + .rpc_caller_batch_prepare_put_keys + .call( + self.view.p2p_module(), + master_node_id.into(), + req, + Some(std::time::Duration::from_secs(60)), + 2, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + Ok(resp.serialize_part) + } + + pub async fn batch_release_put_key_reservations( + &self, + reservation_ids: Vec, + ) -> KvResult { + if reservation_ids.is_empty() { + return Ok(BatchReleasePutKeyReservationsResp { + error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + }); + } + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: + "ClientKvApi is shutting down; rejecting batch_release_put_key_reservations" + .to_string(), + })); + } + let req = MsgPack { + serialize_part: BatchReleasePutKeyReservationsReq { reservation_ids }, + raw_bytes: Vec::new(), + }; + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let resp = self + .rpc_caller_batch_release_put_key_reservations + .call( + self.view.p2p_module(), + master_node_id.into(), + req, + Some(std::time::Duration::from_secs(60)), + 2, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + Ok(resp.serialize_part) + } + + pub async fn batch_put_revoke( + &self, + items: Vec, + ) -> KvResult { + if items.is_empty() { + return Ok(BatchPutRevokeResp { + items: Vec::new(), + error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, + error_json: String::new(), + }); + } + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting batch_put_revoke".to_string(), + })); + } + let req = MsgPack { + serialize_part: BatchPutRevokeReq { items }, + raw_bytes: Vec::new(), + }; + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let resp = self + .rpc_caller_batch_put_revoke + .call_with_transport_policy( + self.view.p2p_module(), + master_node_id.into(), + req, + Some(std::time::Duration::from_secs(60)), + RpcTransportPolicy::ForceTransport, + 2, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + Ok(resp.serialize_part) + } + + pub async fn batch_put_done( + &self, + items: Vec, + ) -> KvResult { + if items.is_empty() { + return Ok(BatchPutDoneResp { + items: Vec::new(), + error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + }); + } + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting batch_put_done".to_string(), + })); + } + let req = MsgPack { + serialize_part: BatchPutDoneReq { items }, + raw_bytes: Vec::new(), + }; + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let resp = self + .rpc_caller_batch_put_done + .call_with_transport_policy( + self.view.p2p_module(), + master_node_id.into(), + req, + Some(std::time::Duration::from_secs(60)), + RpcTransportPolicy::ForceTransport, + 0, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + Ok(resp.serialize_part) + } + /// 完成 Put 操作,提交数据(inner,无监控) pub async fn put_end_inner( &self, @@ -526,6 +1989,8 @@ impl ClientKvApiInner { key: key.to_string(), put_id, lease_id, + committed_slot: None, + publish_local_cache: false, }, raw_bytes: Vec::new(), }; @@ -562,6 +2027,58 @@ impl ClientKvApiInner { }) } + pub async fn put_end_inner_with_local_cache_publish( + &self, + key: &str, + put_id: PutIDForAKey, + lease_id: Option, + publish_local_cache: bool, + ) -> KvResult { + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting put_end".to_string(), + })); + } + let req = MsgPack { + serialize_part: PutDoneReq { + key: key.to_string(), + put_id, + lease_id, + committed_slot: None, + publish_local_cache, + }, + raw_bytes: Vec::new(), + }; + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let rpc_started_at = Instant::now(); + let resp = self + .rpc_caller_put_done + .call( + self.view.p2p_module(), + master_node_id.into(), + req, + Some(std::time::Duration::from_secs(60)), + 0, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + Ok(PutEndWithLocalCachePublish { + stats: PutEndStats { + master_put_end_rpc_us: duration_to_i64_us(rpc_started_at.elapsed()), + master_put_end_server_us: resp.serialize_part.server_process_us, + }, + local_cache_holder_id: resp.serialize_part.local_cache_holder_id, + }) + } + /// 完成 Put 操作,提交数据(带监控):适配 external 路径,统一聚合 t1..t4 pub async fn put_end( &self, @@ -593,4 +2110,143 @@ impl ClientKvApiInner { ); Ok(end_stats) } + + pub async fn put_end_with_local_cache_publish( + &self, + key: &str, + put_id: PutIDForAKey, + lease_id: Option, + publish_local_cache: bool, + ) -> KvResult { + let metrics = self.metrics_handle(); + let client_id = self.client_id_str(); + let node_role = self.node_role(); + + let end = match self + .put_end_inner_with_local_cache_publish(key, put_id, lease_id, publish_local_cache) + .await + { + Ok(end) => end, + Err(e) => { + crate::observe_kvope::obe_put_end_error_from_pending( + &metrics, &client_id, &node_role, put_id, + ); + return Err(e); + } + }; + + metrics.pending_put_set_end_handle(put_id, end.stats.master_put_end_server_us); + crate::observe_kvope::obe_put_done_success_from_pending( + &metrics, &client_id, &node_role, key, put_id, 0, + ); + Ok(end) + } +} + +pub fn spawn_write_back_append_actor( + view: ClientKvApiView, + mut rx: tokio::sync::ampsc::Receiver, +) { + let view_task = view.clone(); + let _ = view.spawn("write_back_append_actor", async move { + let mut shutdown_waiter = view_task.register_shutdown_waiter(); + loop { + let job = tokio::select! { + _ = shutdown_waiter.wait() => { + tracing::info!("write_back_append_actor stopping due to shutdown signal"); + break; + } + job = rx.recv() => { + match job { + Some(job) => job, + None => break, + } + } + }; + let inner = view_task.client_kv_api().inner(); + let src_offset = job.holder.memory_info().offset; + let len = job.holder.get_length() as u64; + let append_start = match inner + .put_append_start( + &job.key, + job.put_id, + job.holder.get_length(), + job.preferred_sub_cluster.as_deref(), + ) + .await + { + Ok(resp) => resp, + Err(err) => { + tracing::warn!( + "write-back append start failed: key={} put_id=({},{}) err={}", + job.key, + job.put_id.0, + job.put_id.1, + err + ); + continue; + } + }; + if !append_start.scheduled { + tracing::debug!( + "write-back append skipped because current version no longer needs remote replica: key={} put_id=({},{})", + job.key, + job.put_id.0, + job.put_id.1 + ); + continue; + } + let target_offset = append_start.target_addr - append_start.target_base_addr; + if let Err(err) = inner + .put_transfer( + &job.key, + job.put_id, + src_offset, + target_offset, + len, + Some(append_start.node_id.clone()), + Some(append_start.target_base_addr), + ) + .await + { + tracing::warn!( + "write-back append transfer failed: key={} put_id=({},{}) err={}", + job.key, + job.put_id.0, + job.put_id.1, + err + ); + if let Err(revoke_err) = inner.put_append_revoke(&job.key, job.put_id).await { + tracing::warn!( + "write-back append revoke failed after transfer error: key={} put_id=({},{}) err={}", + job.key, + job.put_id.0, + job.put_id.1, + revoke_err + ); + } + continue; + } + match inner.put_append_done(&job.key, job.put_id).await { + Ok(resp) => { + tracing::debug!( + "write-back append done: key={} put_id=({},{}) appended={}", + job.key, + job.put_id.0, + job.put_id.1, + resp.appended + ); + } + Err(err) => { + tracing::warn!( + "write-back append done failed: key={} put_id=({},{}) err={}", + job.key, + job.put_id.0, + job.put_id.1, + err + ); + } + } + } + }); } diff --git a/fluxon_rs/fluxon_kv/src/client_seg_pool/mod.rs b/fluxon_rs/fluxon_kv/src/client_seg_pool/mod.rs index 1aa6954..429f6b8 100644 --- a/fluxon_rs/fluxon_kv/src/client_seg_pool/mod.rs +++ b/fluxon_rs/fluxon_kv/src/client_seg_pool/mod.rs @@ -1,4 +1,3 @@ -use crate::ClientKvApiAccessTrait; use crate::client_kv_api::ClientKvApi; use crate::client_transfer_engine::{ClientTransferEngine, ClientTransferEngineAccessTrait}; use crate::cluster_manager::ClusterManagerAccessTrait; @@ -6,8 +5,9 @@ use crate::config::ContributeToClusterPoolSize; use crate::master_seg_manager::msg_pack::SegmentDeviceMemInfo; use crate::p2p::p2p_module::P2pModule; use crate::p2p::p2p_module::P2pModuleAccessTrait; -use crate::rpcresp_kvresult_convert::FromError; use crate::rpcresp_kvresult_convert::msg_and_error::OK; +use crate::rpcresp_kvresult_convert::FromError; +use crate::ClientKvApiAccessTrait; use crate::{ cluster_manager::{ClusterManager, ClusterMember}, master_seg_manager::msg_pack::{ @@ -19,7 +19,7 @@ use crate::{ use async_trait::async_trait; use bitcode::{Decode, Encode}; use fluxon_commu::{CpuAllocatedMem, ShareGroupOwnerRef}; -use fluxon_framework::{LogicalModule, define_module}; +use fluxon_framework::{define_module, LogicalModule}; use fluxon_util::new_map; use limit_thirdparty::tokio; use limit_thirdparty::tokio::sync::ARwLockReadGuardOwned; @@ -237,10 +237,7 @@ impl ClientSegPool { std::path::Path::new(share_mem_path).join(SIDE_TRANSFER_PEERS_DIRNAME) } - pub fn side_transfer_peer_file_path( - share_mem_path: &str, - side_id: &str, - ) -> std::path::PathBuf { + pub fn side_transfer_peer_file_path(share_mem_path: &str, side_id: &str) -> std::path::PathBuf { Self::side_transfer_peers_dir(share_mem_path).join(format!("{side_id}.json")) } @@ -399,17 +396,13 @@ impl ClientSegPool { crate::rpcresp_kvresult_convert::msg_and_error::SharedMemError::MappingFailed { path: String::new(), len: map_len as u64, - detail: "share_mem_path is empty; explicit configuration required" - .to_string(), + detail: "share_mem_path is empty; explicit configuration required".to_string(), }, )); } let base_path = &share_mem_path; - tracing::info!( - "Using share_mem_path: {} for memory-mapped file", - base_path - ); + tracing::info!("Using share_mem_path: {} for memory-mapped file", base_path); std::fs::create_dir_all(base_path).map_err(|e| { KvError::SharedMem( crate::rpcresp_kvresult_convert::msg_and_error::SharedMemError::MappingFailed { diff --git a/fluxon_rs/fluxon_kv/src/config.rs b/fluxon_rs/fluxon_kv/src/config.rs index f9c7691..4c7615f 100644 --- a/fluxon_rs/fluxon_kv/src/config.rs +++ b/fluxon_rs/fluxon_kv/src/config.rs @@ -133,6 +133,10 @@ pub struct TestSpecConfig { pub short_circuit_put_payload_path: bool, #[serde(default)] pub skip_put_end_commit: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub owner_local_reserve_soft_wait_timeout_ms: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub owner_local_reserve_hard_timeout_ms: Option, #[serde(skip_serializing_if = "Option::is_none")] pub transport_mode: Option, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -171,6 +175,8 @@ impl Default for TestSpecConfig { prefer_local_placement: false, short_circuit_put_payload_path: false, skip_put_end_commit: false, + owner_local_reserve_soft_wait_timeout_ms: None, + owner_local_reserve_hard_timeout_ms: None, transport_mode: None, tcp_thread_reactor_shard_count: None, tcp_thread_bulk_lane_count: None, @@ -297,6 +303,38 @@ fn validate_required_transfer_rpc_fast_path_ready_timeout( Ok(()) } +fn validate_owner_local_reserve_timeouts(test_spec_config: &TestSpecConfig) -> KvResult<()> { + let Some(soft_wait_timeout_ms) = test_spec_config.owner_local_reserve_soft_wait_timeout_ms + else { + return Ok(()); + }; + if soft_wait_timeout_ms == 0 { + return Err(ConfigError::InvalidClientConfig { + detail: "test_spec_config.owner_local_reserve_soft_wait_timeout_ms must be > 0" + .to_string(), + } + .into_kverror()); + } + + if let Some(hard_timeout_ms) = test_spec_config.owner_local_reserve_hard_timeout_ms { + if hard_timeout_ms == 0 { + return Err(ConfigError::InvalidClientConfig { + detail: "test_spec_config.owner_local_reserve_hard_timeout_ms must be > 0" + .to_string(), + } + .into_kverror()); + } + if hard_timeout_ms <= soft_wait_timeout_ms { + return Err(ConfigError::InvalidClientConfig { + detail: "test_spec_config.owner_local_reserve_hard_timeout_ms must be greater than owner_local_reserve_soft_wait_timeout_ms".to_string(), + } + .into_kverror()); + } + } + + Ok(()) +} + fn apply_test_spec_rdma_device_names_to_protocol( mut protocol: ProtocolConfig, normalized_rdma_device_names: Option<&Vec>, @@ -733,7 +771,7 @@ pub struct ClientConfig { pub pprof_duration_seconds: Option, pub redis_compat_listen_addr: Option, pub fluxonkv_spec: FluxonKvSpec, - pub share_mem_path: String, // Mandatory shared bundle path + pub share_mem_path: String, // Mandatory shared bundle path pub large_file_paths: LargeFilePaths, // Mandatory large-file roots for logs and caches pub test_spec_config: TestSpecConfig, } @@ -913,6 +951,7 @@ impl ClientConfigYaml { )?; materialize_default_test_spec_transport_mode(&mut test_spec_config); validate_required_transfer_rpc_fast_path_ready_timeout(&test_spec_config)?; + validate_owner_local_reserve_timeouts(&test_spec_config)?; validate_test_spec_tcp_thread_tuning(&test_spec_config)?; // Role selection contract: @@ -1170,13 +1209,15 @@ impl ClientConfigYaml { } else { let Some(large_file_paths_yaml) = self.fluxonkv_spec.large_file_paths.as_ref() else { return Err(ConfigError::InvalidClientConfig { - detail: "fluxonkv_spec.large_file_paths is required for owner mode" - .to_string(), + detail: "fluxonkv_spec.large_file_paths is required for owner mode".to_string(), } .into_kverror()); }; LargeFilePaths { - paths: verify_non_empty_root_path_list(&large_file_paths_yaml.0, "large_file_paths")?, + paths: verify_non_empty_root_path_list( + &large_file_paths_yaml.0, + "large_file_paths", + )?, } }; @@ -1498,6 +1539,7 @@ impl MasterConfigYaml { )?; materialize_default_test_spec_transport_mode(&mut test_spec_config); validate_required_transfer_rpc_fast_path_ready_timeout(&test_spec_config)?; + validate_owner_local_reserve_timeouts(&test_spec_config)?; validate_test_spec_tcp_thread_tuning(&test_spec_config)?; let protocol = apply_test_spec_rdma_device_names_to_protocol( self.protocol.unwrap_or(ProtocolConfig { @@ -1647,7 +1689,9 @@ fluxonkv_spec: .unwrap(); let err = cfg.verify().unwrap_err(); let text = format!("{err}"); - assert!(text.contains("fluxonkv_spec.large_file_paths is forbidden in zero-contribution mode")); + assert!( + text.contains("fluxonkv_spec.large_file_paths is forbidden in zero-contribution mode") + ); } #[test] @@ -1667,7 +1711,9 @@ fluxonkv_spec: let logs_dir = large_file_paths.kv_logs_dir("test_cluster").unwrap(); assert_eq!( logs_dir, - first_root.join("child").join("test_cluster_cluster_kv_logs") + first_root + .join("child") + .join("test_cluster_cluster_kv_logs") ); assert!(logs_dir.exists()); @@ -1736,8 +1782,8 @@ test_spec_config: } #[test] - fn client_test_spec_config_implicit_transport_mode_with_rdma_device_names_defaults_to_transfer_with_rpc() - { + fn client_test_spec_config_implicit_transport_mode_with_rdma_device_names_defaults_to_transfer_with_rpc( + ) { let cfg = ClientConfigYaml::from_str( r#" instance_key: test_owner @@ -1802,8 +1848,8 @@ test_spec_config: } #[test] - fn client_test_spec_config_rejects_transfer_rpc_fast_path_ready_timeout_without_explicit_rdma_device_names() - { + fn client_test_spec_config_rejects_transfer_rpc_fast_path_ready_timeout_without_explicit_rdma_device_names( + ) { let cfg = ClientConfigYaml::from_str( r#" instance_key: test_owner @@ -1847,10 +1893,9 @@ test_spec_config: ) .unwrap(); let err = cfg.verify().unwrap_err(); - assert!( - err.to_string() - .contains("test_spec_config.tcp_thread_control_lane_count must be in [1, 8]") - ); + assert!(err + .to_string() + .contains("test_spec_config.tcp_thread_control_lane_count must be in [1, 8]")); } #[test] diff --git a/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs b/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs index 9cb291f..fb60035 100644 --- a/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs +++ b/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs @@ -1,19 +1,28 @@ -use crate::SharedJsonMeta; +use crate::client_kv_api::external_api::{ + compute_external_get_start_transfer_prefix, normalize_external_get_start_group_lens, +}; use crate::client_kv_api::msg_pack::{ - ExternalInvalidateWeakIndexReq, ExternalInvalidateWeakIndexResp, + ExternalInvalidateWeakIndexItem, ExternalInvalidateWeakIndexReq, + ExternalInvalidateWeakIndexResp, }; use crate::client_seg_pool::{ClientSegPool, SideTransferPeerFileMeta}; -use crate::cluster_manager::app_logic_ext::ClusterManagerAppLogicExt; use crate::cluster_manager::{ META_KEY_SHARED_STORAGE_NODE_ID, META_KEY_SHARED_STORAGE_NODE_START_TIME, }; use crate::rpcresp_kvresult_convert::ToResult; +use crate::SharedJsonMeta; use crate::{ client_kv_api::msg_pack::{ - ExternalDeleteAckReq, ExternalDeleteReq, ExternalGetReq, ExternalIsExistReq, - ExternalPutCommitReq, ExternalPutCommitResp, ExternalPutStartReq, ExternalPutStartResp, - ExternalPutTransferEndReq, ExternalPutTransferEndResp, SyncKvToFileReq, SyncKvToFileResp, - TestPutPhaseTrace, + ExternalBatchGetCancelReq, ExternalBatchGetReq, ExternalBatchGetStartReq, + ExternalBatchGetStartResp, ExternalBatchGetTransferReq, ExternalBatchGetTransferResp, + ExternalBatchIsExistReq, ExternalBatchPutCommitItemReq, ExternalBatchPutCommitReq, + ExternalBatchPutCommitResp, ExternalBatchPutStartItemReq, ExternalBatchPutStartReq, + ExternalBatchPutStartResp, ExternalBatchPutTransferEndItemReq, + ExternalBatchPutTransferEndReq, ExternalBatchPutTransferEndResp, ExternalDeleteAckReq, + ExternalDeleteReq, ExternalGetReq, ExternalIsExistReq, ExternalObservabilitySnapshotReq, + ExternalPutCommitReq, ExternalPutCommitResp, ExternalPutRevokeReq, ExternalPutRevokeResp, + ExternalPutStartReq, ExternalPutStartResp, ExternalPutTransferEndReq, + ExternalPutTransferEndResp, SyncKvToFileReq, SyncKvToFileResp, TestPutPhaseTrace, }, cluster_manager::{ ClusterManager, ClusterManagerAccessTrait, IpcBandwidthAttributorHandle, NodeRole, @@ -22,18 +31,18 @@ use crate::{ memholder::ExternalMemHolder, p2p::{ msg_pack::{MsgPack, RPCCaller, RPCHandler}, - p2p_module::{P2pModule, P2pModuleAccessTrait}, + p2p_module::{P2pModule, P2pModuleAccessTrait, RpcTransportPolicy}, }, - rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, KvResult, SharedMemError}, + rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, KvResult, SharedMemError, OK}, }; use async_trait::async_trait; use core::panic; use dashmap::DashMap; use fluxon_commu::ShareGroupOwnerRef; -use fluxon_framework::{LogicalModule, define_module}; +use fluxon_framework::{define_module, LogicalModule}; use fluxon_observability::kv_metrics_actor::{ObserveComponent, ObserveDirection}; use fluxon_util::semaphore_map::SemaphoreMap; -use libc::{MAP_SHARED, PROT_READ, PROT_WRITE, mmap}; +use libc::{mmap, MAP_SHARED, PROT_READ, PROT_WRITE}; use limit_thirdparty::tokio; use limit_thirdparty::tokio::sync::{ARwLock, Notify}; use limit_thirdparty::tokio::time::sleep; @@ -42,8 +51,8 @@ use std::{ fs::File, // path::PathBuf, // 不再使用PathBuf sync::{ - Arc, OnceLock, Weak, atomic::{AtomicUsize, Ordering}, + Arc, OnceLock, Weak, }, time::{Duration, Instant}, }; @@ -62,9 +71,18 @@ const EXTERNAL_PUT_START_RPC_TIMEOUT_SECS: u64 = 30; const EXTERNAL_PUT_TRANSFER_END_RPC_TIMEOUT_SECS: u64 = 30; const EXTERNAL_RPC_P2P_RECOVER_MAX_ATTEMPTS: usize = 3; const EXTERNAL_PUT_TRACE_LOG_WINDOW_SECS: u64 = 10; -const EXTERNAL_INIT_CONTROL_PLANE_READY_TIMEOUT_SECS: u64 = 30; -const EXTERNAL_INIT_CONTROL_PLANE_READY_POLL_MS: u64 = 100; -const EXTERNAL_INIT_CONTROL_PLANE_READY_CONSECUTIVE_SUCCESSES: usize = 2; + +#[derive(Debug, Clone)] +pub struct ExternalClientGetStartResp { + pub handle: u64, + pub raw_prefix_hit_len: usize, +} + +struct PendingExternalGetStart { + keys: Vec, + transferable_len: usize, + first_miss_index: Option, +} fn duration_to_i64_us(duration: std::time::Duration) -> i64 { duration.as_micros().min(i64::MAX as u128) as i64 @@ -195,9 +213,9 @@ struct SharedMemoryPtr { /// Length of the mapping in bytes len: u64, /// Base directory of the shared-memory bundle (used to locate shared.json/mmap.file) - _path: String, + path: String, /// Handle to the mmap backing file. Keeping the FD open is harmless and simplifies lifecycle. - _file: File, + file: File, /// Metadata signature read from shared.json for change detection. memory_signature: SharedMetaSignature, } @@ -218,8 +236,8 @@ impl SharedMemoryPtr { ptr_rw, ptr_ro, len, - _path: path, - _file: file, + path, + file, memory_signature, } } @@ -251,8 +269,8 @@ define_module!( /// External Client configuration parameters #[derive(Clone, Debug)] pub struct ExternalClientApiNewArg { - pub share_mem_path: String, - pub large_file_paths: crate::config::LargeFilePaths, + pub shared_memory_path: String, + pub shared_file_path: String, pub expected_cluster_name: String, pub expected_protocol_version: String, pub enable_side_transfer: bool, @@ -310,24 +328,35 @@ pub struct ExternalInner { initial_sub_cluster: OnceLock>, expected_cluster_name: String, expected_protocol_version: String, - external_share_mem_path: String, - external_large_file_paths: crate::config::LargeFilePaths, - _enable_side_transfer: bool, + external_shared_memory_path: String, + external_shared_file_path: String, + enable_side_transfer: bool, short_circuit_put_payload_path: bool, side_rr_next: AtomicUsize, side_transfer_put_bindings: moka::sync::SegmentedCache<(u64, u32), (String, u16)>, rpc_caller_external_get: RPCCaller, + rpc_caller_external_batch_get: RPCCaller, + rpc_caller_external_batch_get_start: RPCCaller, + rpc_caller_external_batch_get_transfer: RPCCaller, + rpc_caller_external_batch_get_cancel: RPCCaller, rpc_caller_external_put_commit: RPCCaller, + rpc_caller_external_batch_put_commit: RPCCaller, rpc_caller_external_put_start: RPCCaller, + rpc_caller_external_batch_put_start: RPCCaller, rpc_caller_external_put_transfer_end: RPCCaller, + rpc_caller_external_batch_put_transfer_end: RPCCaller, rpc_caller_external_delete: RPCCaller, rpc_caller_external_is_exist: RPCCaller, + rpc_caller_external_batch_is_exist: RPCCaller, + rpc_caller_external_observability_snapshot: RPCCaller, rpc_caller_external_delete_ack: RPCCaller, + rpc_caller_external_put_revoke: RPCCaller, /// Lease RPC callers for external mode - _rpc_caller_allocate_client_lease: RPCCaller, - _rpc_caller_client_lease_keepalive: RPCCaller, + rpc_caller_allocate_client_lease: RPCCaller, + rpc_caller_client_lease_keepalive: RPCCaller, /// key -> Weak index (dashmap-based) key_weak_memholder_index: DashMap>, + pending_external_get_start: DashMap, /// per-key semaphore (permits=1) to ensure single inflight per key inflight1_per_key: SemaphoreMap, put_trace_log_window: Mutex, @@ -350,7 +379,7 @@ impl ExternalClientApi { pub async fn construct(arg: ExternalClientApiNewArg) -> Result { tracing::info!( "Constructing ExternalClientApi in ExternalClient mode (PreView): shm_dir={}", - arg.share_mem_path + arg.shared_memory_path ); Ok(Self(ExternalInner { @@ -361,9 +390,9 @@ impl ExternalClientApi { initial_sub_cluster: OnceLock::new(), expected_cluster_name: arg.expected_cluster_name, expected_protocol_version: arg.expected_protocol_version, - external_share_mem_path: arg.share_mem_path, - external_large_file_paths: arg.large_file_paths, - _enable_side_transfer: arg.enable_side_transfer, + external_shared_memory_path: arg.shared_memory_path, + external_shared_file_path: arg.shared_file_path, + enable_side_transfer: arg.enable_side_transfer, short_circuit_put_payload_path: arg.short_circuit_put_payload_path, side_rr_next: AtomicUsize::new(0), side_transfer_put_bindings: moka::sync::Cache::builder() @@ -371,15 +400,28 @@ impl ExternalClientApi { .segments(16) .build(), rpc_caller_external_get: RPCCaller::::new(), + rpc_caller_external_batch_get: RPCCaller::::new(), + rpc_caller_external_batch_get_start: RPCCaller::::new(), + rpc_caller_external_batch_get_transfer: RPCCaller::::new(), + rpc_caller_external_batch_get_cancel: RPCCaller::::new(), rpc_caller_external_put_commit: RPCCaller::::new(), + rpc_caller_external_batch_put_commit: RPCCaller::::new(), rpc_caller_external_put_start: RPCCaller::::new(), + rpc_caller_external_batch_put_start: RPCCaller::::new(), rpc_caller_external_put_transfer_end: RPCCaller::::new(), + rpc_caller_external_batch_put_transfer_end: + RPCCaller::::new(), rpc_caller_external_delete: RPCCaller::::new(), rpc_caller_external_is_exist: RPCCaller::::new(), + rpc_caller_external_batch_is_exist: RPCCaller::::new(), + rpc_caller_external_observability_snapshot: + RPCCaller::::new(), rpc_caller_external_delete_ack: RPCCaller::::new(), - _rpc_caller_allocate_client_lease: RPCCaller::::new(), - _rpc_caller_client_lease_keepalive: RPCCaller::::new(), + rpc_caller_external_put_revoke: RPCCaller::::new(), + rpc_caller_allocate_client_lease: RPCCaller::::new(), + rpc_caller_client_lease_keepalive: RPCCaller::::new(), key_weak_memholder_index: DashMap::new(), + pending_external_get_start: DashMap::new(), inflight1_per_key: SemaphoreMap::new(1, std::time::Duration::from_secs(120)), put_trace_log_window: Mutex::new(ExternalPutTraceLogWindow::new()), })) @@ -403,7 +445,8 @@ impl ExternalClientApi { let wait_start_ts = i64::MIN; let OwnerRestartPayload { meta, signature } = task_wait_owner_restart( ext.view.clone_view(), - ext.external_share_mem_path.clone(), + ext.external_shared_memory_path.clone(), + ext.external_shared_file_path.clone(), None, wait_start_ts, None, @@ -413,7 +456,7 @@ impl ExternalClientApi { .await?; let shared_memory_ptr = ExternalInner::init_shared_memory_from_meta( - &ext.external_share_mem_path, + &ext.external_shared_memory_path, &meta, signature, )?; @@ -449,17 +492,37 @@ impl ExternalClientApi { // Owner binding (current_owner) is already established by the init resource // `owner_shared_mem_bundle_ready`, so handler registration is safe here. ext.rpc_caller_external_get.regist(ext.view.p2p_module()); + ext.rpc_caller_external_batch_get + .regist(ext.view.p2p_module()); + ext.rpc_caller_external_batch_get_start + .regist(ext.view.p2p_module()); + ext.rpc_caller_external_batch_get_transfer + .regist(ext.view.p2p_module()); + ext.rpc_caller_external_batch_get_cancel + .regist(ext.view.p2p_module()); ext.rpc_caller_external_put_commit .regist(ext.view.p2p_module()); + ext.rpc_caller_external_batch_put_commit + .regist(ext.view.p2p_module()); ext.rpc_caller_external_put_start .regist(ext.view.p2p_module()); + ext.rpc_caller_external_batch_put_start + .regist(ext.view.p2p_module()); ext.rpc_caller_external_put_transfer_end .regist(ext.view.p2p_module()); + ext.rpc_caller_external_batch_put_transfer_end + .regist(ext.view.p2p_module()); ext.rpc_caller_external_delete.regist(ext.view.p2p_module()); ext.rpc_caller_external_is_exist .regist(ext.view.p2p_module()); + ext.rpc_caller_external_batch_is_exist + .regist(ext.view.p2p_module()); + ext.rpc_caller_external_observability_snapshot + .regist(ext.view.p2p_module()); ext.rpc_caller_external_delete_ack .regist(ext.view.p2p_module()); + ext.rpc_caller_external_put_revoke + .regist(ext.view.p2p_module()); crate::key_prefix::init_for_p2p_owner(ext.view.p2p_module()); crate::kvlease::init_for_p2p_owner(ext.view.p2p_module()); crate::metrics::client::init_for_p2p_owner(ext.view.p2p_module()); @@ -470,7 +533,7 @@ impl ExternalClientApi { move |resp, msg| { let view = view_ext.clone(); let view_task = view.clone(); - let _ = view.spawn("rpc_external_invalidate_weak_index", async move { + view.spawn("rpc_external_invalidate_weak_index", async move { let result = handle_external_invalidate_weak_index(&view_task, &msg).await; let _ = resp.send_resp(result).await; }); @@ -483,7 +546,7 @@ impl ExternalClientApi { RPCHandler::::new().regist(ext.view.p2p_module(), move |resp, msg| { let view = view_ext.clone(); let view_task = view.clone(); - let _ = view.spawn("rpc_sync_kv_to_file", async move { + view.spawn("rpc_sync_kv_to_file", async move { let result = handle_sync_kv_to_file_external(&view_task, &msg).await; let _ = resp.send_resp(result).await; }); @@ -507,7 +570,7 @@ impl ExternalClientApi { { let view = ext.view.clone_view(); let view_task = view.clone(); - let _ = view.spawn("external_owner_remap_actor", async move { + view.spawn("external_owner_remap_actor", async move { let shutdown_poller = view_task.register_shutdown_poller(); let mut cluster_rx = view_task.cluster_manager().listen(); let mut tick = tokio::time::interval(Duration::from_millis(200)); @@ -518,14 +581,6 @@ impl ExternalClientApi { break; } - let Some(view_guard) = view_task.try_upgrade() else { - tracing::info!( - "external owner remap actor stopped because view was dropped" - ); - break; - }; - let _keep_view_alive = view_guard; - if let Err(err) = view_task .external_client_api() .inner() @@ -567,7 +622,7 @@ impl ExternalClientApi { let owner_id_for_task = owner_id.clone(); let view_task = ext.view.clone_view(); let view_task2 = view_task.clone(); - let _ = view_task.spawn("ipc_bandwidth_attributor", async move { + view_task.spawn("ipc_bandwidth_attributor", async move { let mut shutdown_waiter = view_task2.register_shutdown_waiter(); let mut interval = tokio::time::interval(Duration::from_secs( crate::metric_reporter::METRICS_FLUSH_INTERVAL_SECS, @@ -668,110 +723,6 @@ impl ExternalClientApi { } impl ExternalInner { - async fn wait_initial_control_plane_ready(&self, phase: &'static str) -> KvResult<()> { - let owner_id = self.shared_storage_node_id().await.expect( - "ExternalClientApi expects current_owner to be Some before control-plane readiness wait", - ); - self.wait_peer_send_ready(owner_id, "owner", phase).await?; - - let master_node_id = self - .view - .cluster_manager() - .find_or_wait_master_node() - .await?; - self.wait_peer_send_ready(master_node_id, "master", phase) - .await - } - - async fn wait_peer_send_ready( - &self, - logical_target: String, - target_role: &'static str, - phase: &'static str, - ) -> KvResult<()> { - let deadline = - Instant::now() + Duration::from_secs(EXTERNAL_INIT_CONTROL_PLANE_READY_TIMEOUT_SECS); - let shutdown_poller = self.view.register_shutdown_poller(); - let mut attempts = 0u64; - let mut consecutive_ready = 0usize; - let mut last_transient_err = None; - - loop { - if !shutdown_poller.is_running() { - return Err(KvError::Api(ApiError::SystemShutdown { - detail: format!( - "external control-plane wait stopped during {phase}: target_role={target_role} target={logical_target}" - ), - })); - } - - let readiness = self - .view - .p2p_module() - .ensure_peer_send_ready(&logical_target.clone().into()) - .await; - match readiness { - Ok(()) => { - consecutive_ready += 1; - if consecutive_ready >= EXTERNAL_INIT_CONTROL_PLANE_READY_CONSECUTIVE_SUCCESSES - { - if attempts > 0 { - tracing::info!( - "external control-plane route ready: phase={} target_role={} target={} attempts={}", - phase, - target_role, - logical_target, - attempts + 1, - ); - } - return Ok(()); - } - } - Err(err) - if matches!( - err, - crate::p2p::P2PError::NoConnectionReady { .. } - | crate::p2p::P2PError::NodeNotFound { .. } - | crate::p2p::P2PError::NodeNotConnected { .. } - | crate::p2p::P2PError::NodePortNotReady { .. } - | crate::p2p::P2PError::ConnectionError { .. } - | crate::p2p::P2PError::SendFailed { .. } - | crate::p2p::P2PError::Iceoryx2TransportNotStarted {} - ) => - { - consecutive_ready = 0; - last_transient_err = Some(err.to_string()); - } - Err(err) => return Err(KvError::from(err)), - } - - attempts += 1; - if attempts == 1 || attempts % 20 == 0 { - tracing::info!( - "waiting for external control-plane route: phase={} target_role={} target={} attempts={} last_transient_err={:?}", - phase, - target_role, - logical_target, - attempts, - last_transient_err, - ); - } - - if Instant::now() >= deadline { - return Err(KvError::Api(ApiError::Unknown { - detail: format!( - "timed out waiting for external control-plane route during {phase}: target_role={target_role} target={logical_target} attempts={attempts} last_transient_err={last_transient_err:?}" - ), - })); - } - - sleep(Duration::from_millis( - EXTERNAL_INIT_CONTROL_PLANE_READY_POLL_MS, - )) - .await; - } - } - fn maybe_log_external_put_trace_window(&self, sample: &TestPutPhaseTrace) { let maybe_window = { let mut guard = self.put_trace_log_window.lock(); @@ -795,11 +746,30 @@ impl ExternalInner { ); } - async fn current_owner_start_time(&self) -> i64 { + pub async fn current_owner_start_time(&self) -> i64 { let g = self.current_owner.read().await; g.as_ref().map(|o| o.owner_start_time).unwrap_or_default() } + pub async fn wait_current_owner_mapped_range(&self) -> KvResult<(String, i64, u64, u64, u64)> { + let mut prev_owner_start_time = i64::MIN; + let _ = self.ensure_owner_ready(&mut prev_owner_start_time).await?; + let guard = self.current_owner.read().await; + let owner = guard.as_ref().ok_or_else(|| { + KvError::SharedMem(SharedMemError::NotConfigured { + node_id: None, + detail: Some("Shared memory not ready".to_string()), + }) + })?; + Ok(( + owner.node_id.clone(), + owner.owner_start_time, + owner.shared_memory.as_ptr() as u64, + owner.shared_memory.as_ptr_ro() as u64, + owner.shared_memory.len(), + )) + } + async fn current_owner_snapshot(&self) -> Option<(String, i64, SharedMetaSignature)> { let guard = self.current_owner.read().await; let owner = guard.as_ref()?; @@ -842,11 +812,13 @@ impl ExternalInner { return Ok(false); }; - let share_mem_path = self.share_mem_path(); - let shared_meta_path = format!("{}/shared.json", share_mem_path); + let shared_memory_path = self.shared_memory_path(); + let shared_file_path = self.shared_file_path(); + let shared_meta_path = format!("{}/shared.json", shared_file_path); let probe = probe_owner_restart_payload( &self.view.clone_view(), - &share_mem_path, + &shared_memory_path, + &shared_file_path, &shared_meta_path, Some(¤t_signature), i64::MIN, @@ -865,7 +837,7 @@ impl ExternalInner { return Ok(false); } - self.finish_owner_recover(&share_mem_path, payload) + self.finish_owner_recover(&shared_memory_path, payload) .await?; Ok(true) } @@ -890,9 +862,16 @@ impl ExternalInner { } None } + + async fn try_get_local_complete_holder(&self, key: &str) -> Option> { + if let Some(holder) = self.try_get_from_weak_cache(key).await { + return Some(holder); + } + None + } // Removed trivial helper: inline-match OwnerStartTimeMismatch directly where needed. /// 获取共享内存基址(以 usize 表示的地址);未就绪时返回 NotConfigured - async fn base_ptr(&self) -> KvResult { + pub async fn base_ptr(&self) -> KvResult { let lock = self.current_owner.read().await; if let Some(o) = lock.as_ref() { return Ok(o.shared_memory.as_ptr() as usize); @@ -918,7 +897,7 @@ impl ExternalInner { match self.base_ptr().await { Ok(addr) => Ok(addr), Err(_) => { - let path = self.share_mem_path(); + let path = self.shared_memory_path(); let (st, addr) = self .wait_owner_recover_only(&path, *prev_owner_start_time) .await?; @@ -932,10 +911,10 @@ impl ExternalInner { async fn finish_owner_recover( &self, - share_mem_path: &str, + shared_memory_path: &str, payload: OwnerRestartPayload, ) -> KvResult<(i64, usize)> { - self.remap_shared_memory_with_payload(share_mem_path, &payload) + self.remap_shared_memory_with_payload(shared_memory_path, &payload) .await?; self.view .cluster_manager() @@ -949,18 +928,16 @@ impl ExternalInner { .set_self_sub_cluster(payload.meta.sub_cluster.clone()) .await .map_err(KvError::from)?; - self.wait_initial_control_plane_ready("owner_recover") - .await?; let base_addr = self.base_ptr().await?; Ok((self.current_owner_start_time().await, base_addr)) } async fn wait_owner_recover_only( &self, - share_mem_path: &str, + shared_memory_path: &str, prev_owner_start_time: i64, ) -> KvResult<(i64, usize)> { - self.wait_owner_recover(share_mem_path, prev_owner_start_time) + self.wait_owner_recover(shared_memory_path, prev_owner_start_time) .await } @@ -968,7 +945,7 @@ impl ExternalInner { &self, prev_owner_start_time: &mut i64, ) -> KvResult { - let path = self.share_mem_path(); + let path = self.shared_memory_path(); let (st, addr) = self .wait_owner_recover_only(&path, *prev_owner_start_time) .await?; @@ -984,7 +961,7 @@ impl ExternalInner { return match self.base_ptr().await { Ok(addr) => Ok(addr), Err(_) => { - let path = self.share_mem_path(); + let path = self.shared_memory_path(); let (st, addr) = self .wait_owner_recover_only(&path, *prev_owner_start_time) .await?; @@ -994,7 +971,7 @@ impl ExternalInner { }; } - let path = self.share_mem_path(); + let path = self.shared_memory_path(); let (st, addr) = self .wait_owner_recover_only(&path, *prev_owner_start_time) .await?; @@ -1006,7 +983,7 @@ impl ExternalInner { /// has advanced. async fn wait_owner_recover( &self, - _share_mem_path: &str, + _shared_memory_path: &str, prev_owner_start_time: i64, ) -> KvResult<(i64, usize)> { if let Some(res) = self @@ -1087,11 +1064,11 @@ impl ExternalInner { async fn remap_shared_memory_with_payload( &self, - share_mem_path: &str, + shared_memory_path: &str, payload: &OwnerRestartPayload, ) -> KvResult<()> { let shared_memory = Self::init_shared_memory_from_meta( - share_mem_path, + shared_memory_path, &payload.meta, payload.signature.clone(), )?; @@ -1209,11 +1186,11 @@ impl ExternalInner { } fn init_shared_memory_from_meta( - share_mem_path: &str, + shared_memory_path: &str, meta: &SharedJsonMeta, memory_signature: SharedMetaSignature, ) -> KvResult> { - let mmap_file_path = format!("{}/mmap.file", share_mem_path); + let mmap_file_path = format!("{}/mmap.file", shared_memory_path); Self::init_shared_memory(&mmap_file_path, meta.segment_len, memory_signature) } /// Get the shared storage node ID this client connects to @@ -1224,12 +1201,14 @@ impl ExternalInner { /// Get the configured shared-memory base path (external mode). /// Non-external modes return empty string. - pub fn share_mem_path(&self) -> String { - self.external_share_mem_path.clone() + pub fn shared_memory_path(&self) -> String { + self.external_shared_memory_path.clone() } - pub fn large_file_paths(&self) -> &crate::config::LargeFilePaths { - &self.external_large_file_paths + /// Get the configured shared-file base path (external mode). + /// Non-external modes return empty string. + pub fn shared_file_path(&self) -> String { + self.external_shared_file_path.clone() } fn should_fallback_side_p2p_error(err: &crate::p2p::P2PError) -> bool { @@ -1267,7 +1246,7 @@ impl ExternalInner { // require an extra enable flag once the owner has published ready lanes. let owner_id = self.shared_storage_node_id().await?; let owner_start_time = self.current_owner_start_time().await; - let peers_dir = ClientSegPool::side_transfer_peers_dir(&self.external_share_mem_path); + let peers_dir = ClientSegPool::side_transfer_peers_dir(&self.external_shared_file_path); let entries = std::fs::read_dir(&peers_dir).ok()?; let mut ready = Vec::new(); for entry in entries.flatten() { @@ -1372,10 +1351,151 @@ impl ExternalInner { } } - fn short_circuit_put_payload_path_enabled(&self) -> bool { + pub fn short_circuit_put_payload_path_enabled(&self) -> bool { self.short_circuit_put_payload_path } + pub async fn external_batch_put_start_rpc( + &self, + req: ExternalBatchPutStartReq, + ) -> KvResult { + let owner = self.shared_storage_node_id().await.ok_or_else(|| { + KvError::SharedMem(SharedMemError::NotConfigured { + node_id: None, + detail: Some("Shared storage node id unavailable".to_string()), + }) + })?; + let resp = self + .rpc_caller_external_batch_put_start + .call_with_transport_policy( + self.view.p2p_module(), + owner.into(), + MsgPack { + serialize_part: req, + raw_bytes: Vec::new(), + }, + Some(Duration::from_secs(EXTERNAL_PUT_START_RPC_TIMEOUT_SECS)), + RpcTransportPolicy::ForceTransport, + 0, + ) + .await + .map_err(KvError::from)?; + if resp.serialize_part.error_code != crate::rpcresp_kvresult_convert::msg_and_error::OK { + return Err(KvError::from_json( + resp.serialize_part.error_code, + &resp.serialize_part.error_json, + )); + } + Ok(resp.serialize_part) + } + + pub async fn external_batch_put_transfer_end_rpc( + &self, + req: ExternalBatchPutTransferEndReq, + ) -> KvResult { + let owner = self.shared_storage_node_id().await.ok_or_else(|| { + KvError::SharedMem(SharedMemError::NotConfigured { + node_id: None, + detail: Some("Shared storage node id unavailable".to_string()), + }) + })?; + let resp = self + .rpc_caller_external_batch_put_transfer_end + .call_with_transport_policy( + self.view.p2p_module(), + owner.into(), + MsgPack { + serialize_part: req, + raw_bytes: Vec::new(), + }, + Some(Duration::from_secs( + EXTERNAL_PUT_TRANSFER_END_RPC_TIMEOUT_SECS, + )), + RpcTransportPolicy::ForceTransport, + 0, + ) + .await + .map_err(KvError::from)?; + if resp.serialize_part.error_code != crate::rpcresp_kvresult_convert::msg_and_error::OK { + return Err(KvError::from_json( + resp.serialize_part.error_code, + &resp.serialize_part.error_json, + )); + } + Ok(resp.serialize_part) + } + + pub async fn external_batch_put_commit_rpc( + &self, + req: ExternalBatchPutCommitReq, + ) -> KvResult { + let owner = self.shared_storage_node_id().await.ok_or_else(|| { + KvError::SharedMem(SharedMemError::NotConfigured { + node_id: None, + detail: Some("Shared storage node id unavailable".to_string()), + }) + })?; + let resp = self + .rpc_caller_external_batch_put_commit + .call_with_transport_policy( + self.view.p2p_module(), + owner.into(), + MsgPack { + serialize_part: req, + raw_bytes: Vec::new(), + }, + Some(Duration::from_secs( + EXTERNAL_PUT_TRANSFER_END_RPC_TIMEOUT_SECS, + )), + RpcTransportPolicy::ForceTransport, + 0, + ) + .await + .map_err(KvError::from)?; + if resp.serialize_part.error_code != crate::rpcresp_kvresult_convert::msg_and_error::OK { + return Err(KvError::from_json( + resp.serialize_part.error_code, + &resp.serialize_part.error_json, + )); + } + Ok(resp.serialize_part) + } + + pub async fn external_put_revoke_rpc( + &self, + req: ExternalPutRevokeReq, + ) -> KvResult { + let owner = self.shared_storage_node_id().await.ok_or_else(|| { + KvError::SharedMem(SharedMemError::NotConfigured { + node_id: None, + detail: Some("Shared storage node id unavailable".to_string()), + }) + })?; + let resp = self + .rpc_caller_external_put_revoke + .call( + self.view.p2p_module(), + owner.into(), + MsgPack { + serialize_part: req, + raw_bytes: Vec::new(), + }, + Some(Duration::from_secs( + EXTERNAL_PUT_TRANSFER_END_RPC_TIMEOUT_SECS, + )), + 0, + ) + .await + .map_err(KvError::from)?; + if resp.serialize_part.error_code != crate::rpcresp_kvresult_convert::msg_and_error::OK { + return Err(KvError::from_json( + resp.serialize_part.error_code, + &resp.serialize_part.error_json, + )); + } + Ok(resp.serialize_part) + } + async fn call_put_start_with_side_fallback( &self, owner_id: String, @@ -1523,21 +1643,52 @@ impl ExternalInner { .map_err(KvError::from) } - /// Check if a key exists in the external storage (loop+wait) - pub async fn is_exist(&self, key: &str) -> KvResult { - tracing::debug!("External is_exist request for key: {}", key); + /// Check a batch of keys in the external storage (loop+wait). + pub async fn batch_is_exist( + &self, + keys: Vec, + allow_local_snapshot: bool, + ) -> KvResult> { + tracing::debug!( + "External batch_is_exist request: batch_len={}, allow_local_snapshot={}", + keys.len(), + allow_local_snapshot + ); + if keys.is_empty() { + return Ok(Vec::new()); + } + let mut prev_owner_start_time = self.current_owner_start_time().await; let mut recover_attempts = 0usize; if self.base_ptr().await.is_err() { - let path = self.share_mem_path(); - tracing::info!("ExternalClientApi.is_exist waiting for owner at: {}", path); + let path = self.shared_memory_path(); + tracing::info!( + "ExternalClientApi.batch_is_exist waiting for owner at: {}", + path + ); let _ = self.ensure_owner_ready(&mut prev_owner_start_time).await?; } loop { + let mut results = vec![false; keys.len()]; + let mut missing_indices = Vec::new(); + let mut missing_keys = Vec::new(); + for (idx, key) in keys.iter().enumerate() { + if allow_local_snapshot && self.try_get_local_complete_holder(key).await.is_some() { + results[idx] = true; + continue; + } + missing_indices.push(idx); + missing_keys.push(key.clone()); + } + if missing_keys.is_empty() { + return Ok(results); + } + let req = MsgPack { - serialize_part: ExternalIsExistReq { - key: key.to_string(), + serialize_part: ExternalBatchIsExistReq { + keys: missing_keys.clone(), + allow_local_snapshot, started_time: self.current_owner_start_time().await, }, raw_bytes: Vec::new(), @@ -1550,7 +1701,7 @@ impl ExternalInner { }) })?; let resp = match self - .rpc_caller_external_is_exist + .rpc_caller_external_batch_is_exist .call(self.view.p2p_module(), owner.into(), req, None, 0) .await { @@ -1562,8 +1713,8 @@ impl ExternalInner { { recover_attempts += 1; tracing::warn!( - "is_exist: transient P2P error; retrying after owner-state recovery check: key={}, attempt={}/{}, err={}", - key, + "batch_is_exist: transient P2P error; retrying after owner-state recovery check: batch_len={}, attempt={}/{}, err={}", + keys.len(), recover_attempts, EXTERNAL_RPC_P2P_RECOVER_MAX_ATTEMPTS, err @@ -1578,10 +1729,28 @@ impl ExternalInner { }; match resp.serialize_part.to_result() { - Ok(exists) => break Ok(exists), + Ok(exists_list) => { + if exists_list.len() != missing_indices.len() { + break Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external batch_is_exist response length mismatch: expected={} got={}", + missing_indices.len(), + exists_list.len() + ), + })); + } + for (idx, exists) in + missing_indices.iter().copied().zip(exists_list.into_iter()) + { + results[idx] = exists; + } + break Ok(results); + } Err(e) => { if matches!(&e, KvError::Api(ApiError::OwnerStartTimeMismatch { .. })) { - tracing::warn!("is_exist: OwnerStartTimeMismatch; remapping and retrying"); + tracing::warn!( + "batch_is_exist: OwnerStartTimeMismatch; remapping and retrying" + ); let _ = self .recover_after_owner_start_time_mismatch(&mut prev_owner_start_time) .await?; @@ -1592,8 +1761,8 @@ impl ExternalInner { { recover_attempts += 1; tracing::warn!( - "is_exist: transient P2P error; retrying after owner-state recovery check: key={}, attempt={}/{}, err={}", - key, + "batch_is_exist: transient P2P error; retrying after owner-state recovery check: batch_len={}, attempt={}/{}, err={}", + keys.len(), recover_attempts, EXTERNAL_RPC_P2P_RECOVER_MAX_ATTEMPTS, e @@ -1603,88 +1772,725 @@ impl ExternalInner { .await?; continue; } - tracing::warn!("External is_exist failed for key: {}, error: {}", key, e); + tracing::warn!( + "External batch_is_exist failed for batch_len {}: {}", + keys.len(), + e + ); break Err(e); } } } } - /// External Get operation (outer): retry + wait wrapper around get_inner - pub async fn get( - &self, - key: &str, - ) -> KvResult>> { - tracing::debug!("External get request for key: {}", key); - - // Ensure external mode configured; if not, block until owner is ready once + pub async fn observability_snapshot(&self) -> KvResult { let mut prev_owner_start_time = self.current_owner_start_time().await; - if self.base_ptr().await.is_err() { - let path = self.share_mem_path(); + let mut recover_attempts = 0usize; + if self.base_ptr_ro().await.is_err() { + let path = self.shared_memory_path(); tracing::info!( - "ExternalClientApi.get detected unmapped shared memory; waiting at: {}", + "ExternalClientApi.observability_snapshot waiting for owner at: {}", path ); let _ = self.ensure_owner_ready(&mut prev_owner_start_time).await?; } - // 1) Fast path: try weak-index lookup first - if let Some(h) = self.try_get_from_weak_cache(key).await { - return Ok(Some(h)); - } - - // 2) Ensure only one inflight get() per key using a keyed semaphore (permits=1) - tracing::debug!( - "External get request for key: {} acquire inflight semaphore", - key - ); - let permit = self.inflight1_per_key.acquire(key.to_string()).await; - - // 3) Re-check weak cache after acquiring the per-key lock - if let Some(h) = self.try_get_from_weak_cache(key).await { - tracing::debug!( - "External get request for key: {} hit by other inflight", - key - ); - drop(permit); - return Ok(Some(h)); - } - - let mut recover_attempts: usize = 0; - loop { - tracing::debug!( - "External get request for key: {} inflight get start once", - key - ); - match self.get_inner(key, prev_owner_start_time).await { - Ok(v) => { - // Update weak index on success if Some - if let Some(ref h) = v { - // let hex= &h.bytes()[..std::cmp::min(16, h.len as usize)]; - // tracing::info!("external get done, key={}, partial_hex={:?}", key, hex); - self.key_weak_memholder_index - .insert(key.to_string(), Arc::downgrade(h)); - } else { - tracing::debug!("external get no key={}", key); - } - drop(permit); - break Ok(v); - } - Err(e) => { - if matches!(&e, KvError::Api(ApiError::OwnerStartTimeMismatch { .. })) { - tracing::warn!("get: OwnerStartTimeMismatch; remapping and retrying"); - let _ = self - .recover_after_owner_start_time_mismatch(&mut prev_owner_start_time) - .await?; - continue; - } - if matches!(&e, KvError::P2p(_)) - && recover_attempts < EXTERNAL_RPC_P2P_RECOVER_MAX_ATTEMPTS - { - recover_attempts += 1; - tracing::warn!( - "get: transient P2P error; retrying after owner-state recovery check: \ + let owner = self.shared_storage_node_id().await.ok_or_else(|| { + KvError::SharedMem(SharedMemError::NotConfigured { + node_id: None, + detail: Some("Shared storage node id unavailable".to_string()), + }) + })?; + let req = MsgPack { + serialize_part: ExternalObservabilitySnapshotReq { + started_time: self.current_owner_start_time().await, + }, + raw_bytes: Vec::new(), + }; + let resp = match self + .rpc_caller_external_observability_snapshot + .call(self.view.p2p_module(), owner.into(), req, None, 0) + .await + { + Ok(resp) => resp, + Err(e) => { + let err = KvError::from(e); + if matches!(&err, KvError::P2p(_)) + && recover_attempts < EXTERNAL_RPC_P2P_RECOVER_MAX_ATTEMPTS + { + recover_attempts += 1; + tracing::warn!( + "observability_snapshot: transient P2P error; retrying after owner-state recovery check: attempt={}/{}, err={}", + recover_attempts, + EXTERNAL_RPC_P2P_RECOVER_MAX_ATTEMPTS, + err + ); + let _ = self + .recover_after_p2p_error(&mut prev_owner_start_time) + .await?; + continue; + } + return Err(err); + } + }; + if resp.serialize_part.error_code != crate::rpcresp_kvresult_convert::msg_and_error::OK + { + let err = KvError::from_json( + resp.serialize_part.error_code, + &resp.serialize_part.error_json, + ); + if matches!(&err, KvError::Api(ApiError::OwnerStartTimeMismatch { .. })) { + tracing::warn!( + "observability_snapshot: OwnerStartTimeMismatch; remapping and retrying" + ); + let _ = self + .recover_after_owner_start_time_mismatch(&mut prev_owner_start_time) + .await?; + continue; + } + if matches!(&err, KvError::P2p(_)) + && recover_attempts < EXTERNAL_RPC_P2P_RECOVER_MAX_ATTEMPTS + { + recover_attempts += 1; + tracing::warn!( + "observability_snapshot: transient P2P error in response; retrying after owner-state recovery check: attempt={}/{}, err={}", + recover_attempts, + EXTERNAL_RPC_P2P_RECOVER_MAX_ATTEMPTS, + err + ); + let _ = self + .recover_after_p2p_error(&mut prev_owner_start_time) + .await?; + continue; + } + return Err(err); + } + return Ok(resp.serialize_part.into_snapshot()); + } + } + + pub async fn batch_get_start( + &self, + keys: Vec, + prefix_best_effort: bool, + atomic_group_lens: Option>, + transfer_concurrency: usize, + ) -> KvResult { + tracing::debug!( + "External batch_get_start request: batch_len={}, prefix_best_effort={}, transfer_concurrency={}", + keys.len(), + prefix_best_effort, + transfer_concurrency + ); + if keys.is_empty() { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: "ExternalClientApi.batch_get_start requires at least one key".to_string(), + })); + } + + let mut prev_owner_start_time = self.current_owner_start_time().await; + let mut recover_attempts = 0usize; + if self.base_ptr_ro().await.is_err() { + let path = self.shared_memory_path(); + tracing::info!( + "ExternalClientApi.batch_get_start waiting for owner at: {}", + path + ); + let _ = self.ensure_owner_ready(&mut prev_owner_start_time).await?; + } + + loop { + let owner = self.shared_storage_node_id().await.ok_or_else(|| { + KvError::SharedMem(SharedMemError::NotConfigured { + node_id: None, + detail: Some("Shared storage node id unavailable".to_string()), + }) + })?; + let req = MsgPack { + serialize_part: ExternalBatchGetStartReq { + keys: keys.clone(), + req_node_id: self.view.cluster_manager().get_self_info().id.clone(), + started_time: self.current_owner_start_time().await, + prefix_best_effort, + atomic_group_lens: atomic_group_lens.clone(), + transfer_concurrency, + }, + raw_bytes: Vec::new(), + }; + let resp = match self + .rpc_caller_external_batch_get_start + .call(self.view.p2p_module(), owner.into(), req, None, 0) + .await + { + Ok(resp) => resp, + Err(e) => { + let err = KvError::from(e); + if matches!(&err, KvError::P2p(_)) + && recover_attempts < EXTERNAL_RPC_P2P_RECOVER_MAX_ATTEMPTS + { + recover_attempts += 1; + tracing::warn!( + "batch_get_start: transient P2P error; retrying after owner-state recovery check: batch_len={}, attempt={}/{}, err={}", + keys.len(), + recover_attempts, + EXTERNAL_RPC_P2P_RECOVER_MAX_ATTEMPTS, + err + ); + let _ = self + .recover_after_p2p_error(&mut prev_owner_start_time) + .await?; + continue; + } + return Err(err); + } + }; + if resp.serialize_part.error_code != OK { + let err = KvError::from_json( + resp.serialize_part.error_code, + &resp.serialize_part.error_json, + ); + if matches!(&err, KvError::Api(ApiError::OwnerStartTimeMismatch { .. })) { + tracing::warn!( + "batch_get_start: OwnerStartTimeMismatch; remapping and retrying" + ); + let _ = self + .recover_after_owner_start_time_mismatch(&mut prev_owner_start_time) + .await?; + continue; + } + return Err(err); + } + return Ok(resp.serialize_part); + } + } + + pub async fn batch_get_transfer( + &self, + handle: u64, + keys: Vec, + ) -> KvResult>>>> { + tracing::debug!( + "External batch_get_transfer request: handle={}, batch_len={}", + handle, + keys.len() + ); + if keys.is_empty() { + return Ok(Vec::new()); + } + + let mut prev_owner_start_time = self.current_owner_start_time().await; + if self.base_ptr_ro().await.is_err() { + let path = self.shared_memory_path(); + tracing::info!( + "ExternalClientApi.batch_get_transfer waiting for owner at: {}", + path + ); + let _ = self.ensure_owner_ready(&mut prev_owner_start_time).await?; + } + + let started_time = self.current_owner_start_time().await; + let base_ptr = self.base_ptr_ro().await.expect( + "ExternalClientApi.batch_get_transfer requires shared memory to be ready after ensure_owner_ready", + ) as u64; + let owner = self.shared_storage_node_id().await.ok_or_else(|| { + KvError::SharedMem(SharedMemError::NotConfigured { + node_id: None, + detail: Some("Shared storage node id unavailable".to_string()), + }) + })?; + let req = MsgPack { + serialize_part: ExternalBatchGetTransferReq { + handle, + req_node_id: self.view.cluster_manager().get_self_info().id.clone(), + started_time, + }, + raw_bytes: Vec::new(), + }; + let resp: MsgPack = self + .rpc_caller_external_batch_get_transfer + .call(self.view.p2p_module(), owner.into(), req, None, 0) + .await + .map_err(KvError::from)?; + if resp.serialize_part.error_code != OK { + return Err(KvError::from_json( + resp.serialize_part.error_code, + &resp.serialize_part.error_json, + )); + } + if resp.serialize_part.items.len() != keys.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external batch_get_transfer response length mismatch: expected={} got={}", + keys.len(), + resp.serialize_part.items.len() + ), + })); + } + + let bandwidth_handle = self + .view + .cluster_manager() + .ipc_bandwidth_attributor_handle() + .expect("ExternalClientApi.batch_get_transfer expects IpcBandwidthAttributor handle to be attached"); + let mut results = Vec::with_capacity(keys.len()); + for (key, item) in keys.into_iter().zip(resp.serialize_part.items.into_iter()) { + if item.error_code == OK { + match item.external_memholder_info { + Some(info) => { + if info.len > 0 { + bandwidth_handle.record_tx_bytes(info.len as u64); + } + let holder = Arc::new(ExternalMemHolder::new( + info.offset, + base_ptr + info.offset, + info.len, + info.holder_id, + key.clone(), + self.view.cluster_manager().get_self_info().id.clone(), + self.view.clone(), + started_time, + )); + self.key_weak_memholder_index + .insert(key, Arc::downgrade(&holder)); + results.push(Ok(Some(holder))); + } + None => results.push(Ok(None)), + } + continue; + } + if item.error_code + == crate::rpcresp_kvresult_convert::msg_and_error::codes_api::API_KEY_NOT_FOUND + { + results.push(Ok(None)); + continue; + } + results.push(Err(KvError::from_json(item.error_code, &item.error_json))); + } + Ok(results) + } + + pub async fn cancel_batch_get_start(&self, handle: u64) -> KvResult<()> { + tracing::debug!("External cancel_batch_get_start request: handle={}", handle); + let started_time = self.current_owner_start_time().await; + let owner = self.shared_storage_node_id().await.ok_or_else(|| { + KvError::SharedMem(SharedMemError::NotConfigured { + node_id: None, + detail: Some("Shared storage node id unavailable".to_string()), + }) + })?; + let req = MsgPack { + serialize_part: ExternalBatchGetCancelReq { + handle, + req_node_id: self.view.cluster_manager().get_self_info().id.clone(), + started_time, + }, + raw_bytes: Vec::new(), + }; + let resp = self + .rpc_caller_external_batch_get_cancel + .call(self.view.p2p_module(), owner.into(), req, None, 0) + .await + .map_err(KvError::from)?; + if resp.serialize_part.error_code == OK { + return Ok(()); + } + let err = KvError::from_json( + resp.serialize_part.error_code, + &resp.serialize_part.error_json, + ); + if matches!(&err, KvError::Api(ApiError::OwnerStartTimeMismatch { .. })) { + tracing::info!( + "cancel_batch_get_start: owner start_time mismatch; owner restarted, treating handle as gone" + ); + return Ok(()); + } + Err(err) + } + + pub async fn get_start( + &self, + keys: Vec, + prefix_best_effort: bool, + atomic_group_lens: Option>, + transfer_concurrency: usize, + ) -> KvResult { + if keys.is_empty() { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: "ExternalClientApi.get_start requires at least one key".to_string(), + })); + } + let started = self + .batch_get_start( + keys.clone(), + prefix_best_effort, + atomic_group_lens.clone(), + transfer_concurrency, + ) + .await?; + if started.raw_prefix_hit_len > keys.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "ExternalClientApi.get_start prefix response out of range: raw_prefix_hit_len={} keys={}", + started.raw_prefix_hit_len, + keys.len() + ), + })); + } + let group_lens = normalize_external_get_start_group_lens(keys.len(), atomic_group_lens)?; + let transferable_len = compute_external_get_start_transfer_prefix( + started.raw_prefix_hit_len, + &group_lens, + prefix_best_effort, + ); + let first_miss_index = if started.raw_prefix_hit_len < keys.len() { + Some(started.raw_prefix_hit_len) + } else { + None + }; + + self.pending_external_get_start.insert( + started.handle, + PendingExternalGetStart { + keys: keys.clone(), + transferable_len, + first_miss_index, + }, + ); + + Ok(ExternalClientGetStartResp { + handle: started.handle, + raw_prefix_hit_len: started.raw_prefix_hit_len, + }) + } + + pub async fn get_transfer( + &self, + handle: u64, + ) -> KvResult>>>> { + let Some((_handle, entry)) = self.pending_external_get_start.remove(&handle) else { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!("get_transfer requires a live get-start handle: {}", handle), + })); + }; + if entry.transferable_len == 0 { + let _ = self.cancel_batch_get_start(handle).await; + let key = entry + .first_miss_index + .and_then(|idx| entry.keys.get(idx).cloned()) + .unwrap_or_else(|| format!("external_get_start_handle:{}", handle)); + return Err(KvError::Api(ApiError::KeyNotFound { key })); + } + if entry.transferable_len > entry.keys.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "get_transfer stored prefix out of range: transferable_len={} keys={}", + entry.transferable_len, + entry.keys.len() + ), + })); + } + self.batch_get_transfer(handle, entry.keys[..entry.transferable_len].to_vec()) + .await + } + + pub async fn cancel_get_transfer(&self, handle: u64) -> KvResult<()> { + let removed = self.pending_external_get_start.remove(&handle); + if removed.is_none() { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "cancel_get_transfer requires a live get-start handle: {}", + handle + ), + })); + } + self.cancel_batch_get_start(handle).await + } + + pub async fn batch_get( + &self, + keys: Vec, + transfer_concurrency: usize, + ) -> KvResult>>>> { + tracing::debug!( + "External batch_get request: batch_len={}, transfer_concurrency={}", + keys.len(), + transfer_concurrency + ); + if keys.is_empty() { + return Ok(Vec::new()); + } + + let mut prev_owner_start_time = self.current_owner_start_time().await; + let mut recover_attempts = 0usize; + if self.base_ptr_ro().await.is_err() { + let path = self.shared_memory_path(); + tracing::info!("ExternalClientApi.batch_get waiting for owner at: {}", path); + let _ = self.ensure_owner_ready(&mut prev_owner_start_time).await?; + } + + let mut results: Vec>>>> = + (0..keys.len()).map(|_| None).collect(); + let mut missing_indices = Vec::new(); + let mut missing_keys = Vec::new(); + for (idx, key) in keys.iter().enumerate() { + if let Some(holder) = self.try_get_from_weak_cache(key).await { + results[idx] = Some(Ok(Some(holder))); + continue; + } + missing_indices.push(idx); + missing_keys.push(key.clone()); + } + if missing_keys.is_empty() { + return Ok(results + .into_iter() + .map(|item| { + item.unwrap_or_else(|| { + Err(KvError::Api(ApiError::Unknown { + detail: "external batch_get result slot was not populated".to_string(), + })) + }) + }) + .collect()); + } + + loop { + let started_time = self.current_owner_start_time().await; + let base_ptr = self.base_ptr_ro().await.expect( + "ExternalClientApi.batch_get requires shared memory to be ready after ensure_owner_ready", + ) as u64; + let req = MsgPack { + serialize_part: ExternalBatchGetReq { + keys: missing_keys.clone(), + req_node_id: self.view.cluster_manager().get_self_info().id.clone(), + started_time, + transfer_concurrency, + }, + raw_bytes: Vec::new(), + }; + let owner = self.shared_storage_node_id().await.ok_or_else(|| { + KvError::SharedMem(SharedMemError::NotConfigured { + node_id: None, + detail: Some("Shared storage node id unavailable".to_string()), + }) + })?; + let resp = match self + .rpc_caller_external_batch_get + .call(self.view.p2p_module(), owner.into(), req, None, 0) + .await + { + Ok(resp) => resp, + Err(e) => { + let err = KvError::from(e); + if matches!(&err, KvError::P2p(_)) + && recover_attempts < EXTERNAL_RPC_P2P_RECOVER_MAX_ATTEMPTS + { + recover_attempts += 1; + tracing::warn!( + "batch_get: transient P2P error; retrying after owner-state recovery check: batch_len={}, attempt={}/{}, err={}", + keys.len(), + recover_attempts, + EXTERNAL_RPC_P2P_RECOVER_MAX_ATTEMPTS, + err + ); + let _ = self + .recover_after_p2p_error(&mut prev_owner_start_time) + .await?; + continue; + } + return Err(err); + } + }; + if resp.serialize_part.error_code != crate::rpcresp_kvresult_convert::msg_and_error::OK + { + let err = KvError::from_json( + resp.serialize_part.error_code, + &resp.serialize_part.error_json, + ); + if matches!(&err, KvError::Api(ApiError::OwnerStartTimeMismatch { .. })) { + tracing::warn!("batch_get: OwnerStartTimeMismatch; remapping and retrying"); + let _ = self + .recover_after_owner_start_time_mismatch(&mut prev_owner_start_time) + .await?; + continue; + } + if matches!(&err, KvError::P2p(_)) + && recover_attempts < EXTERNAL_RPC_P2P_RECOVER_MAX_ATTEMPTS + { + recover_attempts += 1; + tracing::warn!( + "batch_get: transient P2P error; retrying after owner-state recovery check: batch_len={}, attempt={}/{}, err={}", + keys.len(), + recover_attempts, + EXTERNAL_RPC_P2P_RECOVER_MAX_ATTEMPTS, + err + ); + let _ = self + .recover_after_p2p_error(&mut prev_owner_start_time) + .await?; + continue; + } + return Err(err); + } + if resp.serialize_part.items.len() != missing_indices.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external batch_get response length mismatch: expected={} got={}", + missing_indices.len(), + resp.serialize_part.items.len() + ), + })); + } + + let handle = self + .view + .cluster_manager() + .ipc_bandwidth_attributor_handle() + .expect("ExternalClientApi.batch_get expects IpcBandwidthAttributor handle to be attached"); + for (idx, item) in missing_indices + .iter() + .copied() + .zip(resp.serialize_part.items.into_iter()) + { + if item.error_code == crate::rpcresp_kvresult_convert::msg_and_error::OK { + match item.external_memholder_info { + Some(info) => { + if info.len > 0 { + handle.record_tx_bytes(info.len as u64); + } + let holder = Arc::new(ExternalMemHolder::new( + info.offset, + base_ptr + info.offset, + info.len, + info.holder_id, + keys[idx].clone(), + self.view.cluster_manager().get_self_info().id.clone(), + self.view.clone(), + started_time, + )); + self.key_weak_memholder_index + .insert(keys[idx].clone(), Arc::downgrade(&holder)); + results[idx] = Some(Ok(Some(holder))); + } + None => { + results[idx] = Some(Ok(None)); + } + } + continue; + } + if item.error_code + == crate::rpcresp_kvresult_convert::msg_and_error::codes_api::API_KEY_NOT_FOUND + { + results[idx] = Some(Ok(None)); + continue; + } + results[idx] = Some(Err(KvError::from_json(item.error_code, &item.error_json))); + } + + return Ok(results + .into_iter() + .map(|item| { + item.unwrap_or_else(|| { + Err(KvError::Api(ApiError::Unknown { + detail: "external batch_get result slot was not populated".to_string(), + })) + }) + }) + .collect()); + } + } + + pub async fn is_exist_with_local_snapshot( + &self, + key: &str, + allow_local_snapshot: bool, + ) -> KvResult { + let mut results = self + .batch_is_exist(vec![key.to_string()], allow_local_snapshot) + .await?; + Ok(results.pop().unwrap_or(false)) + } + + /// Check if a key exists in the external storage (loop+wait) + pub async fn is_exist(&self, key: &str) -> KvResult { + self.is_exist_with_local_snapshot(key, false).await + } + + /// External Get operation (outer): retry + wait wrapper around get_inner + pub async fn get( + &self, + key: &str, + ) -> KvResult>> { + tracing::debug!("External get request for key: {}", key); + + // Ensure external mode configured; if not, block until owner is ready once + let mut prev_owner_start_time = self.current_owner_start_time().await; + if self.base_ptr().await.is_err() { + let path = self.shared_memory_path(); + tracing::info!( + "ExternalClientApi.get detected unmapped shared memory; waiting at: {}", + path + ); + let _ = self.ensure_owner_ready(&mut prev_owner_start_time).await?; + } + + // 1) Fast path: try weak-index lookup first + if let Some(h) = self.try_get_from_weak_cache(key).await { + return Ok(Some(h)); + } + + // 2) Ensure only one inflight get() per key using a keyed semaphore (permits=1) + tracing::debug!( + "External get request for key: {} acquire inflight semaphore", + key + ); + let permit = self.inflight1_per_key.acquire(key.to_string()).await; + + // 3) Re-check weak cache after acquiring the per-key lock + if let Some(h) = self.try_get_from_weak_cache(key).await { + tracing::debug!( + "External get request for key: {} hit by other inflight", + key + ); + drop(permit); + return Ok(Some(h)); + } + + let mut recover_attempts: usize = 0; + + loop { + tracing::debug!( + "External get request for key: {} inflight get start once", + key + ); + match self.get_inner(key, prev_owner_start_time).await { + Ok(v) => { + // Update weak index on success if Some + if let Some(ref h) = v { + // let hex= &h.bytes()[..std::cmp::min(16, h.len as usize)]; + // tracing::info!("external get done, key={}, partial_hex={:?}", key, hex); + self.key_weak_memholder_index + .insert(key.to_string(), Arc::downgrade(h)); + } else { + tracing::debug!("external get no key={}", key); + } + drop(permit); + break Ok(v); + } + Err(e) => { + if matches!(&e, KvError::Api(ApiError::OwnerStartTimeMismatch { .. })) { + tracing::warn!("get: OwnerStartTimeMismatch; remapping and retrying"); + let _ = self + .recover_after_owner_start_time_mismatch(&mut prev_owner_start_time) + .await?; + continue; + } + if matches!(&e, KvError::P2p(_)) + && recover_attempts < EXTERNAL_RPC_P2P_RECOVER_MAX_ATTEMPTS + { + recover_attempts += 1; + tracing::warn!( + "get: transient P2P error; retrying after owner-state recovery check: \ key={}, attempt={}/{}, err={}", key, recover_attempts, @@ -1803,6 +2609,8 @@ key={}, attempt={}/{}, err={}", ) -> KvResult<()> { let lease_id = opts.lease_id(); let reject_if_inflight_same_key = opts.reject_if_inflight_same_key(); + let reject_if_exist_same_key = opts.reject_if_exist_same_key(); + let write_through = opts.write_through(); let preferred_sub_cluster = opts.preferred_sub_cluster().map(|s| s.to_string()); let observe_sink = opts.test_observe_put_phases(); let observe_enabled = true; @@ -1816,7 +2624,7 @@ key={}, attempt={}/{}, err={}", let mut base_addr: usize = match self.base_ptr().await { Ok(addr) => addr, Err(_) => { - let path = self.share_mem_path(); + let path = self.shared_memory_path(); tracing::info!( "ExternalClientApi.put detected unmapped shared memory; waiting for owner to be ready at path: {}", path @@ -1838,6 +2646,8 @@ key={}, attempt={}/{}, err={}", base_addr, lease_id, reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, preferred_sub_cluster.as_deref(), observe_enabled, ) @@ -1890,6 +2700,8 @@ key={}, attempt={}/{}, err={}", ) -> KvResult<()> { let lease_id = opts.lease_id(); let reject_if_inflight_same_key = opts.reject_if_inflight_same_key(); + let reject_if_exist_same_key = opts.reject_if_exist_same_key(); + let write_through = opts.write_through(); let preferred_sub_cluster = opts.preferred_sub_cluster().map(|s| s.to_string()); let observe_sink = opts.test_observe_put_phases(); let observe_enabled = true; @@ -1905,7 +2717,7 @@ key={}, attempt={}/{}, err={}", let mut base_addr: usize = match self.base_ptr().await { Ok(addr) => addr, Err(_) => { - let path = self.share_mem_path(); + let path = self.shared_memory_path(); tracing::info!( "ExternalClientApi.put_flat_dict_ptrs detected unmapped shared memory; waiting for owner to be ready at path: {}", path @@ -1924,6 +2736,8 @@ key={}, attempt={}/{}, err={}", base_addr, lease_id, reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, preferred_sub_cluster.as_deref(), observe_enabled, ) @@ -1963,6 +2777,370 @@ key={}, attempt={}/{}, err={}", } } + pub async unsafe fn batch_put_flat_dict_ptrs( + &self, + keys: Vec, + ptrs_groups: Vec)>>, + opts: crate::client_kv_api::PutOptionalArgs, + transfer_concurrency: usize, + ) -> KvResult>> { + if keys.len() != ptrs_groups.len() { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "batch_put_flat_dict_ptrs requires keys and ptrs_groups to have the same length: keys={} ptrs_groups={}", + keys.len(), + ptrs_groups.len() + ), + })); + } + if keys.is_empty() { + return Ok(Vec::new()); + } + + let lease_id = opts.lease_id(); + let reject_if_inflight_same_key = opts.reject_if_inflight_same_key(); + let reject_if_exist_same_key = opts.reject_if_exist_same_key(); + let write_through = opts.write_through(); + let preferred_sub_cluster = opts.preferred_sub_cluster().map(|s| s.to_string()); + let mut payload_lens = Vec::with_capacity(ptrs_groups.len()); + for ptrs in ptrs_groups.iter() { + payload_lens.push(crate::memholder::kvclient_encode::calc_flat_dict_encoded_len(ptrs)?); + } + + let mut prev_owner_start_time = self.current_owner_start_time().await; + let mut base_addr: usize = match self.base_ptr().await { + Ok(addr) => addr, + Err(_) => { + let path = self.shared_memory_path(); + tracing::info!( + "ExternalClientApi.batch_put_flat_dict_ptrs waiting for owner at path: {}", + path + ); + self.ensure_owner_ready(&mut prev_owner_start_time).await? + } + }; + + loop { + match unsafe { + self.batch_put_inner_flat_dict_ptrs( + &keys, + &ptrs_groups, + &payload_lens, + prev_owner_start_time, + base_addr, + lease_id, + reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, + preferred_sub_cluster.as_deref(), + transfer_concurrency.max(1), + ) + .await + } { + Ok(results) => break Ok(results), + Err(e) => { + if matches!(&e, KvError::Api(ApiError::OwnerStartTimeMismatch { .. })) { + tracing::warn!( + "batch_put_flat_dict_ptrs: OwnerStartTimeMismatch; remapping and retrying" + ); + base_addr = self + .recover_after_owner_start_time_mismatch(&mut prev_owner_start_time) + .await?; + continue; + } + if matches!(&e, KvError::P2p(_)) { + tracing::warn!( + "batch_put_flat_dict_ptrs: P2P error (owner/link likely offline); retrying after owner-state recovery check: {}", + e + ); + base_addr = self + .recover_after_p2p_error(&mut prev_owner_start_time) + .await?; + continue; + } + break Err(e); + } + } + } + } + + async unsafe fn batch_put_inner_flat_dict_ptrs( + &self, + keys: &[String], + ptrs_groups: &[Vec<(u8, usize, u32, u64, u32, Option)>], + payload_lens: &[u64], + started_time: i64, + base_addr: usize, + lease_id: Option, + reject_if_inflight_same_key: bool, + reject_if_exist_same_key: bool, + write_through: bool, + preferred_sub_cluster: Option<&str>, + transfer_concurrency: usize, + ) -> KvResult>> { + let owner = self.shared_storage_node_id().await.ok_or_else(|| { + KvError::SharedMem(SharedMemError::NotConfigured { + node_id: None, + detail: Some("Shared storage node id unavailable".to_string()), + }) + })?; + let start_req = MsgPack { + serialize_part: ExternalBatchPutStartReq { + items: keys + .iter() + .zip(payload_lens.iter()) + .map(|(key, payload_len)| ExternalBatchPutStartItemReq { + key: key.clone(), + len: *payload_len, + reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, + preferred_sub_cluster: preferred_sub_cluster.map(|s| s.to_string()), + }) + .collect(), + started_time, + }, + raw_bytes: Vec::new(), + }; + let start_resp = self + .rpc_caller_external_batch_put_start + .call_with_transport_policy( + self.view.p2p_module(), + owner.clone().into(), + start_req, + Some(Duration::from_secs(EXTERNAL_PUT_START_RPC_TIMEOUT_SECS)), + RpcTransportPolicy::ForceTransport, + 0, + ) + .await + .map_err(KvError::from)?; + if start_resp.serialize_part.error_code + != crate::rpcresp_kvresult_convert::msg_and_error::OK + { + return Err(KvError::from_json( + start_resp.serialize_part.error_code, + &start_resp.serialize_part.error_json, + )); + } + if start_resp.serialize_part.items.len() != keys.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external batch_put_start response length mismatch: expected={} got={}", + keys.len(), + start_resp.serialize_part.items.len() + ), + })); + } + + let short_circuit_payload = self.short_circuit_put_payload_path_enabled(); + let mut results: Vec>> = (0..keys.len()).map(|_| None).collect(); + let mut commit_pending = Vec::new(); + let mut transfer_pending = Vec::new(); + let mut total_written_payload = 0u64; + + for (idx, (((key, ptrs), payload_len), start_item)) in keys + .iter() + .zip(ptrs_groups.iter()) + .zip(payload_lens.iter()) + .zip(start_resp.serialize_part.items.into_iter()) + .enumerate() + { + if start_item.error_code != crate::rpcresp_kvresult_convert::msg_and_error::OK { + results[idx] = Some(Err(KvError::from_json( + start_item.error_code, + &start_item.error_json, + ))); + continue; + } + let Some(put_id) = start_item.put_id else { + results[idx] = Some(Err(KvError::Unreachable( + crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::RpcDecodeError { + rpc_input_json: format!( + "missing put_id in external batch_put_start success response; key={}", + key + ), + }, + ))); + continue; + }; + + if short_circuit_payload { + commit_pending.push(( + idx, + ExternalBatchPutCommitItemReq { + key: key.clone(), + len: *payload_len, + src_offset: start_item.src_offset, + remote_target: start_item.peer_id.is_some(), + put_id: Some(put_id), + lease_id, + write_through, + }, + )); + continue; + } + + let write_ptr = (base_addr + start_item.target_offset as usize) as *mut u8; + unsafe { + crate::memholder::kvclient_encode::write_flat_dict_ptrs_to_ptr(write_ptr, ptrs); + } + total_written_payload = total_written_payload.saturating_add(*payload_len); + transfer_pending.push(( + idx, + ExternalBatchPutTransferEndItemReq { + key: key.clone(), + len: *payload_len, + src_offset: start_item.src_offset, + target_offset: start_item + .transfer_target_offset + .unwrap_or(start_item.target_offset), + peer_id: start_item.peer_id.clone(), + target_base_addr: if start_item.peer_id.is_some() { + Some(start_item.target_base_addr) + } else { + None + }, + put_id: Some(put_id), + write_through, + lease_id, + }, + )); + } + + if total_written_payload > 0 { + let handle = self + .view + .cluster_manager() + .ipc_bandwidth_attributor_handle() + .expect("ExternalClientApi.batch_put_flat_dict_ptrs expects IpcBandwidthAttributor handle to be attached"); + handle.record_rx_bytes(total_written_payload); + } + + if short_circuit_payload { + if !commit_pending.is_empty() { + let commit_resp = self + .rpc_caller_external_batch_put_commit + .call_with_transport_policy( + self.view.p2p_module(), + owner.into(), + MsgPack { + serialize_part: ExternalBatchPutCommitReq { + items: commit_pending + .iter() + .map(|(_, item)| item.clone()) + .collect(), + started_time, + }, + raw_bytes: Vec::new(), + }, + Some(Duration::from_secs( + EXTERNAL_PUT_TRANSFER_END_RPC_TIMEOUT_SECS, + )), + RpcTransportPolicy::ForceTransport, + 0, + ) + .await + .map_err(KvError::from)?; + if commit_resp.serialize_part.error_code + != crate::rpcresp_kvresult_convert::msg_and_error::OK + { + return Err(KvError::from_json( + commit_resp.serialize_part.error_code, + &commit_resp.serialize_part.error_json, + )); + } + if commit_resp.serialize_part.items.len() != commit_pending.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external batch_put_commit response length mismatch: expected={} got={}", + commit_pending.len(), + commit_resp.serialize_part.items.len() + ), + })); + } + for ((idx, _), item_resp) in commit_pending + .into_iter() + .zip(commit_resp.serialize_part.items.into_iter()) + { + if item_resp.error_code == crate::rpcresp_kvresult_convert::msg_and_error::OK { + results[idx] = Some(Ok(())); + } else { + results[idx] = Some(Err(KvError::from_json( + item_resp.error_code, + &item_resp.error_json, + ))); + } + } + } + } else if !transfer_pending.is_empty() { + let transfer_resp = self + .rpc_caller_external_batch_put_transfer_end + .call_with_transport_policy( + self.view.p2p_module(), + owner.into(), + MsgPack { + serialize_part: ExternalBatchPutTransferEndReq { + items: transfer_pending + .iter() + .map(|(_, item)| item.clone()) + .collect(), + started_time, + transfer_concurrency, + }, + raw_bytes: Vec::new(), + }, + Some(Duration::from_secs( + EXTERNAL_PUT_TRANSFER_END_RPC_TIMEOUT_SECS, + )), + RpcTransportPolicy::ForceTransport, + 0, + ) + .await + .map_err(KvError::from)?; + if transfer_resp.serialize_part.error_code + != crate::rpcresp_kvresult_convert::msg_and_error::OK + { + return Err(KvError::from_json( + transfer_resp.serialize_part.error_code, + &transfer_resp.serialize_part.error_json, + )); + } + if transfer_resp.serialize_part.items.len() != transfer_pending.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external batch_put_transfer_end response length mismatch: expected={} got={}", + transfer_pending.len(), + transfer_resp.serialize_part.items.len() + ), + })); + } + for ((idx, _), item_resp) in transfer_pending + .into_iter() + .zip(transfer_resp.serialize_part.items.into_iter()) + { + if item_resp.error_code == crate::rpcresp_kvresult_convert::msg_and_error::OK { + results[idx] = Some(Ok(())); + } else { + results[idx] = Some(Err(KvError::from_json( + item_resp.error_code, + &item_resp.error_json, + ))); + } + } + } + + Ok(results + .into_iter() + .map(|item| { + item.unwrap_or_else(|| { + Err(KvError::Api(ApiError::Unknown { + detail: "external batch_put result slot was not populated".to_string(), + })) + }) + }) + .collect()) + } + async unsafe fn put_inner_flat_dict_ptrs( &self, key: &str, @@ -1972,6 +3150,8 @@ key={}, attempt={}/{}, err={}", base_addr: usize, lease_id: Option, reject_if_inflight_same_key: bool, + reject_if_exist_same_key: bool, + write_through: bool, preferred_sub_cluster: Option<&str>, observe_enabled: bool, ) -> KvResult { @@ -1981,6 +3161,8 @@ key={}, attempt={}/{}, err={}", key: key.to_string(), len: payload_len, reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, preferred_sub_cluster: preferred_sub_cluster.map(|s| s.to_string()), started_time, test_observe_put_phases: true, @@ -1995,7 +3177,7 @@ key={}, attempt={}/{}, err={}", })?; let put_start_rpc_started_at = observe_enabled.then(Instant::now); let (put_resp, put_start_side) = self - .call_put_start_with_side_fallback(owner, put_start_req) + .call_put_start_with_side_fallback(owner.clone(), put_start_req) .await?; if let Some(started_at) = put_start_rpc_started_at { trace.external_put_start_rpc_us = duration_to_i64_us(started_at.elapsed()); @@ -2012,11 +3194,19 @@ key={}, attempt={}/{}, err={}", self.remember_side_transfer_binding(put_start_ok.put_id, put_start_side); if self.short_circuit_put_payload_path_enabled() { + let remote_target = put_start_ok + .peer_id + .as_deref() + .is_some_and(|peer| peer != owner.as_str()); let commit_req = MsgPack { serialize_part: ExternalPutCommitReq { key: key.to_string(), + len: payload_len, + src_offset: put_start_ok.src_offset, + remote_target, put_id: put_start_ok.put_id, lease_id, + write_through, started_time, test_observe_put_phases: true, }, @@ -2085,6 +3275,7 @@ key={}, attempt={}/{}, err={}", None }, put_id: put_start_ok.put_id.clone(), + write_through, lease_id, started_time, test_observe_put_phases: true, @@ -2129,6 +3320,8 @@ key={}, attempt={}/{}, err={}", base_addr: usize, lease_id: Option, reject_if_inflight_same_key: bool, + reject_if_exist_same_key: bool, + write_through: bool, preferred_sub_cluster: Option<&str>, observe_enabled: bool, ) -> KvResult { @@ -2139,6 +3332,8 @@ key={}, attempt={}/{}, err={}", key: key.to_string(), len: value.len() as u64, reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, preferred_sub_cluster: preferred_sub_cluster.map(|s| s.to_string()), started_time, test_observe_put_phases: true, @@ -2153,7 +3348,7 @@ key={}, attempt={}/{}, err={}", })?; let put_start_rpc_started_at = observe_enabled.then(Instant::now); let (put_resp, put_start_side) = self - .call_put_start_with_side_fallback(owner, put_start_req) + .call_put_start_with_side_fallback(owner.clone(), put_start_req) .await?; if let Some(started_at) = put_start_rpc_started_at { trace.external_put_start_rpc_us = duration_to_i64_us(started_at.elapsed()); @@ -2169,11 +3364,19 @@ key={}, attempt={}/{}, err={}", self.remember_side_transfer_binding(put_start_ok.put_id, put_start_side); if self.short_circuit_put_payload_path_enabled() { + let remote_target = put_start_ok + .peer_id + .as_deref() + .is_some_and(|peer| peer != owner.as_str()); let commit_req = MsgPack { serialize_part: ExternalPutCommitReq { key: key.to_string(), + len: value.len() as u64, + src_offset: put_start_ok.src_offset, + remote_target, put_id: put_start_ok.put_id, lease_id, + write_through, started_time, test_observe_put_phases: true, }, @@ -2256,6 +3459,7 @@ key={}, attempt={}/{}, err={}", None }, put_id: put_start_ok.put_id.clone(), + write_through, lease_id, started_time, test_observe_put_phases: true, @@ -2295,7 +3499,7 @@ key={}, attempt={}/{}, err={}", let mut prev_owner_start_time = self.current_owner_start_time().await; let mut recover_attempts = 0usize; if self.base_ptr().await.is_err() { - let path = self.share_mem_path(); + let path = self.shared_memory_path(); tracing::info!("ExternalClientApi.delete waiting for owner at: {}", path); let _ = self.ensure_owner_ready(&mut prev_owner_start_time).await?; } @@ -2473,14 +3677,25 @@ async fn handle_external_invalidate_weak_index( let api = view.external_client_api(); let inner = api.inner(); let mut removed_total = 0usize; - for k in req.keys.iter() { - if let Some(_v) = inner.key_weak_memholder_index.remove(k) { + let items = if req.items.is_empty() { + req.keys + .iter() + .cloned() + .map(|key| ExternalInvalidateWeakIndexItem { key }) + .collect::>() + } else { + req.items.clone() + }; + for item in items.iter() { + let key = &item.key; + let weak_removed = inner.key_weak_memholder_index.remove(key).is_some(); + if weak_removed { removed_total += 1; } } tracing::debug!( - "External invalidated weak_index for keys: {:?} (removed {} entries)", - req.keys, + "External invalidated weak_index for items: {:?} (removed {} entries)", + items, removed_total ); @@ -2659,7 +3874,8 @@ async fn handle_sync_kv_to_file_external( async fn task_wait_owner_restart( view: ExternalClientApiView, - share_mem_path: String, + shared_memory_path: String, + shared_file_path: String, current_sig_snapshot: Option, wait_start_ts: i64, old_owner_id: Option, @@ -2668,7 +3884,7 @@ async fn task_wait_owner_restart( ) -> KvResult { let shutdown_poller = view.register_shutdown_poller(); let mut cluster_rx = view.cluster_manager().listen(); - let shared_meta_path = format!("{}/shared.json", &share_mem_path); + let shared_meta_path = format!("{}/shared.json", &shared_file_path); let mut waited = 0u64; loop { if !shutdown_poller.is_running() { @@ -2679,7 +3895,8 @@ async fn task_wait_owner_restart( match probe_owner_restart_payload( &view, - &share_mem_path, + &shared_memory_path, + &shared_file_path, &shared_meta_path, current_sig_snapshot.as_ref(), wait_start_ts, @@ -2728,7 +3945,8 @@ fn read_shared_json_snapshot( async fn probe_owner_restart_payload( view: &ExternalClientApiView, - share_mem_path: &str, + shared_memory_path: &str, + shared_file_path: &str, shared_meta_path: &str, current_sig_snapshot: Option<&SharedMetaSignature>, wait_start_ts: i64, @@ -2736,16 +3954,16 @@ async fn probe_owner_restart_payload( expected_cluster_name: &str, expected_protocol_version: &str, ) -> KvResult { - if !fluxon_util::fs_watch::are_files_ready(share_mem_path, &["mmap.file"]) { + if !fluxon_util::fs_watch::are_files_ready(shared_memory_path, &["mmap.file"]) { return Ok(OwnerRestartProbe::Pending(format!( "shared memory mmap.file not ready yet: path={}", - share_mem_path + shared_memory_path ))); } - if !fluxon_util::fs_watch::are_files_ready(share_mem_path, &["shared.json"]) { + if !fluxon_util::fs_watch::are_files_ready(shared_file_path, &["shared.json"]) { return Ok(OwnerRestartProbe::Pending(format!( "shared metadata shared.json not ready yet: path={}", - share_mem_path + shared_file_path ))); } @@ -2768,13 +3986,13 @@ async fn probe_owner_restart_payload( if meta.protocol_version != expected_protocol_version { return Ok(OwnerRestartProbe::Pending(format!( "shared.json protocol_version mismatch; waiting: shm_dir='{}' shared='{}' local='{}'", - share_mem_path, meta.protocol_version, expected_protocol_version + shared_memory_path, meta.protocol_version, expected_protocol_version ))); } if meta.cluster_name != expected_cluster_name { return Ok(OwnerRestartProbe::Pending(format!( "shared.json cluster_name mismatch; waiting: shm_dir='{}' shared='{}' local='{}'", - share_mem_path, meta.cluster_name, expected_cluster_name + shared_memory_path, meta.cluster_name, expected_cluster_name ))); } if let Some(old_owner_id) = old_owner_id { @@ -2844,7 +4062,7 @@ impl LogicalModule for ExternalClientApi { async fn shutdown(&self) -> Result<(), Self::Error> { // 只在ExternalClient模式下清理共享内存映射 let ext = &self.0; - if ext.share_mem_path().is_empty() { + if ext.shared_memory_path().is_empty() { tracing::info!("ExternalClientApi shutdown (no shared memory path configured)"); return Ok(()); } diff --git a/fluxon_rs/fluxon_kv/src/kv_test.rs b/fluxon_rs/fluxon_kv/src/kv_test.rs index 5f0a9e2..392ccf1 100644 --- a/fluxon_rs/fluxon_kv/src/kv_test.rs +++ b/fluxon_rs/fluxon_kv/src/kv_test.rs @@ -11,11 +11,12 @@ use crate::cluster_manager::ClusterManagerRdmaControlInit; use crate::config::{ - ClientConfig, ContributeToClusterPoolSize, FluxonKvSpec, LargeFilePaths, MasterConfig, MonitoringConfig, - ProtocolConfig, ProtocolType, TestSpecConfig, TestSpecTransportMode, TransferEngineType, + ClientConfig, ContributeToClusterPoolSize, FluxonKvSpec, LargeFilePaths, MasterConfig, + MonitoringConfig, ProtocolConfig, ProtocolType, TestSpecConfig, TestSpecTransportMode, + TransferEngineType, }; use crate::run_master_with_test_overrides; -use crate::{ClientRunTestOverrides, MasterRunTestOverrides, run_client_with_test_overrides}; +use crate::{run_client_with_test_overrides, ClientRunTestOverrides, MasterRunTestOverrides}; // external client runs via run_client when contribution is zero use crate::ConfigArg; use etcd_client::Client as EtcdClient; @@ -518,18 +519,16 @@ async fn verify_rdma_transfer_data_link( ); } - let Some(raw) = fetch_transfer_link_te_value( - cluster_name, - from_instance_key, - to_instance_key, - ) - .await - .unwrap_or_else(|err| { - panic!( + let Some(raw) = + fetch_transfer_link_te_value(cluster_name, from_instance_key, to_instance_key) + .await + .unwrap_or_else(|err| { + panic!( "closed transfer_link probe failed: cluster={} from={} to={} attempt={} err={}", cluster_name, from_instance_key, to_instance_key, attempt, err ) - }) else { + }) + else { if Instant::now() >= deadline { panic!( "closed transfer data probe timed out without transfer_link_te key: cluster={} from={} to={} key_prefix={} key={} attempt={}", @@ -802,7 +801,6 @@ impl KvTestRoundOptions { kv_test_run_scope() ) } - } #[derive(Clone, Debug)] @@ -842,8 +840,7 @@ fn default_client_large_file_paths( instance_key: &str, contribute_to_cluster_pool_size: &ContributeToClusterPoolSize, ) -> LargeFilePaths { - if contribute_to_cluster_pool_size.dram == 0 - && contribute_to_cluster_pool_size.vram.is_empty() + if contribute_to_cluster_pool_size.dram == 0 && contribute_to_cluster_pool_size.vram.is_empty() { return LargeFilePaths { paths: Vec::new() }; } @@ -1381,7 +1378,10 @@ async fn key_meta_cache_check( } } - tracing::info!("🔍 Starting PUT and GET in parallel: {}", parallel_unique_key); + tracing::info!( + "🔍 Starting PUT and GET in parallel: {}", + parallel_unique_key + ); for i in 0..10 { let (put_client, other_client) = if i % 2 == 0 { (client, client2) @@ -1420,7 +1420,9 @@ async fn key_meta_cache_check( } assert!( - put_client.client_kv_api().has_cached_key(parallel_unique_key), + put_client + .client_kv_api() + .has_cached_key(parallel_unique_key), "put client should have immediate local cache metadata for key {} after put time {}", parallel_unique_key, i diff --git a/fluxon_rs/fluxon_kv/src/lib.rs b/fluxon_rs/fluxon_kv/src/lib.rs index edaa386..fe69407 100644 --- a/fluxon_rs/fluxon_kv/src/lib.rs +++ b/fluxon_rs/fluxon_kv/src/lib.rs @@ -30,6 +30,8 @@ pub use crate::client_seg_pool::SharedJsonMeta; pub use crate::cluster_manager::{ClusterEvent, ClusterMember}; pub use fluxon_observability::types::FsMountKind; +pub const OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES: u64 = 512 * 1024 * 1024; + pub type MembershipEventReceiver = limit_thirdparty::tokio::sync::abroadcast::Receiver; @@ -56,8 +58,8 @@ use crate::external_client_api::ExternalClientApiViewTrait; use crate::master_kv_router::MasterKvRouterAccessTrait; use crate::master_kv_router::MasterKvRouterView; use crate::master_kv_router::MasterKvRouterViewTrait; -use crate::master_lease_manager::MasterLeaseManager; use crate::master_lease_manager::master_lease_manager::MasterLeaseManagerNewArg; +use crate::master_lease_manager::MasterLeaseManager; use crate::master_lease_manager::{ MasterLeaseManagerAccessTrait, MasterLeaseManagerView, MasterLeaseManagerViewTrait, }; @@ -78,21 +80,21 @@ use client_seg_pool::{ClientSegPool, ClientSegPoolNewArg}; use client_transfer_engine::ClientTransferEngine; use cluster_manager::{ClusterManager, ClusterManagerNewArg, ClusterManagerRdmaControlInit}; use config::{ - ClientConfig, ClientConfigYaml, ContributeToClusterPoolSize, FluxonKvSpec, MasterConfig, - MasterConfigYaml, ProtocolConfig, ProtocolType, SideTransferRole, TestSpecConfig, - TestSpecTransportMode, TransferEngineType, normalize_etcd_addresses, + normalize_etcd_addresses, ClientConfig, ClientConfigYaml, ContributeToClusterPoolSize, + FluxonKvSpec, MasterConfig, MasterConfigYaml, ProtocolConfig, ProtocolType, SideTransferRole, + TestSpecConfig, TestSpecTransportMode, TransferEngineType, }; use external_client_api::{ExternalClientApi, ExternalClientApiNewArg}; use fluxon_commu::TransferBackendActivationMode; use fluxon_framework::LogicalModule; -use fluxon_framework::{AnyResult, define_framework}; +use fluxon_framework::{define_framework, AnyResult}; use master_kv_router::{MasterKvRouter, MasterKvRouterNewArg}; use master_seg_manager::MasterSegManager; use metric_reporter::{ - META_KEY_KV_OBSERVE_BROADCAST, MetricReporter, MetricReporterAccessTrait, MetricReporterNewArg, - MetricReporterView, MetricReporterViewTrait, ObserveProxyCaller, ObserveProxyPicker, register_greptime_otlp_log_proxy_rpc, serialize_master_observe_broadcast, - wait_master_observe_broadcast, + wait_master_observe_broadcast, MetricReporter, MetricReporterAccessTrait, MetricReporterNewArg, + MetricReporterView, MetricReporterViewTrait, ObserveProxyCaller, ObserveProxyPicker, + META_KEY_KV_OBSERVE_BROADCAST, }; use p2p::p2p_module::{P2pModule, P2pModuleNewArg, P2pTcpThreadTransportTuning}; use sha2::{Digest, Sha256}; @@ -254,6 +256,16 @@ pub trait KvClientTrait { /// Existence check by role async fn kv_is_exist(&self, key: &str) -> KvResult; + /// Batch existence check by role. + /// + /// `allow_local_snapshot` only enables positive local-cache hits; misses + /// still fall through to the authority path. + async fn kv_batch_is_exist( + &self, + keys: Vec, + allow_local_snapshot: bool, + ) -> KvResult>; + /// Count keys by prefix via master-side radix index. async fn kv_count_prefix(&self, prefix: &str) -> KvResult; @@ -403,6 +415,26 @@ impl KvClientTrait for Framework { } } + async fn kv_batch_is_exist( + &self, + keys: Vec, + allow_local_snapshot: bool, + ) -> KvResult> { + if self.is_external_mode() { + self.external_client_api_view() + .external_client_api() + .inner() + .batch_is_exist(keys, allow_local_snapshot) + .await + } else { + self.client_kv_api_view() + .client_kv_api() + .inner() + .batch_is_exist(keys, allow_local_snapshot) + .await + } + } + async fn kv_count_prefix(&self, prefix: &str) -> KvResult { // Delegate to key_prefix helper that talks to master. crate::key_prefix::count_prefix_for_framework(self, prefix).await @@ -1989,8 +2021,8 @@ async fn run_client_impl( test_spec_config: config.test_spec_config.clone(), }, external_client_api_arg: ExternalClientApiNewArg { - share_mem_path: config.share_mem_path.clone(), - large_file_paths: config.large_file_paths.clone(), + shared_memory_path: config.share_mem_path.clone(), + shared_file_path: config.share_mem_path.clone(), expected_cluster_name: config.cluster_name.clone(), expected_protocol_version: build_version.clone(), enable_side_transfer: config.test_spec_config.enable_side_transfer, @@ -2736,8 +2768,8 @@ mod tests { large_file_paths: crate::config::LargeFilePaths { paths: vec![owner_large_root.to_string_lossy().into_owned()], }, - protocol_version: - fluxon_util::git_version_build_record::get_current_git_commitid().unwrap(), + protocol_version: fluxon_util::git_version_build_record::get_current_git_commitid() + .unwrap(), write_ts: Some(chrono::Utc::now().timestamp_micros()), }; let shared_meta_json = serde_json::to_string(&shared_meta).unwrap(); diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/delete.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/delete.rs index 12a55ee..b7d65fc 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/delete.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/delete.rs @@ -1,12 +1,12 @@ use super::{ - MasterKvRouterView, msg_pack::{ BatchDeleteAckReq, BatchDeleteAckResp, BatchDeleteClientKvMetaCacheReq, DeleteAckReq, DeleteAckResp, DeleteClientKvMetaCacheItem, DeleteReq, DeleteResp, }, + MasterKvRouterView, }; -use crate::master_kv_router::OneKvNodesRoutes; use crate::master_kv_router::put::PutIDForAKey; +use crate::master_kv_router::OneKvNodesRoutes; use crate::memholder::{ EnsureMemholderMgmtDeleteActorOwned, MasterOwnerMemMgr, MemholderManagerTrait, }; @@ -90,6 +90,7 @@ pub fn evict_one_kv_replica_for_node( node_id: NodeID, put_id: PutIDForAKey, ) -> Result<(), msg_and_error::ErrorCode> { + let _guard = view.master_kv_router().inner().route_lifetime_lock.lock(); let route = if let Some(route) = view.master_kv_router().inner().kv_routes.get(&key) { route.clone() } else { diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs index 8c17155..4a290a7 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs @@ -1,23 +1,31 @@ use super::{ - InflightGetInfo, KvRouteInfo, MasterKvRouterView, NodeValueReplicaDesc, OwnerHoldingGetInfo, msg_pack::{ - GetAllocationMode, GetDoneReq, GetDoneResp, GetMetaReq, GetMetaResp, GetRevokeReq, - GetRevokeResp, GetStartReq, GetStartResp, + BatchGetDoneItemResp, BatchGetDoneReq, BatchGetDoneResp, BatchGetRevokeItemResp, + BatchGetRevokeReq, BatchGetRevokeResp, BatchGetStartItemResp, BatchGetStartReq, + BatchGetStartResp, BatchIsExistReq, BatchIsExistResp, GetAllocationMode, GetDoneReq, + GetDoneResp, GetMetaReq, GetMetaResp, GetRevokeReq, GetRevokeResp, GetStartReq, + GetStartResp, MemHolderKeepAliveReq, MemHolderKeepAliveResp, MemHolderReleaseReq, + MemHolderReleaseResp, }, + InflightGetInfo, KvRouteInfo, MasterKvRouterView, NodeValueReplicaDesc, OwnerHoldingGetInfo, }; -use crate::master_kv_router::OneKvNodesRoutes; use crate::master_kv_router::put::PutIDForAKey; +use crate::master_kv_router::OneKvNodesRoutes; use crate::memholder::MemholderManagerTrait; use crate::{ - cluster_manager::NodeID, master_seg_manager::one_seg_allocator::Allocation, - p2p::msg_pack::MsgPack, rpcresp_kvresult_convert::msg_and_error, + cluster_manager::NodeID, + master_seg_manager::{one_seg_allocator::Allocation, MasterSegManagerAccessTrait}, + p2p::msg_pack::MsgPack, + rpcresp_kvresult_convert::msg_and_error::{self, kv}, }; -use rand::Rng; +use dashmap::DashMap; +use limit_thirdparty::tokio; use rand::seq::SliceRandom; +use rand::Rng; use std::collections::HashSet; use std::{ collections::HashMap, - sync::{Arc, atomic::Ordering}, + sync::{atomic::Ordering, Arc}, }; fn update_moka_for_node( @@ -32,7 +40,7 @@ fn update_moka_for_node( return; } let view_task = view.clone(); - let _ = view.spawn("update_moka_for_node", async move { + view.spawn("update_moka_for_node", async move { if let Some(cache) = view_task .master_kv_router() .get_node_cache_controller(&node_id) @@ -68,6 +76,14 @@ fn update_moka_for_node( }); } +fn one_kv_routes_has_live_replica(one_kv_nodes_routes: &OneKvNodesRoutes) -> bool { + one_kv_nodes_routes + .nodes_replicas + .read() + .values() + .any(|kv_info| !kv_info.tomb_tag.is_tomb()) +} + pub async fn handle_get_start( view: MasterKvRouterView, req: MsgPack, @@ -153,15 +169,17 @@ pub async fn handle_get_start( tombs.insert(selected_replica_key.to_owned()); continue; } - let src_allocation = selected_replica.allocation.clone(); let src_node_id = selected_replica.node_id.clone(); - - // 为get调用方分配接收内存作为传输target - if target_allocations.is_none() { - target_allocations = if let Some(replica_on_recv_node) = replicas.get(&req_node_id) { - allocation_mode = GetAllocationMode::ReuseReplica; - Some(replica_on_recv_node.allocation.clone()) - } else { + let src_len = selected_replica.backing.len(); + let src_abs_addr = selected_replica.backing.abs_addr(); + let src_base = selected_replica.backing.base_addr(); + + // For committed-slot replicas on the requester node, we still allocate a + // normal target buffer here instead of reusing the committed slot as a + // MemHolder backing. That keeps the existing get-path carrier stable + // and avoids the old None->unwrap panic. + let mut allocate_request_target = + || -> Result, (u64, MsgPack)> { let target_allocation = { let req_node_allocators = view.master_seg_manager().get_node_allocators(&req_node_id); @@ -173,12 +191,12 @@ pub async fn handle_get_start( let err = msg_and_error::KvError::Unreachable( msg_and_error::UnreachableError::OwnerNoSeg { detail: "config=0 initializes as external; non-zero initializes as owner; the owner must have memory space (segment)".to_string() } ); - return failed_resp_err( + return Err(failed_resp_err( err, - Some((tombs, one_kv_nodes_routes.put_id)), + Some((tombs.clone(), one_kv_nodes_routes.put_id)), &view, &req.serialize_part.key, - ); + )); } let target_allocator = @@ -186,7 +204,7 @@ pub async fn handle_get_start( let mut allocated_addr: Option = None; for attempt in 1..=3 { - if let Ok(allocation) = target_allocator.allocate(src_allocation.size()) { + if let Ok(allocation) = target_allocator.allocate(src_len) { allocated_addr = Some(allocation); break; } else { @@ -208,12 +226,12 @@ pub async fn handle_get_start( total_capacity: total, free_capacity: free, }); - return failed_resp_err( + return Err(failed_resp_err( err, - Some((tombs, one_kv_nodes_routes.put_id)), + Some((tombs.clone(), one_kv_nodes_routes.put_id)), &view, &req.serialize_part.key, - ); + )); } allocated_addr.unwrap() }; @@ -222,15 +240,38 @@ pub async fn handle_get_start( } else { allocation_mode = GetAllocationMode::Temporary; } - Some(Arc::new(target_allocation)) + Ok(Arc::new(target_allocation)) }; + + // 为get调用方分配接收内存作为传输target + if target_allocations.is_none() { + target_allocations = Some( + if let Some(replica_on_recv_node) = replicas.get(&req_node_id) { + match &replica_on_recv_node.backing { + super::KvReplicaBacking::Allocation(allocation) => { + allocation_mode = GetAllocationMode::ReuseReplica; + allocation.clone() + } + super::KvReplicaBacking::CommittedSlot(_) => { + match allocate_request_target() { + Ok(allocation) => allocation, + Err(resp) => return resp, + } + } + } + } else { + match allocate_request_target() { + Ok(allocation) => allocation, + Err(resp) => return resp, + } + }, + ); } let target_allocation = target_allocations.unwrap(); // Convert to absolute addresses for Mooncake (requires absolute) // Use allocation's allocator base directly - let src_base = src_allocation.base_addr(); let target_base = target_allocation.base_addr(); // If we reuse existing target on requesting node, declare src=target on req node @@ -242,7 +283,7 @@ pub async fn handle_get_start( } else { ( src_node_id.clone(), - src_base + src_allocation.addr(), + src_abs_addr, target_base + target_allocation.addr(), src_base, target_base, @@ -257,7 +298,7 @@ pub async fn handle_get_start( target_addr: resp_target_addr, src_base_addr: resp_src_base, target_base_addr: resp_target_base, - len: src_allocation.size(), + len: src_len, error_code: msg_and_error::OK, error_json: String::new(), server_process_us: 0, @@ -268,7 +309,7 @@ pub async fn handle_get_start( src_node_id: src_node_id.clone(), key: req.serialize_part.key.clone(), req_node_id, - len: src_allocation.size(), + len: src_len, allocation: target_allocation, // 存储target allocation route: one_kv_nodes_routes.clone(), allocation_mode, @@ -411,7 +452,9 @@ pub async fn handle_get_done( inflight_info.req_node_id.clone(), KvRouteInfo { node_id: inflight_info.req_node_id, - allocation: inflight_info.allocation, + backing: super::KvReplicaBacking::Allocation( + inflight_info.allocation, + ), tomb_tag, }, ); @@ -490,6 +533,15 @@ pub async fn handle_get_done( get_id, holder_id ); + view.master_kv_router() + .view() + .metric_reporter() + .metrics() + .inc_kv_get_done_allocation(match allocation_mode { + GetAllocationMode::Temporary => "temporary", + GetAllocationMode::ReuseReplica => "reuse_replica", + GetAllocationMode::DurableReplica => "durable_replica", + }); MsgPack { serialize_part: GetDoneResp { @@ -621,7 +673,7 @@ pub async fn handle_get_meta( if kv_info.tomb_tag.is_tomb() { continue; } - let len = kv_info.allocation.size(); + let len = kv_info.backing.len(); return MsgPack { serialize_part: GetMetaResp { exists: true, @@ -684,3 +736,143 @@ pub async fn handle_get_meta( } } } + +pub async fn handle_batch_is_exist( + view: MasterKvRouterView, + req: MsgPack, + _req_node_id: NodeID, +) -> MsgPack { + tracing::debug!( + "Handling BatchIsExistReq: batch_len={}", + req.serialize_part.keys.len() + ); + + let mut exists_list = Vec::with_capacity(req.serialize_part.keys.len()); + + { + let _guard = view.master_kv_router().inner().route_lifetime_lock.lock(); + for key in &req.serialize_part.keys { + if let Some(one_kv_nodes_routes) = view.master_kv_router().inner().kv_routes.get(key) { + let exists = one_kv_routes_has_live_replica(&one_kv_nodes_routes); + exists_list.push(exists); + } else { + exists_list.push(false); + } + } + } + + MsgPack { + serialize_part: BatchIsExistResp { + exists_list, + error_code: msg_and_error::OK, + error_json: String::new(), + }, + raw_bytes: Vec::new(), + } +} + +pub async fn handle_batch_get_start( + view: MasterKvRouterView, + req: MsgPack, + req_node_id: NodeID, +) -> MsgPack { + let mut items = Vec::with_capacity(req.serialize_part.keys.len()); + for key in req.serialize_part.keys { + let (_get_id, resp) = handle_get_start( + view.clone(), + MsgPack { + serialize_part: GetStartReq { key }, + raw_bytes: Vec::new(), + }, + req_node_id.clone(), + ) + .await; + let part = resp.serialize_part; + items.push(BatchGetStartItemResp { + get_id: part.get_id, + node_id: part.node_id, + put_id: part.put_id, + target_addr: part.target_addr, + src_addr: part.src_addr, + target_base_addr: part.target_base_addr, + src_base_addr: part.src_base_addr, + len: part.len, + error_code: part.error_code, + error_json: part.error_json, + }); + } + MsgPack { + serialize_part: BatchGetStartResp { + items, + error_code: msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + }, + raw_bytes: Vec::new(), + } +} + +pub async fn handle_batch_get_revoke( + view: MasterKvRouterView, + req: MsgPack, +) -> MsgPack { + let mut items = Vec::with_capacity(req.serialize_part.get_ids.len()); + for get_id in req.serialize_part.get_ids { + let resp = handle_get_revoke( + view.clone(), + MsgPack { + serialize_part: GetRevokeReq { get_id }, + raw_bytes: Vec::new(), + }, + ) + .await; + let part = resp.serialize_part; + items.push(BatchGetRevokeItemResp { + get_id, + error_code: part.error_code, + error_json: part.error_json, + }); + } + MsgPack { + serialize_part: BatchGetRevokeResp { + items, + error_code: msg_and_error::OK, + error_json: String::new(), + }, + raw_bytes: Vec::new(), + } +} + +pub async fn handle_batch_get_done( + view: MasterKvRouterView, + req: MsgPack, +) -> MsgPack { + let mut items = Vec::with_capacity(req.serialize_part.get_ids.len()); + for get_id in req.serialize_part.get_ids { + let resp = handle_get_done( + view.clone(), + MsgPack { + serialize_part: GetDoneReq { get_id }, + raw_bytes: Vec::new(), + }, + ) + .await; + let part = resp.serialize_part; + items.push(BatchGetDoneItemResp { + get_id, + holder_id: part.holder_id, + allocation_mode: part.allocation_mode, + error_code: part.error_code, + error_json: part.error_json, + }); + } + MsgPack { + serialize_part: BatchGetDoneResp { + items, + error_code: msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + }, + raw_bytes: Vec::new(), + } +} diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs index ee4ca2b..6fb7426 100644 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs @@ -11,16 +11,29 @@ use self::{ delete::handle_batch_delete_ack, delete::handle_delete, delete::handle_delete_ack, - get::{handle_get_done, handle_get_meta, handle_get_revoke, handle_get_start}, + get::{ + handle_batch_get_done, handle_batch_get_revoke, handle_batch_get_start, + handle_batch_is_exist, handle_get_done, handle_get_meta, handle_get_revoke, + handle_get_start, + }, msg_pack::{ - BatchDeleteAckReq, BatchDeleteClientKvMetaCacheReq, CountPrefixReq, CountPrefixResp, - DeleteAckReq, DeleteReq, GetAllocationMode, GetDoneReq, GetMetaReq, GetRevokeReq, - GetStartReq, PutDoneReq, PutRevokeReq, PutStartReq, + BatchDeleteAckReq, BatchDeleteClientKvMetaCacheReq, BatchGetDoneReq, BatchGetRevokeReq, + BatchGetStartReq, BatchIsExistReq, BatchPreparePutKeysReq, BatchPutDoneReq, + BatchPutRevokeReq, BatchPutStartReq, BatchReleasePutKeyReservationsReq, CountPrefixReq, + CountPrefixResp, DeleteAckReq, DeleteReq, GetAllocationMode, GetDoneReq, + GetMasterOnlyMetricPartReq, GetMasterOnlyMetricPartResp, GetMetaReq, GetRevokeReq, + GetStartReq, MemHolderKeepAliveReq, MemHolderReleaseReq, PutAppendDoneReq, + PutAppendRevokeReq, PutAppendStartReq, PutDoneReq, PutRevokeReq, PutStartReq, + ReleaseLocalGrantReq, ReserveLocalGrantReq, }, placement::{PlacementDefault, PlacementPolicy}, - put::{handle_put_done, handle_put_revoke, handle_put_start}, + put::{ + handle_batch_prepare_put_keys, handle_batch_put_done, handle_batch_put_revoke, + handle_batch_put_start, handle_batch_release_put_key_reservations, handle_put_append_done, + handle_put_append_revoke, handle_put_append_start, handle_put_done, handle_put_revoke, + handle_put_start, handle_release_local_grant, handle_reserve_local_grant, + }, }; -use crate::ClientKvApiAccessTrait; use crate::client_kv_api::ClientKvApi; use crate::cluster_manager::{ ClusterEvent, ClusterManager, ClusterManagerAccessTrait, NodeID, NodeIDString, @@ -29,29 +42,35 @@ use crate::config::TestSpecConfig; use crate::master_kv_router::delete::DeleteKeyInfo; use crate::master_kv_router::put::PutIDForAKey; use crate::master_lease_manager::{MasterLeaseManager, MasterLeaseManagerAccessTrait}; +use crate::master_seg_manager::one_seg_allocator::Allocation; use crate::master_seg_manager::MasterSegManager; use crate::master_seg_manager::MasterSegManagerAccessTrait; use crate::master_seg_manager::NodeTombTag; -use crate::master_seg_manager::one_seg_allocator::Allocation; -use crate::memholder::{EnsureMemholderMgmtDeleteHandle, MasterOwnerMemMgr, MemholderManagerTrait}; +use crate::memholder::{ + EnsureMemholderMgmtDeleteHandle, MasterOwnerMemMgr, MemholderManagerTrait, NodeHolderKey, +}; use crate::metric_reporter::{MetricReporter, MetricReporterAccessTrait}; use crate::p2p::msg_pack::{MsgPack, RPCCaller, RPCHandler}; use crate::p2p::p2p_module::{P2pModule, P2pModuleAccessTrait}; +use crate::rpcresp_kvresult_convert; use crate::rpcresp_kvresult_convert::msg_and_error::{KvError, OK}; -use fluxon_framework::{LogicalModule, define_module}; +use crate::ClientKvApiAccessTrait; +use fluxon_framework::{define_module, LogicalModule}; +use fluxon_framework_compiled::upgrade_view_guard::UpgradeViewGuard; use async_trait::async_trait; use chrono::Utc; use dashmap::DashMap; -use limit_thirdparty::tokio::sync::ARwLock; +use limit_thirdparty::tokio::sync::{abroadcast, ARwLock}; use limit_thirdparty::tokio::{self, sync::ampsc}; use moka::notification::RemovalCause; use parking_lot::Mutex; use parking_lot::RwLock; -use std::collections::HashMap; +use std::borrow::Cow; use std::collections::HashSet; -use std::sync::Arc; +use std::collections::{HashMap, VecDeque}; use std::sync::atomic::{AtomicU32, AtomicU64, Ordering}; +use std::sync::Arc; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use tracing::{debug, error, info, warn}; @@ -69,12 +88,78 @@ pub enum PutPlacementMode { Remote, } +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum ReservedCapacityReason { + LeaseBoundKv, + LocalReserveGrant, +} + +#[derive(Debug, Default)] +pub struct NodeCacheReservedCapacity { + pub total_bytes: AtomicU64, + pub lease_bound_kv_bytes: AtomicU64, + pub local_reserve_grant_bytes: AtomicU64, +} + +impl NodeCacheReservedCapacity { + fn apply_delta(&self, reason: ReservedCapacityReason, delta_bytes: i64) { + if delta_bytes >= 0 { + let delta = delta_bytes as u64; + self.total_bytes.fetch_add(delta, Ordering::Relaxed); + match reason { + ReservedCapacityReason::LeaseBoundKv => { + self.lease_bound_kv_bytes + .fetch_add(delta, Ordering::Relaxed); + } + ReservedCapacityReason::LocalReserveGrant => { + self.local_reserve_grant_bytes + .fetch_add(delta, Ordering::Relaxed); + } + } + } else { + let delta = (-delta_bytes) as u64; + self.total_bytes.fetch_sub(delta, Ordering::Relaxed); + match reason { + ReservedCapacityReason::LeaseBoundKv => { + self.lease_bound_kv_bytes + .fetch_sub(delta, Ordering::Relaxed); + } + ReservedCapacityReason::LocalReserveGrant => { + self.local_reserve_grant_bytes + .fetch_sub(delta, Ordering::Relaxed); + } + } + } + } + + fn total_reserved_bytes(&self) -> u64 { + self.total_bytes.load(Ordering::Relaxed) + } +} + #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct RequesterTargetPair { requester_node_id: NodeIDString, target_node_id: NodeIDString, } +#[derive(Clone, Debug, Default)] +pub struct ReplicaCacheNodeObserveSnapshot { + pub owner_node: String, + pub entries: u64, + pub weighted_bytes: u64, + pub effective_capacity_bytes: u64, + pub reserved_capacity_bytes: u64, + pub base_capacity_bytes: u64, +} + +#[derive(Clone, Debug, Default)] +pub struct MasterRuntimeObserveSnapshot { + pub get_holding_entries: u64, + pub get_holding_bytes: u64, + pub replica_cache_nodes: Vec, +} + impl RequesterTargetPair { fn new(requester_node_id: &str, target_node_id: &str) -> Self { Self { @@ -88,23 +173,49 @@ impl RequesterTargetPair { } } +#[derive(Clone, Debug)] +pub struct CommittedSlotReplica { + pub owner_node_id: NodeID, + pub grant_id: u64, + pub slot_index: u32, + pub slot_size: u64, + pub addr: u64, + pub len: u64, + pub base_addr: u64, +} + /// Information about a `put` operation that is currently in progress. pub enum InflightPutAllocation { /// Local fast path: the same allocation is used as both src (staging) and target (final). Local(Allocation), /// Remote path: separate allocations for src (on requester) and target (on selected node). Remote { src: Allocation, target: Allocation }, + /// Local-first fast path: data is already committed in owner-local reserve slot. + LocalCommittedSlot(CommittedSlotReplica), +} + +#[derive(Clone)] +pub struct InflightPutCommitInfo { + pub node_id: NodeID, + pub src_target_allocation: Arc>>, } /// Information about a `put` operation that is currently in progress. #[derive(Clone)] pub struct InflightPutInfo { - pub node_id: NodeID, - // seg_name: String, pub key: String, pub req_node_id: NodeID, pub len: u64, - pub src_target_allocation: Arc>>, + pub commit_info: InflightPutCommitInfo, + pub remote_append: Option, +} + +#[derive(Clone)] +pub struct InflightPutAppendInfo { + pub node_id: NodeID, + pub key: String, + pub put_id: PutIDForAKey, + pub target_allocation: Arc>>, } /// Information about a `get` operation that is currently in progress. @@ -137,6 +248,16 @@ pub struct OwnerHoldingGetInfo { pub allocation: Arc, // The target allocation where data was transferred } +pub struct LocalReserveGrantInfo { + pub owner_node_id: NodeID, + pub allocation: Allocation, +} + +pub struct PreparedPutKeyReservationInfo { + pub owner_node_id: NodeID, + pub key: String, +} + async fn handle_count_prefix( view: &MasterKvRouterView, msg: MsgPack, @@ -194,10 +315,39 @@ pub struct NodeValueReplicaDesc { /// Information about a completed `put` operation that can be retrieved via `get`. /// Now supports multiple replicas per key. +#[derive(Clone, Debug)] +pub enum KvReplicaBacking { + Allocation(Arc), + CommittedSlot(CommittedSlotReplica), +} + +impl KvReplicaBacking { + pub fn abs_addr(&self) -> u64 { + match self { + Self::Allocation(allocation) => allocation.base_addr() + allocation.addr(), + Self::CommittedSlot(slot) => slot.addr, + } + } + + pub fn base_addr(&self) -> u64 { + match self { + Self::Allocation(allocation) => allocation.base_addr(), + Self::CommittedSlot(slot) => slot.base_addr, + } + } + + pub fn len(&self) -> u64 { + match self { + Self::Allocation(allocation) => allocation.size(), + Self::CommittedSlot(slot) => slot.len, + } + } +} + #[derive(Clone, Debug)] pub struct KvRouteInfo { pub node_id: NodeID, - pub allocation: Arc, + pub backing: KvReplicaBacking, pub tomb_tag: NodeTombTag, } @@ -238,7 +388,7 @@ impl OneKvNodesRoutes { &self, verify_put_id: PutIDForAKey, tombs: HashSet, - _view: &MasterKvRouterView, + view: &MasterKvRouterView, ) -> bool { if self.put_id != verify_put_id { return false; @@ -346,6 +496,7 @@ pub struct MasterKvRouterInner { /// (key, put_time_ms, put_version) -> inflight_put_info pub inflight_puts: moka::future::Cache<(String, u64, u32), InflightPutInfo>, + pub inflight_put_appends: moka::future::Cache<(String, u64, u32), InflightPutAppendInfo>, /// key -> inflight put count pub inflight_put_key_counts: Arc>, pub inflight_gets: moka::future::Cache, @@ -359,24 +510,37 @@ pub struct MasterKvRouterInner { /// Counter for holder_id pub next_holder_id: AtomicU64, + /// Counter for local reserve grant identifiers. + pub next_local_reserve_grant_id: AtomicU64, + + /// Counter for prepared put-key reservation identifiers. + pub next_prepared_put_key_reservation_id: AtomicU64, + /// Latest version of key-value replicas pub kv_routes: DashMap>, - /// Prefix-counting index derived from `kv_routes`. - /// - /// It is updated through async follow-up maintenance, so it does not guarantee - /// immediate strong-consistency visibility for a freshly committed put. - /// The generic surface is `CountPrefix` RPC; the current primary use case is - /// MQ capacity backpressure / prefix counting. + /// Serializes route-level existence checks with cache-eviction route cleanup. + /// This protects route metadata consistency only; it does not create MemHolders + /// or move payload data. + pub route_lifetime_lock: Mutex<()>, + + /// Grants reserved for owner-local hot-path staging. + pub local_reserve_grants: DashMap, + + /// Prepared key reservations for owner-local hot-path staging. + pub prepared_put_key_reservations: DashMap, + + /// Prefix-counting index for keys, used by CountPrefix RPC. pub prefix_index: ARwLock, /// Support replicas: node_id -> key -> route_info pub node_kv_cache_controller: DashMap>>, - /// Per-node total bytes reserved for leased replicas. We subtract this from - /// the base max capacity of each node's moka cache. Acts like a fetch_sub/add counter. - pub lease_reserved_bytes: DashMap>, + /// Per-node bytes reserved out of moka usable capacity. + /// The reservation is reason-grouped, but `total_bytes` is the authority + /// used to derive the effective moka max_capacity for the node. + pub node_cache_reserved_capacity: DashMap>, /// Historical final put placement decisions by target node. pub put_target_decision_counts: DashMap>, @@ -497,20 +661,29 @@ impl MasterKvRouter { } }) .build(); + let inflight_put_appends = moka::future::Cache::builder() + .time_to_live(Duration::from_secs(60)) + .build(); let inner = MasterKvRouterInner { view: std::sync::OnceLock::new(), policy: policy_impl, test_spec_config: arg.test_spec_config, inflight_puts, + inflight_put_appends, inflight_put_key_counts, inflight_gets, get_holding: MasterOwnerMemMgr::default(), next_get_id: AtomicU64::new(0), next_holder_id: AtomicU64::new(0), + next_local_reserve_grant_id: AtomicU64::new(1), + next_prepared_put_key_reservation_id: AtomicU64::new(1), kv_routes: DashMap::new(), + route_lifetime_lock: Mutex::new(()), + local_reserve_grants: DashMap::new(), + prepared_put_key_reservations: DashMap::new(), prefix_index: ARwLock::new(PrefixRadixTree::new()), node_kv_cache_controller: DashMap::new(), - lease_reserved_bytes: DashMap::new(), + node_cache_reserved_capacity: DashMap::new(), put_target_decision_counts: DashMap::new(), put_requester_target_decision_counts: DashMap::new(), put_placement_mode_counts: DashMap::new(), @@ -532,6 +705,7 @@ impl MasterKvRouter { self.spawn_cluster_listener(); self.spawn_put_placement_reporter(); + self.spawn_runtime_observe_reporter(); let delete_broadcast_rx = self .0 @@ -587,7 +761,15 @@ impl MasterKvRouter { &self, key: &str, reject_if_inflight_same_key: bool, + reject_if_exist_same_key: bool, ) -> Result<(), KvError> { + if reject_if_exist_same_key && self.key_has_live_replica(key) { + return Err(KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::KeyAlreadyExists { + key: key.to_string(), + }, + )); + } let counts = &self.inner().inflight_put_key_counts; let mut entry = counts.entry(key.to_string()).or_insert(0); if reject_if_inflight_same_key && *entry > 0 { @@ -601,6 +783,20 @@ impl MasterKvRouter { Ok(()) } + pub fn key_has_live_replica(&self, key: &str) -> bool { + self.inner() + .kv_routes + .get(key) + .map(|one_kv_nodes_routes| { + one_kv_nodes_routes + .nodes_replicas + .read() + .values() + .any(|kv_info| !kv_info.tomb_tag.is_tomb()) + }) + .unwrap_or(false) + } + pub fn release_inflight_put_key(&self, key: &str) { Self::release_inflight_put_key_count_map(&self.inner().inflight_put_key_counts, key); } @@ -690,6 +886,92 @@ impl MasterKvRouter { crate::metrics::datasource::register_master_only_metric_handler(self.0.view()); // --- Put Handlers --- + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let view2 = view.clone(); + let req_node_id = resp.node_id().clone(); + let view_task = view2.clone(); + let _ = view.spawn("rpc_reserve_local_grant", async move { + let t0 = Utc::now().timestamp_micros(); + let (grant_id, mut ack) = + handle_reserve_local_grant(view_task.clone(), msg, req_node_id).await; + ack.serialize_part.server_process_us = Utc::now().timestamp_micros() - t0; + if let Err(e) = resp.send_resp(ack).await { + error!("Failed to send ReserveLocalGrantResp: {:?}", e); + if grant_id != 0 { + let _ = view_task + .master_kv_router() + .take_local_reserve_grant(grant_id); + } + } + }); + Ok(()) + }); + + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let view2 = view.clone(); + let req_node_id = resp.node_id().clone(); + let view_task = view2.clone(); + let _ = view.spawn("rpc_release_local_grant", async move { + let t0 = Utc::now().timestamp_micros(); + let mut ack = handle_release_local_grant(view_task, msg, req_node_id).await; + ack.serialize_part.server_process_us = Utc::now().timestamp_micros() - t0; + if let Err(e) = resp.send_resp(ack).await { + error!("Failed to send ReleaseLocalGrantResp: {:?}", e); + } + }); + Ok(()) + }); + + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let view2 = view.clone(); + let req_node_id = resp.node_id().clone(); + let view_task = view2.clone(); + let _ = view.spawn("rpc_batch_prepare_put_keys", async move { + let t0 = Utc::now().timestamp_micros(); + let (reservation_ids, mut ack) = + handle_batch_prepare_put_keys(view_task.clone(), msg, req_node_id).await; + ack.serialize_part.server_process_us = Utc::now().timestamp_micros() - t0; + if let Err(e) = resp.send_resp(ack).await { + error!("Failed to send BatchPreparePutKeysResp: {:?}", e); + for reservation_id in reservation_ids { + if let Some(info) = view_task + .master_kv_router() + .take_prepared_put_key_reservation(reservation_id) + { + view_task + .master_kv_router() + .release_inflight_put_key(&info.key); + } + } + } + }); + Ok(()) + }); + + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let view2 = view.clone(); + let req_node_id = resp.node_id().clone(); + let view_task = view2.clone(); + let _ = view.spawn("rpc_batch_release_put_key_reservations", async move { + let t0 = Utc::now().timestamp_micros(); + let mut ack = + handle_batch_release_put_key_reservations(view_task, msg, req_node_id).await; + ack.serialize_part.server_process_us = Utc::now().timestamp_micros() - t0; + if let Err(e) = resp.send_resp(ack).await { + error!("Failed to send BatchReleasePutKeyReservationsResp: {:?}", e); + } + }); + Ok(()) + }); + let view = self.0.view().clone(); RPCHandler::::new().regist(p2p, move |resp, msg| { let view = view.clone(); @@ -812,7 +1094,7 @@ impl MasterKvRouter { let view = view.clone(); let view2 = view.clone(); let view_task = view2.clone(); - let _ = view.spawn("rpc_delete_ack", async move { + view.spawn("rpc_delete_ack", async move { let ack = handle_delete_ack(view_task, msg).await; if let Err(e) = resp.send_resp(ack).await { error!("Failed to send DeleteAckResp: {:?}", e); @@ -826,7 +1108,7 @@ impl MasterKvRouter { let view = view.clone(); let view2 = view.clone(); let view_task = view2.clone(); - let _ = view.spawn("rpc_batch_delete_ack", async move { + view.spawn("rpc_batch_delete_ack", async move { let ack = handle_batch_delete_ack(view_task, msg).await; if let Err(e) = resp.send_resp(ack).await { error!("Failed to send BatchDeleteAckResp: {:?}", e); @@ -835,12 +1117,59 @@ impl MasterKvRouter { Ok(()) }); + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let view2 = view.clone(); + let req_node_id = resp.node_id().clone(); + let view_task = view2.clone(); + let _ = view.spawn("rpc_put_append_start", async move { + let t0 = Utc::now().timestamp_micros(); + let mut ack = handle_put_append_start(view_task.clone(), msg, req_node_id).await; + ack.serialize_part.server_process_us = Utc::now().timestamp_micros() - t0; + if let Err(e) = resp.send_resp(ack).await { + error!("Failed to send PutAppendStartResp: {:?}", e); + } + }); + Ok(()) + }); + + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let view2 = view.clone(); + let view_task = view2.clone(); + let _ = view.spawn("rpc_put_append_revoke", async move { + let ack = handle_put_append_revoke(view_task, msg).await; + if let Err(e) = resp.send_resp(ack).await { + error!("Failed to send PutAppendRevokeResp: {:?}", e); + } + }); + Ok(()) + }); + + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let view2 = view.clone(); + let view_task = view2.clone(); + let _ = view.spawn("rpc_put_append_done", async move { + let t0 = Utc::now().timestamp_micros(); + let mut ack = handle_put_append_done(view_task, msg).await; + ack.serialize_part.server_process_us = Utc::now().timestamp_micros() - t0; + if let Err(e) = resp.send_resp(ack).await { + error!("Failed to send PutAppendDoneResp: {:?}", e); + } + }); + Ok(()) + }); + // --- GetMeta Handler --- let view = self.0.view().clone(); RPCHandler::::new().regist(p2p, move |resp, msg| { let view = view.clone(); let view2 = view.clone(); - let _ = view.spawn("rpc_get_meta", async move { + view.spawn("rpc_get_meta", async move { let ack = handle_get_meta(view2, msg, resp.node_id().clone()).await; if let Err(e) = resp.send_resp(ack).await { error!("Failed to send GetMetaResp: {:?}", e); @@ -848,6 +1177,107 @@ impl MasterKvRouter { }); Ok(()) }); + + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let view2 = view.clone(); + view.spawn("rpc_batch_is_exist", async move { + let ack = handle_batch_is_exist(view2, msg, resp.node_id().clone()).await; + if let Err(e) = resp.send_resp(ack).await { + error!("Failed to send BatchIsExistResp: {:?}", e); + } + }); + Ok(()) + }); + + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let view2 = view.clone(); + let req_node_id = resp.node_id().clone(); + view.spawn("rpc_batch_put_start", async move { + let t0 = Utc::now().timestamp_micros(); + let mut ack = handle_batch_put_start(view2, msg, req_node_id).await; + ack.serialize_part.server_process_us = Utc::now().timestamp_micros() - t0; + if let Err(e) = resp.send_resp(ack).await { + error!("Failed to send BatchPutStartResp: {:?}", e); + } + }); + Ok(()) + }); + + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let view2 = view.clone(); + view.spawn("rpc_batch_put_revoke", async move { + let ack = handle_batch_put_revoke(view2, msg).await; + if let Err(e) = resp.send_resp(ack).await { + error!("Failed to send BatchPutRevokeResp: {:?}", e); + } + }); + Ok(()) + }); + + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let view2 = view.clone(); + view.spawn("rpc_batch_put_done", async move { + let t0 = Utc::now().timestamp_micros(); + let mut ack = handle_batch_put_done(view2, msg).await; + ack.serialize_part.server_process_us = Utc::now().timestamp_micros() - t0; + if let Err(e) = resp.send_resp(ack).await { + error!("Failed to send BatchPutDoneResp: {:?}", e); + } + }); + Ok(()) + }); + + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let view2 = view.clone(); + let req_node_id = resp.node_id().clone(); + view.spawn("rpc_batch_get_start", async move { + let t0 = Utc::now().timestamp_micros(); + let mut ack = handle_batch_get_start(view2, msg, req_node_id).await; + ack.serialize_part.server_process_us = Utc::now().timestamp_micros() - t0; + if let Err(e) = resp.send_resp(ack).await { + error!("Failed to send BatchGetStartResp: {:?}", e); + } + }); + Ok(()) + }); + + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let view2 = view.clone(); + view.spawn("rpc_batch_get_revoke", async move { + let ack = handle_batch_get_revoke(view2, msg).await; + if let Err(e) = resp.send_resp(ack).await { + error!("Failed to send BatchGetRevokeResp: {:?}", e); + } + }); + Ok(()) + }); + + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let view2 = view.clone(); + view.spawn("rpc_batch_get_done", async move { + let t0 = Utc::now().timestamp_micros(); + let mut ack = handle_batch_get_done(view2, msg).await; + ack.serialize_part.server_process_us = Utc::now().timestamp_micros() - t0; + if let Err(e) = resp.send_resp(ack).await { + error!("Failed to send BatchGetDoneResp: {:?}", e); + } + }); + Ok(()) + }); } fn spawn_node_segement_registration_caller(&self) -> ampsc::Sender { @@ -856,7 +1286,7 @@ impl MasterKvRouter { let (tx, mut rx) = ampsc::channel::(NODE_EVENT_QUEUE_CAPACITY); let view = self.inner().view().clone(); let view_task = view.clone(); - let _ = view.spawn("node_segment_registration_caller", async move { + view.spawn("node_segment_registration_caller", async move { use std::future::Future; use std::pin::Pin; @@ -1171,7 +1601,7 @@ impl MasterKvRouter { > = HashMap::new(); async fn send_event_with_warn( - _view: &MasterKvRouterView, + view: &MasterKvRouterView, node_id: &str, tx: ampsc::Sender, event: ClusterEvent, @@ -1451,36 +1881,30 @@ impl MasterKvRouter { ) } - /// Atomically adjust a node's cache capacity reservation by `delta_bytes`. + /// Atomically adjust a node's moka usable-capacity reservation by `delta_bytes`. /// Positive delta reserves capacity (fetch_sub from usable capacity), /// negative delta releases reservation (fetch_add back to usable capacity). - pub fn adjust_node_cache_capacity_for_lease( + pub fn adjust_node_cache_reserved_capacity( &self, node_id: &str, + reason: ReservedCapacityReason, delta_bytes: i64, ) -> crate::rpcresp_kvresult_convert::msg_and_error::KvResult<()> { if !self.replica_cache_enabled() { return Ok(()); } - // Track per-node reserved bytes with an atomic counter - let reserved_counter = self + let reserved_capacity = self .inner() - .lease_reserved_bytes + .node_cache_reserved_capacity .entry(node_id.to_string()) - .or_insert_with(|| Arc::new(AtomicU64::new(0))) + .or_insert_with(|| Arc::new(NodeCacheReservedCapacity::default())) .value() .clone(); - // Apply delta to the counter with simple fetch ops per user's preference - if delta_bytes >= 0 { - reserved_counter.fetch_add(delta_bytes as u64, Ordering::Relaxed); - } else { - let sub = (-delta_bytes) as u64; - reserved_counter.fetch_sub(sub, Ordering::Relaxed); - } + reserved_capacity.apply_delta(reason, delta_bytes); // Recompute target capacity: base(=MOKA_CACHE_CAPACITY_RATIO * node_space) - reserved_total - let reserved_total = reserved_counter.load(Ordering::Relaxed); + let reserved_total = reserved_capacity.total_reserved_bytes(); let node_space_size = self .inner() .view() @@ -1489,12 +1913,7 @@ impl MasterKvRouter { if node_space_size == 0 { // Node not ready: this should not happen in a successful put_done path. // Revert the counter delta before returning error. - if delta_bytes >= 0 { - reserved_counter.fetch_sub(delta_bytes as u64, Ordering::Relaxed); - } else { - let add = (-delta_bytes) as u64; - reserved_counter.fetch_add(add, Ordering::Relaxed); - } + reserved_capacity.apply_delta(reason, -delta_bytes); return Err( crate::rpcresp_kvresult_convert::msg_and_error::KvError::Unreachable( crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::OwnerNoSeg { @@ -1512,12 +1931,7 @@ impl MasterKvRouter { if let Some(cache) = self.get_node_cache_controller(node_id) { if let Err(e) = cache.set_max_capacity(new_capacity) { // Revert counter and return error. - if delta_bytes >= 0 { - reserved_counter.fetch_sub(delta_bytes as u64, Ordering::Relaxed); - } else { - let add = (-delta_bytes) as u64; - reserved_counter.fetch_add(add, Ordering::Relaxed); - } + reserved_capacity.apply_delta(reason, -delta_bytes); return Err(crate::rpcresp_kvresult_convert::msg_and_error::KvError::Unreachable( crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::RpcDecodeError { rpc_input_json: format!( @@ -1530,12 +1944,7 @@ impl MasterKvRouter { Ok(()) } else { // Revert counter and return error. - if delta_bytes >= 0 { - reserved_counter.fetch_sub(delta_bytes as u64, Ordering::Relaxed); - } else { - let add = (-delta_bytes) as u64; - reserved_counter.fetch_add(add, Ordering::Relaxed); - } + reserved_capacity.apply_delta(reason, -delta_bytes); Err( crate::rpcresp_kvresult_convert::msg_and_error::KvError::Unreachable( crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::OwnerNoSeg { @@ -1546,21 +1955,159 @@ impl MasterKvRouter { } } - // Note: no additional getters for reserved bytes; policy currently relies only on adjust calls. -} + pub fn next_local_reserve_grant_id(&self) -> u64 { + self.inner() + .next_local_reserve_grant_id + .fetch_add(1, Ordering::Relaxed) + } + + pub fn next_prepared_put_key_reservation_id(&self) -> u64 { + self.inner() + .next_prepared_put_key_reservation_id + .fetch_add(1, Ordering::Relaxed) + } + + pub fn install_local_reserve_grant(&self, grant_id: u64, grant: LocalReserveGrantInfo) { + if self + .inner() + .local_reserve_grants + .insert(grant_id, grant) + .is_some() + { + panic!( + "duplicate local reserve grant id indicates a logic bug: grant_id={}", + grant_id + ); + } + } -impl MasterKvRouterView { - pub fn try_adjust_node_cache_capacity_for_lease( + pub fn take_local_reserve_grant(&self, grant_id: u64) -> Option { + self.inner() + .local_reserve_grants + .remove(&grant_id) + .map(|(_, grant)| grant) + } + + pub fn install_prepared_put_key_reservation( &self, - node_id: &str, - delta_bytes: i64, - ) -> Option> { - let _view_guard = self.try_upgrade()?; - Some( - self.master_kv_router() - .adjust_node_cache_capacity_for_lease(node_id, delta_bytes), - ) + reservation_id: u64, + info: PreparedPutKeyReservationInfo, + ) { + if self + .inner() + .prepared_put_key_reservations + .insert(reservation_id, info) + .is_some() + { + panic!( + "duplicate prepared put key reservation id indicates a logic bug: reservation_id={}", + reservation_id + ); + } + } + + pub fn take_prepared_put_key_reservation( + &self, + reservation_id: u64, + ) -> Option { + self.inner() + .prepared_put_key_reservations + .remove(&reservation_id) + .map(|(_, info)| info) + } + + pub fn runtime_observe_snapshot(&self) -> MasterRuntimeObserveSnapshot { + let mut get_holding_bytes = 0u64; + for entry in self.inner().get_holding.inner().iter() { + get_holding_bytes = get_holding_bytes.saturating_add(entry.value().len); + } + + let mut replica_cache_nodes = Vec::new(); + for entry in self.inner().node_kv_cache_controller.iter() { + let owner_node = entry.key().clone(); + let cache = entry.value().clone(); + let node_space_size = self + .inner() + .view() + .master_seg_manager() + .get_node_space_size(owner_node.as_str()); + let base_capacity_bytes = (node_space_size as f32 * MOKA_CACHE_CAPACITY_RATIO) as u64; + let reserved_capacity_bytes = self + .inner() + .node_cache_reserved_capacity + .get(owner_node.as_str()) + .map(|reserved| reserved.total_reserved_bytes()) + .unwrap_or(0); + let effective_capacity_bytes = cache.policy().max_capacity().unwrap_or(0); + replica_cache_nodes.push(ReplicaCacheNodeObserveSnapshot { + owner_node, + entries: cache.entry_count(), + weighted_bytes: cache.weighted_size(), + effective_capacity_bytes, + reserved_capacity_bytes, + base_capacity_bytes, + }); + } + + MasterRuntimeObserveSnapshot { + get_holding_entries: self.inner().get_holding.total() as u64, + get_holding_bytes, + replica_cache_nodes, + } } + + fn spawn_runtime_observe_reporter(&self) { + let view = self.0.view().clone(); + let view_task = view.clone(); + view.spawn("master_runtime_observe_reporter", async move { + let mut interval = tokio::time::interval(Duration::from_secs(30)); + let mut shutdown_waiter = view_task.register_shutdown_waiter(); + loop { + tokio::select! { + _ = shutdown_waiter.wait() => break, + _ = interval.tick() => { + let snapshot = view_task.master_kv_router().runtime_observe_snapshot(); + let metrics = view_task.metric_reporter().metrics(); + metrics.set_kv_holding_entries( + "master_get_holding", + snapshot.get_holding_entries, + ); + metrics.set_kv_holding_bytes( + "master_get_holding", + snapshot.get_holding_bytes, + ); + for node in snapshot.replica_cache_nodes { + metrics.set_kv_replica_cache_entries( + node.owner_node.as_str(), + node.entries, + ); + metrics.set_kv_replica_cache_weighted_bytes( + node.owner_node.as_str(), + node.weighted_bytes, + ); + metrics.set_kv_replica_cache_capacity_bytes( + node.owner_node.as_str(), + "effective", + node.effective_capacity_bytes, + ); + metrics.set_kv_replica_cache_capacity_bytes( + node.owner_node.as_str(), + "reserved", + node.reserved_capacity_bytes, + ); + metrics.set_kv_replica_cache_capacity_bytes( + node.owner_node.as_str(), + "base", + node.base_capacity_bytes, + ); + } + } + } + } + }); + } + + // Note: no additional getters for reserved bytes; policy currently relies only on adjust calls. } // moved to crate::metrics::client diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs index 9d5eb1d..efb12c9 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs @@ -1,7 +1,7 @@ use crate::{ cluster_manager::NodeIDString, p2p::msg_pack::{MsgPackSerializePart, RPCReq}, - rpcresp_kvresult_convert::msg_and_error::{ErrorCode, MsgId}, + rpcresp_kvresult_convert::msg_and_error::{ErrorCode, MsgId, OK}, }; use bitcode::{Decode, Encode}; use std::collections::HashMap; @@ -103,6 +103,113 @@ impl RPCReq for GetDoneReq { type Resp = GetDoneResp; } +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchGetStartReq { + pub keys: Vec, +} +impl MsgPackSerializePart for BatchGetStartReq { + fn msg_id(&self) -> u32 { + MsgId::BatchGetStartReq as u32 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchGetStartItemResp { + pub get_id: u64, + pub node_id: NodeIDString, + pub put_id: PutIDForAKey, + pub target_addr: u64, + pub src_addr: u64, + pub target_base_addr: u64, + pub src_base_addr: u64, + pub len: u64, + pub error_code: ErrorCode, + pub error_json: String, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchGetStartResp { + pub items: Vec, + pub error_code: ErrorCode, + pub error_json: String, + pub server_process_us: i64, +} +impl MsgPackSerializePart for BatchGetStartResp { + fn msg_id(&self) -> u32 { + MsgId::BatchGetStartResp as u32 + } +} +impl RPCReq for BatchGetStartReq { + type Resp = BatchGetStartResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchGetRevokeReq { + pub get_ids: Vec, +} +impl MsgPackSerializePart for BatchGetRevokeReq { + fn msg_id(&self) -> u32 { + MsgId::BatchGetRevokeReq as u32 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchGetRevokeItemResp { + pub get_id: u64, + pub error_code: ErrorCode, + pub error_json: String, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchGetRevokeResp { + pub items: Vec, + pub error_code: ErrorCode, + pub error_json: String, +} +impl MsgPackSerializePart for BatchGetRevokeResp { + fn msg_id(&self) -> u32 { + MsgId::BatchGetRevokeResp as u32 + } +} +impl RPCReq for BatchGetRevokeReq { + type Resp = BatchGetRevokeResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchGetDoneReq { + pub get_ids: Vec, +} +impl MsgPackSerializePart for BatchGetDoneReq { + fn msg_id(&self) -> u32 { + MsgId::BatchGetDoneReq as u32 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchGetDoneItemResp { + pub get_id: u64, + pub holder_id: u64, + pub allocation_mode: GetAllocationMode, + pub error_code: ErrorCode, + pub error_json: String, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchGetDoneResp { + pub items: Vec, + pub error_code: ErrorCode, + pub error_json: String, + pub server_process_us: i64, +} +impl MsgPackSerializePart for BatchGetDoneResp { + fn msg_id(&self) -> u32 { + MsgId::BatchGetDoneResp as u32 + } +} +impl RPCReq for BatchGetDoneReq { + type Resp = BatchGetDoneResp; +} + // --- RPC for CountPrefix --- #[derive(Default, Debug, Clone, Encode, Decode)] @@ -156,6 +263,117 @@ impl RPCReq for GetMasterOnlyMetricPartReq { type Resp = GetMasterOnlyMetricPartResp; } +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ReserveLocalGrantReq; +impl MsgPackSerializePart for ReserveLocalGrantReq { + fn msg_id(&self) -> u32 { + MsgId::ReserveLocalGrantReq as u32 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ReserveLocalGrantResp { + pub grant_id: u64, + pub node_id: NodeIDString, + pub addr: u64, + pub base_addr: u64, + pub len: u64, + pub error_code: ErrorCode, + pub error_json: String, + pub server_process_us: i64, +} +impl MsgPackSerializePart for ReserveLocalGrantResp { + fn msg_id(&self) -> u32 { + MsgId::ReserveLocalGrantResp as u32 + } +} +impl RPCReq for ReserveLocalGrantReq { + type Resp = ReserveLocalGrantResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ReleaseLocalGrantReq { + pub grant_id: u64, +} +impl MsgPackSerializePart for ReleaseLocalGrantReq { + fn msg_id(&self) -> u32 { + MsgId::ReleaseLocalGrantReq as u32 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ReleaseLocalGrantResp { + pub error_code: ErrorCode, + pub error_json: String, + pub server_process_us: i64, +} +impl MsgPackSerializePart for ReleaseLocalGrantResp { + fn msg_id(&self) -> u32 { + MsgId::ReleaseLocalGrantResp as u32 + } +} +impl RPCReq for ReleaseLocalGrantReq { + type Resp = ReleaseLocalGrantResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPreparePutKeyItemReq { + pub key: String, + pub reject_if_inflight_same_key: bool, + pub reject_if_exist_same_key: bool, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPreparePutKeysReq { + pub items: Vec, +} +impl MsgPackSerializePart for BatchPreparePutKeysReq { + fn msg_id(&self) -> u32 { + MsgId::BatchPreparePutKeysReq as u32 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPreparePutKeysResp { + pub reservation_ids: Vec, + pub error_code: ErrorCode, + pub error_json: String, + pub server_process_us: i64, +} +impl MsgPackSerializePart for BatchPreparePutKeysResp { + fn msg_id(&self) -> u32 { + MsgId::BatchPreparePutKeysResp as u32 + } +} +impl RPCReq for BatchPreparePutKeysReq { + type Resp = BatchPreparePutKeysResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchReleasePutKeyReservationsReq { + pub reservation_ids: Vec, +} +impl MsgPackSerializePart for BatchReleasePutKeyReservationsReq { + fn msg_id(&self) -> u32 { + MsgId::BatchReleasePutKeyReservationsReq as u32 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchReleasePutKeyReservationsResp { + pub error_code: ErrorCode, + pub error_json: String, + pub server_process_us: i64, +} +impl MsgPackSerializePart for BatchReleasePutKeyReservationsResp { + fn msg_id(&self) -> u32 { + MsgId::BatchReleasePutKeyReservationsResp as u32 + } +} +impl RPCReq for BatchReleasePutKeyReservationsReq { + type Resp = BatchReleasePutKeyReservationsResp; +} + // --- RPC for Put --- #[derive(Default, Debug, Clone, Encode, Decode)] @@ -163,6 +381,8 @@ pub struct PutStartReq { pub key: String, pub len: u64, pub reject_if_inflight_same_key: bool, + pub reject_if_exist_same_key: bool, + pub write_through: bool, /// Prefer placing the target allocation on any kvclient within this sub_cluster. pub preferred_sub_cluster: Option, /// Optional source-node override for side-transfer workers that share an owner's mmap. @@ -222,12 +442,26 @@ impl RPCReq for PutRevokeReq { type Resp = PutRevokeResp; } +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct PutDoneCommittedSlot { + pub grant_id: u64, + pub slot_index: u32, + pub slot_size: u64, + pub addr: u64, + pub base_addr: u64, + pub len: u64, +} + #[derive(Default, Debug, Clone, Encode, Decode)] pub struct PutDoneReq { pub key: String, pub put_id: PutIDForAKey, /// Optional lease to attach this key to on commit pub lease_id: Option, + /// Optional local committed slot descriptor for local-first publish path. + pub committed_slot: Option, + /// Ask master to keep a local read holder for the committing node. + pub publish_local_cache: bool, } impl MsgPackSerializePart for PutDoneReq { fn msg_id(&self) -> u32 { @@ -240,6 +474,8 @@ pub struct PutDoneResp { pub error_json: String, /// Server-side processing time in microseconds for this RPC handler pub server_process_us: i64, + /// Holder id for an owner-local cache view, present only when requested. + pub local_cache_holder_id: Option, } impl MsgPackSerializePart for PutDoneResp { fn msg_id(&self) -> u32 { @@ -250,6 +486,220 @@ impl RPCReq for PutDoneReq { type Resp = PutDoneResp; } +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPutStartItemReq { + pub key: String, + pub len: u64, + pub reject_if_inflight_same_key: bool, + pub reject_if_exist_same_key: bool, + pub write_through: bool, + pub preferred_sub_cluster: Option, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPutStartReq { + pub items: Vec, +} +impl MsgPackSerializePart for BatchPutStartReq { + fn msg_id(&self) -> u32 { + MsgId::BatchPutStartReq as u32 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPutStartItemResp { + pub put_id: PutIDForAKey, + pub node_id: NodeIDString, + pub target_addr: u64, + pub src_addr: u64, + pub target_base_addr: u64, + pub src_base_addr: u64, + pub len: u64, + pub error_code: ErrorCode, + pub error_json: String, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPutStartResp { + pub items: Vec, + pub error_code: ErrorCode, + pub error_json: String, + pub server_process_us: i64, +} +impl MsgPackSerializePart for BatchPutStartResp { + fn msg_id(&self) -> u32 { + MsgId::BatchPutStartResp as u32 + } +} +impl RPCReq for BatchPutStartReq { + type Resp = BatchPutStartResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPutRevokeItemReq { + pub key: String, + pub put_id: PutIDForAKey, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPutRevokeReq { + pub items: Vec, +} +impl MsgPackSerializePart for BatchPutRevokeReq { + fn msg_id(&self) -> u32 { + MsgId::BatchPutRevokeReq as u32 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPutRevokeItemResp { + pub key: String, + pub put_id: PutIDForAKey, + pub error_code: ErrorCode, + pub error_json: String, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPutRevokeResp { + pub items: Vec, + pub error_code: ErrorCode, + pub error_json: String, +} +impl MsgPackSerializePart for BatchPutRevokeResp { + fn msg_id(&self) -> u32 { + MsgId::BatchPutRevokeResp as u32 + } +} +impl RPCReq for BatchPutRevokeReq { + type Resp = BatchPutRevokeResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPutDoneItemReq { + pub key: String, + pub put_id: PutIDForAKey, + pub lease_id: Option, + pub committed_slot: Option, + pub publish_local_cache: bool, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPutDoneReq { + pub items: Vec, +} +impl MsgPackSerializePart for BatchPutDoneReq { + fn msg_id(&self) -> u32 { + MsgId::BatchPutDoneReq as u32 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPutDoneItemResp { + pub key: String, + pub put_id: PutIDForAKey, + pub error_code: ErrorCode, + pub error_json: String, + pub local_cache_holder_id: Option, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPutDoneResp { + pub items: Vec, + pub error_code: ErrorCode, + pub error_json: String, + pub server_process_us: i64, +} +impl MsgPackSerializePart for BatchPutDoneResp { + fn msg_id(&self) -> u32 { + MsgId::BatchPutDoneResp as u32 + } +} +impl RPCReq for BatchPutDoneReq { + type Resp = BatchPutDoneResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct PutAppendStartReq { + pub key: String, + pub put_id: PutIDForAKey, + pub len: u64, + pub preferred_sub_cluster: Option, +} +impl MsgPackSerializePart for PutAppendStartReq { + fn msg_id(&self) -> u32 { + MsgId::PutAppendStartReq as u32 + } +} +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct PutAppendStartResp { + pub scheduled: bool, + pub node_id: NodeIDString, + pub target_addr: u64, + pub target_base_addr: u64, + pub len: u64, + pub error_code: ErrorCode, + pub error_json: String, + pub server_process_us: i64, +} +impl MsgPackSerializePart for PutAppendStartResp { + fn msg_id(&self) -> u32 { + MsgId::PutAppendStartResp as u32 + } +} +impl RPCReq for PutAppendStartReq { + type Resp = PutAppendStartResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct PutAppendRevokeReq { + pub key: String, + pub put_id: PutIDForAKey, +} +impl MsgPackSerializePart for PutAppendRevokeReq { + fn msg_id(&self) -> u32 { + MsgId::PutAppendRevokeReq as u32 + } +} +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct PutAppendRevokeResp { + pub error_code: ErrorCode, + pub error_json: String, +} +impl MsgPackSerializePart for PutAppendRevokeResp { + fn msg_id(&self) -> u32 { + MsgId::PutAppendRevokeResp as u32 + } +} +impl RPCReq for PutAppendRevokeReq { + type Resp = PutAppendRevokeResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct PutAppendDoneReq { + pub key: String, + pub put_id: PutIDForAKey, +} +impl MsgPackSerializePart for PutAppendDoneReq { + fn msg_id(&self) -> u32 { + MsgId::PutAppendDoneReq as u32 + } +} +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct PutAppendDoneResp { + pub appended: bool, + pub error_code: ErrorCode, + pub error_json: String, + pub server_process_us: i64, +} +impl MsgPackSerializePart for PutAppendDoneResp { + fn msg_id(&self) -> u32 { + MsgId::PutAppendDoneResp as u32 + } +} +impl RPCReq for PutAppendDoneReq { + type Resp = PutAppendDoneResp; +} + // --- RPC for MemHolder KeepAlive --- #[derive(Default, Debug, Clone, Encode, Decode)] @@ -414,6 +864,31 @@ impl RPCReq for GetMetaReq { type Resp = GetMetaResp; } +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchIsExistReq { + pub keys: Vec, +} +impl MsgPackSerializePart for BatchIsExistReq { + fn msg_id(&self) -> u32 { + MsgId::BatchIsExistReq as u32 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchIsExistResp { + pub exists_list: Vec, + pub error_code: ErrorCode, + pub error_json: String, +} +impl MsgPackSerializePart for BatchIsExistResp { + fn msg_id(&self) -> u32 { + MsgId::BatchIsExistResp as u32 + } +} +impl RPCReq for BatchIsExistReq { + type Resp = BatchIsExistResp; +} + // --- RPC for Batch Delete Client KV Meta Cache --- #[derive(Debug, Clone, Encode, Decode, Default)] diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/placement.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/placement.rs index d9f509f..d6c04bf 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/placement.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/placement.rs @@ -6,8 +6,8 @@ use crate::{ rpcresp_kvresult_convert::msg_and_error::KvError, }; use async_trait::async_trait; -use rand::Rng; use rand::seq::SliceRandom; +use rand::Rng; use super::MasterKvRouterView; @@ -40,8 +40,8 @@ pub trait PlacementPolicy: Send + Sync { /// Change the type alias to switch behavior (and rebuild): /// - `LocalFirstPlacementPolicy` prefers local placement when possible. /// - `RandomPlacementPolicy` selects a random eligible target. -// pub type PlacementDefault = LocalFirstPlacementPolicy; -pub type PlacementDefault = RandomPlacementPolicy; +pub type PlacementDefault = LocalFirstPlacementPolicy; +// pub type PlacementDefault = RandomPlacementPolicy; /// A policy that prefers placing on the requesting node when possible. pub struct LocalFirstPlacementPolicy; diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs index 70d8858..e8598e8 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs @@ -1,24 +1,41 @@ use super::NodeValueReplicaDesc; use super::{ - InflightPutAllocation, InflightPutInfo, KvRouteInfo, MasterKvRouterView, PutPlacementMode, - msg_pack::{PutDoneReq, PutDoneResp, PutRevokeReq, PutRevokeResp, PutStartReq, PutStartResp}, + msg_pack::{ + BatchPreparePutKeysReq, BatchPreparePutKeysResp, BatchPutDoneItemResp, BatchPutDoneReq, + BatchPutDoneResp, BatchPutRevokeItemResp, BatchPutRevokeReq, BatchPutRevokeResp, + BatchPutStartItemResp, BatchPutStartReq, BatchPutStartResp, + BatchReleasePutKeyReservationsReq, BatchReleasePutKeyReservationsResp, PutAppendDoneReq, + PutAppendDoneResp, PutAppendRevokeReq, PutAppendRevokeResp, PutAppendStartReq, + PutAppendStartResp, PutDoneReq, PutDoneResp, PutRevokeReq, PutRevokeResp, PutStartReq, + PutStartResp, ReleaseLocalGrantReq, ReleaseLocalGrantResp, ReserveLocalGrantReq, + ReserveLocalGrantResp, + }, placement::PutPlacementTarget, + CommittedSlotReplica, InflightPutAllocation, InflightPutAppendInfo, InflightPutCommitInfo, + InflightPutInfo, KvReplicaBacking, KvRouteInfo, LocalReserveGrantInfo, MasterKvRouterView, + OwnerHoldingGetInfo, PreparedPutKeyReservationInfo, PutPlacementMode, ReservedCapacityReason, }; -use crate::master_kv_router::OneKvNodesRoutes; use crate::master_kv_router::delete::DeleteKeyInfo; +use crate::master_kv_router::OneKvNodesRoutes; +use crate::memholder::MemholderManagerTrait; use crate::{ - cluster_manager::{META_KEY_LOCAL_IPC_ROOT, NodeID}, - master_seg_manager::one_seg_allocator::Allocation, + cluster_manager::{ + NodeID, META_KEY_LOCAL_IPC_ROOT, META_KEY_SHARED_STORAGE_NODE_ID, + META_KEY_SHARED_STORAGE_NODE_START_TIME, + }, + master_seg_manager::{one_seg_allocator::Allocation, MasterSegManagerAccessTrait}, p2p::msg_pack::MsgPack, - rpcresp_kvresult_convert::msg_and_error, + rpcresp_kvresult_convert::msg_and_error::{self, kv}, + OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES, }; -use fluxon_commu::{META_KEY_SHARED_STORAGE_NODE_ID, META_KEY_SHARED_STORAGE_NODE_START_TIME}; +use chrono::Utc; +use limit_thirdparty::tokio; use parking_lot::Mutex; use parking_lot::RwLock; use rand::seq::SliceRandom; use std::{ - collections::HashMap, - sync::{Arc, atomic::AtomicU32}, + collections::{HashMap, HashSet}, + sync::{atomic::AtomicU32, Arc}, }; pub type PutIDForAKey = (u64, u32); @@ -153,16 +170,325 @@ fn validate_put_start_source_node_override( Ok(()) } +fn current_route_needs_remote_replica( + route: &OneKvNodesRoutes, + source_node_id: &NodeID, + verify_put_id: PutIDForAKey, +) -> bool { + if route.put_id != verify_put_id { + return false; + } + route + .nodes_replicas + .read() + .values() + .all(|replica| replica.tomb_tag.is_tomb() || replica.node_id == *source_node_id) +} + +fn append_current_route_replica_if_matching( + view: &MasterKvRouterView, + key: &str, + put_id: PutIDForAKey, + node_id: NodeID, + allocation: Allocation, +) -> bool { + let Some(one_kv_nodes_routes) = view.master_kv_router().inner().kv_routes.get(key) else { + tracing::debug!( + "append_current_route_replica_if_matching skipped because route disappeared: key={} put_id=({},{})", + key, + put_id.0, + put_id.1 + ); + return false; + }; + if one_kv_nodes_routes.put_id != put_id { + tracing::debug!( + "append_current_route_replica_if_matching skipped because version changed: key={} current_put_id=({},{}) append_put_id=({},{})", + key, + one_kv_nodes_routes.put_id.0, + one_kv_nodes_routes.put_id.1, + put_id.0, + put_id.1 + ); + return false; + } + let Some(tomb_tag) = view.master_seg_manager().get_node_tomb_tag(&node_id) else { + tracing::warn!( + "append_current_route_replica_if_matching skipped because target node tomb-tag missing: key={} put_id=({},{}) node_id={}", + key, + put_id.0, + put_id.1, + node_id + ); + return false; + }; + if tomb_tag.is_tomb() { + tracing::warn!( + "append_current_route_replica_if_matching skipped because target node is tomb: key={} put_id=({},{}) node_id={}", + key, + put_id.0, + put_id.1, + node_id + ); + return false; + } + let alloc_cap = allocation.capcity(); + let req_weight = if alloc_cap > u32::MAX as u64 { + tracing::warn!( + "moka weight saturation on put append: key={} put_id=({},{}) cap={}B exceeds u32::MAX; weight set to u32::MAX", + key, + put_id.0, + put_id.1, + alloc_cap + ); + u32::MAX + } else { + alloc_cap as u32 + }; + let lease_id = one_kv_nodes_routes.lease_id; + one_kv_nodes_routes.nodes_replicas.write().insert( + node_id.clone(), + KvRouteInfo { + node_id: node_id.clone(), + backing: KvReplicaBacking::Allocation(Arc::new(allocation)), + tomb_tag, + }, + ); + if lease_id.is_none() { + if let Some(cache) = view.master_kv_router().get_node_cache_controller(&node_id) { + cache.insert( + key.to_string(), + NodeValueReplicaDesc { + weight_bytes: req_weight, + put_id, + }, + ); + } + } + true +} + +fn choose_remote_append_target( + view: &MasterKvRouterView, + source_node_id: &NodeID, + excluded_nodes: &HashSet, + preferred_sub_cluster: Option<&str>, + len: u64, +) -> msg_and_error::KvResult<(NodeID, Allocation)> { + let seg_manager = view.master_seg_manager(); + let mut last_no_space_ctx: Option<(String, String, u64, u64)> = None; + + if let Some(sc) = preferred_sub_cluster { + let mut preferred_nodes: Vec = view + .cluster_manager() + .get_client_members() + .into_iter() + .filter_map(|m| (m.sub_cluster.as_deref() == Some(sc)).then_some(m.id.into())) + .collect(); + preferred_nodes.retain(|node_id| { + node_id.as_ref() != source_node_id.as_ref() && !excluded_nodes.contains(node_id) + }); + preferred_nodes.shuffle(&mut rand::thread_rng()); + for node_id in preferred_nodes { + let node_allocators = seg_manager.get_node_allocators(&node_id); + let Some(allocator) = node_allocators.choose(&mut rand::thread_rng()).cloned() else { + continue; + }; + let total = allocator.total_size_bytes(); + let used = allocator.used_size_bytes(); + let free = total.saturating_sub(used); + last_no_space_ctx = Some(( + node_id.as_ref().to_string(), + allocator.seg_device_id.clone(), + total, + free, + )); + if let Ok(allocation) = allocator.allocate(len) { + return Ok((node_id, allocation)); + } + } + } + + let all_segs = seg_manager.get_all_segments_allocator(); + let mut candidates: Vec<( + NodeID, + Arc, + )> = all_segs + .into_iter() + .filter_map(|(node_id, allocator)| { + let node_id: NodeID = node_id.into(); + if node_id.as_ref() == source_node_id.as_ref() || excluded_nodes.contains(&node_id) { + return None; + } + Some((node_id, allocator)) + }) + .collect(); + candidates.shuffle(&mut rand::thread_rng()); + for (node_id, allocator) in candidates { + let total = allocator.total_size_bytes(); + let used = allocator.used_size_bytes(); + let free = total.saturating_sub(used); + last_no_space_ctx = Some(( + node_id.as_ref().to_string(), + allocator.seg_device_id.clone(), + total, + free, + )); + if let Ok(allocation) = allocator.allocate(len) { + return Ok((node_id, allocation)); + } + } + + Err( + if let Some((node, segment, total_capacity, free_capacity)) = last_no_space_ctx { + msg_and_error::KvError::Api(msg_and_error::ApiError::NoSpace { + node, + segment, + total_capacity, + free_capacity, + }) + } else { + msg_and_error::KvError::Api(msg_and_error::ApiError::NoSpace { + node: "unknown".to_string(), + segment: "unknown".to_string(), + total_capacity: 0, + free_capacity: 0, + }) + }, + ) +} + +fn allocate_from_node_local_segment( + view: &MasterKvRouterView, + node_id: &NodeID, + len: u64, + op_name: &str, +) -> msg_and_error::KvResult { + let node_allocators = view.master_seg_manager().get_node_allocators(node_id); + if node_allocators.is_empty() { + tracing::warn!("No allocators found for {} node={}", op_name, node_id); + return Err(msg_and_error::KvError::Api( + msg_and_error::ApiError::RegisterSegmentFailed { + detail: format!( + "{} node has no registered segments: node={}", + op_name, node_id + ), + }, + )); + } + + let allocator = node_allocators.choose(&mut rand::thread_rng()).unwrap(); + for attempt in 1..=3 { + if let Ok(allocation) = allocator.allocate(len) { + return Ok(allocation); + } + tracing::warn!( + "Allocation attempt {}/3 failed for {} node={} len={}", + attempt, + op_name, + node_id, + len + ); + } + + let total = allocator.total_size_bytes(); + let used = allocator.used_size_bytes(); + let free = total.saturating_sub(used); + Err(msg_and_error::KvError::Api( + msg_and_error::ApiError::NoSpace { + node: node_id.as_ref().to_string(), + segment: allocator.seg_device_id.clone(), + total_capacity: total, + free_capacity: free, + }, + )) +} + +fn reserve_write_back_remote_append( + view: &MasterKvRouterView, + key: &str, + put_id: PutIDForAKey, + source_node_id: &NodeID, + preferred_sub_cluster: Option<&str>, + len: u64, +) -> msg_and_error::KvResult { + let (target_node_id, target_allocation) = choose_remote_append_target( + view, + source_node_id, + &HashSet::new(), + preferred_sub_cluster, + len, + )?; + tracing::debug!( + "write-back remote append reserved: key={} put_id=({},{}) source_node_id={} target_node_id={} preferred_sub_cluster={:?} len={}", + key, + put_id.0, + put_id.1, + source_node_id, + target_node_id, + preferred_sub_cluster, + len + ); + Ok(InflightPutAppendInfo { + node_id: target_node_id, + key: key.to_string(), + put_id, + target_allocation: Arc::new(Mutex::new(Some(target_allocation))), + }) +} + +fn try_reserve_write_back_remote_append( + view: &MasterKvRouterView, + key: &str, + put_id: PutIDForAKey, + source_node_id: &NodeID, + preferred_sub_cluster: Option<&str>, + len: u64, +) -> msg_and_error::KvResult> { + match reserve_write_back_remote_append( + view, + key, + put_id, + source_node_id, + preferred_sub_cluster, + len, + ) { + Ok(reserved) => Ok(Some(reserved)), + Err(msg_and_error::KvError::Api(msg_and_error::ApiError::NoSpace { + node, + segment, + total_capacity, + free_capacity, + })) => { + tracing::info!( + "write-back remote append not scheduled; fallback to local-only commit: key={} put_id=({},{}) source_node_id={} preferred_sub_cluster={:?} node={} segment={} total_capacity={} free_capacity={}", + key, + put_id.0, + put_id.1, + source_node_id, + preferred_sub_cluster, + node, + segment, + total_capacity, + free_capacity + ); + Ok(None) + } + Err(err) => Err(err), + } +} + pub async fn handle_put_start( view: MasterKvRouterView, req: MsgPack, req_node_id: NodeID, ) -> (PutIDForAKey, MsgPack) { let key = req.serialize_part.key.clone(); - if let Err(err) = view - .master_kv_router() - .reserve_inflight_put_key(&key, req.serialize_part.reject_if_inflight_same_key) - { + if let Err(err) = view.master_kv_router().reserve_inflight_put_key( + &key, + req.serialize_part.reject_if_inflight_same_key, + req.serialize_part.reject_if_exist_same_key, + ) { let resp: PutStartResp = crate::rpcresp_kvresult_convert::FromError::from_error(&err); return ( (0, 0), @@ -199,58 +525,14 @@ pub async fn handle_put_start( let inflight_put_key: (String, u64, u32) = (key.clone(), put_id.0, put_id.1); - // randomly select one src_allocator - let src_allocation = { - let src_node_allocators = view - .master_seg_manager() - .get_node_allocators(&source_node_id); - if src_node_allocators.is_empty() { - tracing::warn!( - "No allocators found for put_start source node: requester={} source={}", - req_node_id, - source_node_id - ); - let err = msg_and_error::KvError::Api(msg_and_error::ApiError::RegisterSegmentFailed { - detail: format!( - "put_start source node has no registered segments: requester={} source={}", - req_node_id, source_node_id - ), - }); - let resp: PutStartResp = crate::rpcresp_kvresult_convert::FromError::from_error(&err); - return ( - (0, 0), - MsgPack { - serialize_part: resp, - raw_bytes: Vec::new(), - }, - ); - } - - let src_allocator = src_node_allocators.choose(&mut rand::thread_rng()).unwrap(); - - let mut allocated_addr: Option = None; - for attempt in 1..=3 { - if let Ok(allocation) = src_allocator.allocate(req.serialize_part.len) { - allocated_addr = Some(allocation); - break; - } else { - tracing::warn!( - "Allocation attempt {}/3 failed for put_id {:?}", - attempt, - put_id - ); - } - } - if allocated_addr.is_none() { - let total = src_allocator.total_size_bytes(); - let used = src_allocator.used_size_bytes(); - let free = total.saturating_sub(used); - let err = msg_and_error::KvError::Api(msg_and_error::ApiError::NoSpace { - node: source_node_id.as_ref().to_string(), - segment: src_allocator.seg_device_id.clone(), - total_capacity: total, - free_capacity: free, - }); + let src_allocation = match allocate_from_node_local_segment( + &view, + &source_node_id, + req.serialize_part.len, + "put_start source", + ) { + Ok(allocation) => allocation, + Err(err) => { let resp: PutStartResp = crate::rpcresp_kvresult_convert::FromError::from_error(&err); return ( (0, 0), @@ -260,25 +542,29 @@ pub async fn handle_put_start( }, ); } - allocated_addr.unwrap() }; // Keep src allocation alive across retry attempts until we have a successful target. let mut src_allocation = Some(src_allocation); - let finalize = |node_id: NodeID, + let finalize = |commit_node_id: NodeID, + response_node_id: NodeID, inflight_alloc: InflightPutAllocation, + remote_append: Option, src_addr: u64, target_addr: u64, src_base_addr: u64, target_base_addr: u64, len: u64| { let info = InflightPutInfo { - node_id: node_id.clone(), key: key.clone(), len, req_node_id: req_node_id.clone(), - src_target_allocation: Arc::new(Mutex::new(Some(inflight_alloc))), + commit_info: InflightPutCommitInfo { + node_id: commit_node_id, + src_target_allocation: Arc::new(Mutex::new(Some(inflight_alloc))), + }, + remote_append, }; let view_task = view.clone(); @@ -293,7 +579,7 @@ pub async fn handle_put_start( let resp = PutStartResp { put_id, - node_id: node_id.into(), + node_id: response_node_id.into(), src_addr, target_addr, src_base_addr, @@ -314,17 +600,22 @@ pub async fn handle_put_start( } }; - let put_target = view - .master_kv_router() - .inner() - .policy - .select_put_target( - &view, - &source_node_id, - req.serialize_part.preferred_sub_cluster.as_deref(), - req.serialize_part.len, - ) - .await; + let put_target = if req.serialize_part.write_through { + view.master_kv_router() + .inner() + .policy + .select_put_target( + &view, + &source_node_id, + req.serialize_part.preferred_sub_cluster.as_deref(), + req.serialize_part.len, + ) + .await + } else { + Ok(PutPlacementTarget::Local { + node_id: source_node_id.clone(), + }) + }; match put_target { Ok(PutPlacementTarget::Local { node_id }) => { @@ -362,14 +653,58 @@ pub async fn handle_put_start( let src = src_allocation .take() .expect("src_allocation must exist when finalizing local put"); + let remote_append = if req.serialize_part.write_through { + None + } else { + match try_reserve_write_back_remote_append( + &view, + &key, + put_id, + &source_node_id, + req.serialize_part.preferred_sub_cluster.as_deref(), + req.serialize_part.len, + ) { + Ok(reserved) => reserved, + Err(err) => { + let resp: PutStartResp = + crate::rpcresp_kvresult_convert::FromError::from_error(&err); + return ( + (0, 0), + MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + }, + ); + } + } + }; + let (response_node_id, response_target_addr, response_target_base_addr, response_len) = + if let Some(remote_append) = remote_append.as_ref() { + let target_allocation_guard = remote_append.target_allocation.lock(); + let target_allocation = target_allocation_guard + .as_ref() + .expect("reserved remote append allocation must exist during put_start"); + let target_base = target_allocation.base_addr(); + let target_addr = target_base + target_allocation.addr(); + ( + remote_append.node_id.clone(), + target_addr, + target_base, + target_allocation.size(), + ) + } else { + (node_id.clone(), abs, src_base, allocation_size) + }; let fut = finalize( node_id, + response_node_id, InflightPutAllocation::Local(src), + remote_append, abs, - abs, - src_base, + response_target_addr, src_base, - allocation_size, + response_target_base_addr, + response_len, ); let result = fut.await; key_reservation.disarm(); @@ -413,11 +748,13 @@ pub async fn handle_put_start( .take() .expect("src_allocation must exist when finalizing remote put"); let fut = finalize( + node_id.clone(), node_id, InflightPutAllocation::Remote { src, target: target_allocation, }, + None, src_base + src_offset, target_base + target_offset, src_base, @@ -441,6 +778,249 @@ pub async fn handle_put_start( } } +pub async fn handle_reserve_local_grant( + view: MasterKvRouterView, + req: MsgPack, + req_node_id: NodeID, +) -> (u64, MsgPack) { + let _ = req; + + let mut allocation = match allocate_from_node_local_segment( + &view, + &req_node_id, + OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES, + "reserve_local_grant", + ) { + Ok(allocation) => allocation, + Err(err) => { + let resp: ReserveLocalGrantResp = + crate::rpcresp_kvresult_convert::FromError::from_error(&err); + return ( + 0, + MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + }, + ); + } + }; + + let reserved_bytes = allocation.capcity(); + if let Err(err) = view.master_kv_router().adjust_node_cache_reserved_capacity( + req_node_id.as_ref(), + ReservedCapacityReason::LocalReserveGrant, + reserved_bytes as i64, + ) { + let resp: ReserveLocalGrantResp = + crate::rpcresp_kvresult_convert::FromError::from_error(&err); + return ( + 0, + MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + }, + ); + } + + let view_clone = view.clone(); + let node_id_string = req_node_id.as_ref().to_string(); + allocation.set_on_drop(move || { + if let Err(e) = view_clone + .master_kv_router() + .adjust_node_cache_reserved_capacity( + &node_id_string, + ReservedCapacityReason::LocalReserveGrant, + -(reserved_bytes as i64), + ) + { + tracing::warn!( + "Failed to restore moka capacity on local reserve grant drop: node_id={}, bytes={}, err={}", + node_id_string, + reserved_bytes, + e + ); + } + }); + + let grant_id = view.master_kv_router().next_local_reserve_grant_id(); + let grant_base_addr = allocation.base_addr(); + let grant_abs_addr = grant_base_addr + allocation.addr(); + let grant_len = allocation.capcity(); + view.master_kv_router().install_local_reserve_grant( + grant_id, + LocalReserveGrantInfo { + owner_node_id: req_node_id.clone(), + allocation, + }, + ); + + ( + grant_id, + MsgPack { + serialize_part: ReserveLocalGrantResp { + grant_id, + node_id: req_node_id.into_owned(), + addr: grant_abs_addr, + base_addr: grant_base_addr, + len: grant_len, + error_code: msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + }, + raw_bytes: Vec::new(), + }, + ) +} + +pub async fn handle_release_local_grant( + view: MasterKvRouterView, + req: MsgPack, + req_node_id: NodeID, +) -> MsgPack { + let grant_id = req.serialize_part.grant_id; + let Some(grant) = view.master_kv_router().take_local_reserve_grant(grant_id) else { + tracing::info!( + "release_local_grant ignored missing grant_id={} requester_node_id={}", + grant_id, + req_node_id + ); + return MsgPack { + serialize_part: ReleaseLocalGrantResp::default(), + raw_bytes: Vec::new(), + }; + }; + + if grant.owner_node_id.as_ref() != req_node_id.as_ref() { + let owner_node_id = grant.owner_node_id.to_string(); + view.master_kv_router() + .install_local_reserve_grant(grant_id, grant); + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { + detail: format!( + "release_local_grant owner mismatch: grant_id={} owner_node_id={} requester_node_id={}", + grant_id, owner_node_id, req_node_id + ), + }); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), + raw_bytes: Vec::new(), + }; + } + + drop(grant); + MsgPack { + serialize_part: ReleaseLocalGrantResp::default(), + raw_bytes: Vec::new(), + } +} + +pub async fn handle_batch_prepare_put_keys( + view: MasterKvRouterView, + req: MsgPack, + req_node_id: NodeID, +) -> (Vec, MsgPack) { + let mut reservation_ids = Vec::with_capacity(req.serialize_part.items.len()); + for item in req.serialize_part.items { + if let Err(err) = view.master_kv_router().reserve_inflight_put_key( + &item.key, + item.reject_if_inflight_same_key, + item.reject_if_exist_same_key, + ) { + for reservation_id in reservation_ids.drain(..) { + if let Some(info) = view + .master_kv_router() + .take_prepared_put_key_reservation(reservation_id) + { + view.master_kv_router().release_inflight_put_key(&info.key); + } + } + let resp: BatchPreparePutKeysResp = + crate::rpcresp_kvresult_convert::FromError::from_error(&err); + return ( + Vec::new(), + MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + }, + ); + } + let reservation_id = view + .master_kv_router() + .next_prepared_put_key_reservation_id(); + view.master_kv_router() + .install_prepared_put_key_reservation( + reservation_id, + PreparedPutKeyReservationInfo { + owner_node_id: req_node_id.clone(), + key: item.key, + }, + ); + reservation_ids.push(reservation_id); + } + + ( + reservation_ids.clone(), + MsgPack { + serialize_part: BatchPreparePutKeysResp { + reservation_ids, + error_code: msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + }, + raw_bytes: Vec::new(), + }, + ) +} + +pub async fn handle_batch_release_put_key_reservations( + view: MasterKvRouterView, + req: MsgPack, + req_node_id: NodeID, +) -> MsgPack { + let mut taken = Vec::with_capacity(req.serialize_part.reservation_ids.len()); + for reservation_id in req.serialize_part.reservation_ids { + let Some(info) = view + .master_kv_router() + .take_prepared_put_key_reservation(reservation_id) + else { + tracing::info!( + "batch_release_put_key_reservations ignored missing reservation_id={} requester_node_id={}", + reservation_id, + req_node_id + ); + continue; + }; + if info.owner_node_id.as_ref() != req_node_id.as_ref() { + let owner_node_id = info.owner_node_id.to_string(); + view.master_kv_router() + .install_prepared_put_key_reservation(reservation_id, info); + for (restore_id, restore_info) in taken { + view.master_kv_router() + .install_prepared_put_key_reservation(restore_id, restore_info); + } + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { + detail: format!( + "batch_release_put_key_reservations owner mismatch: reservation_id={} owner_node_id={} requester_node_id={}", + reservation_id, owner_node_id, req_node_id + ), + }); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), + raw_bytes: Vec::new(), + }; + } + taken.push((reservation_id, info)); + } + + for (_reservation_id, info) in taken { + view.master_kv_router().release_inflight_put_key(&info.key); + } + + MsgPack { + serialize_part: BatchReleasePutKeyReservationsResp::default(), + raw_bytes: Vec::new(), + } +} + pub async fn handle_put_revoke( view: MasterKvRouterView, req: MsgPack, @@ -483,12 +1063,13 @@ pub async fn handle_put_done( let put_id = req.serialize_part.put_id; let lease_id_opt = req.serialize_part.lease_id; let full_put_id: (String, u64, u32) = (req.serialize_part.key.clone(), put_id.0, put_id.1); + let local_cache_holder_id: Option; // Remove from inflight_puts and store in completed_puts if let Some(InflightPutInfo { - node_id, key, - src_target_allocation, + commit_info, + remote_append, .. }) = view .master_kv_router() @@ -498,7 +1079,8 @@ pub async fn handle_put_done( .await { view.master_kv_router().release_inflight_put_key(&key); - let Some(allocs) = src_target_allocation.lock().take() else { + let node_id = commit_info.node_id; + let Some(allocs) = commit_info.src_target_allocation.lock().take() else { tracing::warn!( "Put operation with put_id {:?} not found for completion", full_put_id @@ -515,11 +1097,6 @@ pub async fn handle_put_done( }; }; - let mut target_allocation = match allocs { - InflightPutAllocation::Local(target) => target, - InflightPutAllocation::Remote { src: _src, target } => target, - }; - let Some(tomb_tag) = view.master_seg_manager().get_node_tomb_tag(&node_id) else { tracing::warn!( "Put operation with put_id {:?} not found for completion", @@ -548,7 +1125,225 @@ pub async fn handle_put_done( }; } - let target_cap_bytes = target_allocation.capcity(); + let route_committed_slot = req.serialize_part.committed_slot.clone(); + let (target_cap_bytes, completed_info, local_cache_publish_supported) = match allocs { + InflightPutAllocation::Local(mut target_allocation) => { + if let Some(slot) = route_committed_slot { + let target_cap_bytes = slot.len; + if let Some(lease_id) = lease_id_opt { + if let Err(e) = view + .master_lease_manager() + .attach_key(lease_id, key.clone(), put_id) + .await + { + let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = + e.into(); + return MsgPack { + serialize_part: + crate::rpcresp_kvresult_convert::FromError::from_error(&kv_err), + raw_bytes: Vec::new(), + }; + } + if let Err(e) = view.master_kv_router().adjust_node_cache_reserved_capacity( + node_id.as_ref(), + ReservedCapacityReason::LeaseBoundKv, + target_cap_bytes as i64, + ) { + let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = + e.into(); + return MsgPack { + serialize_part: + crate::rpcresp_kvresult_convert::FromError::from_error(&kv_err), + raw_bytes: Vec::new(), + }; + } + } + drop(target_allocation); + ( + target_cap_bytes, + KvRouteInfo { + node_id: node_id.clone(), + backing: KvReplicaBacking::CommittedSlot(CommittedSlotReplica { + owner_node_id: node_id.clone(), + grant_id: slot.grant_id, + slot_index: slot.slot_index, + slot_size: slot.slot_size, + addr: slot.addr, + len: slot.len, + base_addr: slot.base_addr, + }), + tomb_tag, + }, + false, + ) + } else { + let target_cap_bytes = target_allocation.capcity(); + if let Some(lease_id) = lease_id_opt { + if let Err(e) = view + .master_lease_manager() + .attach_key(lease_id, key.clone(), put_id) + .await + { + let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = + e.into(); + return MsgPack { + serialize_part: + crate::rpcresp_kvresult_convert::FromError::from_error(&kv_err), + raw_bytes: Vec::new(), + }; + } + if let Err(e) = view.master_kv_router().adjust_node_cache_reserved_capacity( + node_id.as_ref(), + ReservedCapacityReason::LeaseBoundKv, + target_cap_bytes as i64, + ) { + let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = + e.into(); + return MsgPack { + serialize_part: + crate::rpcresp_kvresult_convert::FromError::from_error(&kv_err), + raw_bytes: Vec::new(), + }; + } + let view_clone = view.clone(); + let node_id_string = node_id.as_ref().to_string(); + target_allocation.set_on_drop(move || { + if let Err(e) = view_clone + .master_kv_router() + .adjust_node_cache_reserved_capacity( + &node_id_string, + ReservedCapacityReason::LeaseBoundKv, + -(target_cap_bytes as i64), + ) + { + tracing::warn!( + "Failed to restore moka capacity on drop: node_id={}, bytes={}, err={}", + node_id_string, + target_cap_bytes, + e + ); + } + }); + } + ( + target_cap_bytes, + KvRouteInfo { + node_id: node_id.clone(), + backing: KvReplicaBacking::Allocation(Arc::new(target_allocation)), + tomb_tag, + }, + true, + ) + } + } + InflightPutAllocation::Remote { + src: _src, + mut target, + } => { + let target_cap_bytes = target.capcity(); + if let Some(lease_id) = lease_id_opt { + if let Err(e) = view + .master_lease_manager() + .attach_key(lease_id, key.clone(), put_id) + .await + { + let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = + e.into(); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error( + &kv_err, + ), + raw_bytes: Vec::new(), + }; + } + if let Err(e) = view.master_kv_router().adjust_node_cache_reserved_capacity( + node_id.as_ref(), + ReservedCapacityReason::LeaseBoundKv, + target_cap_bytes as i64, + ) { + let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = + e.into(); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error( + &kv_err, + ), + raw_bytes: Vec::new(), + }; + } + let view_clone = view.clone(); + let node_id_string = node_id.as_ref().to_string(); + target.set_on_drop(move || { + if let Err(e) = view_clone + .master_kv_router() + .adjust_node_cache_reserved_capacity( + &node_id_string, + ReservedCapacityReason::LeaseBoundKv, + -(target_cap_bytes as i64), + ) + { + tracing::warn!( + "Failed to restore moka capacity on drop: node_id={}, bytes={}, err={}", + node_id_string, + target_cap_bytes, + e + ); + } + }); + } + ( + target_cap_bytes, + KvRouteInfo { + node_id: node_id.clone(), + backing: KvReplicaBacking::Allocation(Arc::new(target)), + tomb_tag, + }, + false, + ) + } + InflightPutAllocation::LocalCommittedSlot(slot) => { + let target_cap_bytes = slot.len; + if let Some(lease_id) = lease_id_opt { + if let Err(e) = view + .master_lease_manager() + .attach_key(lease_id, key.clone(), put_id) + .await + { + let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = + e.into(); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error( + &kv_err, + ), + raw_bytes: Vec::new(), + }; + } + if let Err(e) = view.master_kv_router().adjust_node_cache_reserved_capacity( + node_id.as_ref(), + ReservedCapacityReason::LeaseBoundKv, + target_cap_bytes as i64, + ) { + let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = + e.into(); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error( + &kv_err, + ), + raw_bytes: Vec::new(), + }; + } + } + ( + target_cap_bytes, + KvRouteInfo { + node_id: node_id.clone(), + backing: KvReplicaBacking::CommittedSlot(slot), + tomb_tag, + }, + false, + ) + } + }; + // NOTE on weight sizing for moka cache: // - moka's `weigher` returns a u32 per-entry weight while the cache's // `max_capacity` and `weighted_size()` use u64. If an allocation's @@ -562,6 +1357,54 @@ pub async fn handle_put_done( // u32::MAX when `capcity()` is larger than u32::MAX. This keeps the // cache accounting conservative (evicts earlier rather than later) // and prevents weight=0 due to truncation. + local_cache_holder_id = if req.serialize_part.publish_local_cache { + if !local_cache_publish_supported { + let err = msg_and_error::KvError::Api( + msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "publish_local_cache requires owner-local allocation backing; key={} put_id=({},{})", + key, put_id.0, put_id.1 + ), + }, + ); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), + raw_bytes: Vec::new(), + }; + }; + let KvReplicaBacking::Allocation(allocation) = &completed_info.backing else { + let err = msg_and_error::KvError::Api( + msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "publish_local_cache requires allocation backing; key={} put_id=({},{})", + key, put_id.0, put_id.1 + ), + }, + ); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), + raw_bytes: Vec::new(), + }; + }; + let holder_id = view + .master_kv_router() + .inner() + .next_holder_id + .fetch_add(1, std::sync::atomic::Ordering::Relaxed); + view.master_kv_router().inner().get_holding.insert( + crate::memholder::NodeHolderKey::new(node_id.to_string(), holder_id), + OwnerHoldingGetInfo { + key: key.clone(), + holding_node_id: node_id.clone(), + len: allocation.size(), + allocation: allocation.clone(), + }, + ); + Some(holder_id) + } else { + None + }; + let saturated_weight_u32 = if target_cap_bytes > u32::MAX as u64 { tracing::warn!( "moka weight saturation: key={} put_id=({},{}) cap={}B exceeds u32::MAX; weight set to u32::MAX", @@ -576,64 +1419,6 @@ pub async fn handle_put_done( }; // Note: moka cache insertion happens after commit in a spawned task // using the same saturated weight; avoid unused local here. - // If lease is provided, attach first and fail fast on error - if let Some(lease_id) = lease_id_opt { - if let Err(e) = view - .master_lease_manager() - .attach_key(lease_id, key.clone(), put_id) - .await - { - let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = e.into(); - return MsgPack { - serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&kv_err), - raw_bytes: Vec::new(), - }; - } - // Reserve cache capacity on this node for the leased allocation now (fetch_sub semantics) - if let Err(e) = view - .master_kv_router() - .adjust_node_cache_capacity_for_lease(node_id.as_ref(), target_cap_bytes as i64) - { - let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = e.into(); - return MsgPack { - serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&kv_err), - raw_bytes: Vec::new(), - }; - } - // And attach an on-drop hook to restore it (fetch_add on Allocation drop) - let view_clone = view.clone(); - let node_id_string = node_id.as_ref().to_string(); - target_allocation.set_on_drop(move || { - match view_clone.try_adjust_node_cache_capacity_for_lease( - &node_id_string, - -(target_cap_bytes as i64), - ) { - Some(Ok(())) => {} - Some(Err(e)) => { - tracing::warn!( - "Failed to restore moka capacity on drop: node_id={}, bytes={}, err={}", - node_id_string, - target_cap_bytes, - e - ); - } - None => { - tracing::debug!( - "Skipped restoring moka capacity on drop because MasterKvRouterView is gone: node_id={}, bytes={}", - node_id_string, - target_cap_bytes - ); - } - } - }); - } - - let completed_info = KvRouteInfo { - node_id: node_id.clone(), - allocation: Arc::new(target_allocation), - tomb_tag, - }; - // Insert into kv_routes with replica support let mut old_one_kv_routes: Option> = None; let mut inserted = false; @@ -668,6 +1453,21 @@ pub async fn handle_put_done( .insert(node_id.clone(), completed_info); } + if let Some(remote_append) = remote_append { + view.master_kv_router() + .inner() + .inflight_put_appends + .insert( + ( + remote_append.key.clone(), + remote_append.put_id.0, + remote_append.put_id.1, + ), + remote_append, + ) + .await; + } + if let Some(old) = old_one_kv_routes { if let Err(err) = view .master_kv_router() @@ -698,10 +1498,8 @@ pub async fn handle_put_done( lease_id_opt.is_none() && view.master_kv_router().replica_cache_enabled(); // Reuse the saturated weight computed above for moka insertion let cap_bytes_u32 = saturated_weight_u32; - let _ = view.spawn("post_put_done_maintenance", async move { - // 1) Update the derived prefix-counting index asynchronously. - // This keeps PutDone lean, but also means CountPrefix visibility - // is not an immediate strong-consistency signal for this put. + view.spawn("post_put_done_maintenance", async move { + // 1) Update prefix-counting index if do_prefix_index_update { let inner = view_task.master_kv_router().inner(); let mut tree = inner.prefix_index.write().await; @@ -761,6 +1559,295 @@ pub async fn handle_put_done( error_code: msg_and_error::OK, error_json: String::new(), server_process_us: 0, + local_cache_holder_id, + }, + raw_bytes: Vec::new(), + } +} + +pub async fn handle_batch_put_start( + view: MasterKvRouterView, + req: MsgPack, + req_node_id: NodeID, +) -> MsgPack { + let mut items = Vec::with_capacity(req.serialize_part.items.len()); + for item in req.serialize_part.items { + let (_put_id, resp) = handle_put_start( + view.clone(), + MsgPack { + serialize_part: PutStartReq { + key: item.key, + len: item.len, + reject_if_inflight_same_key: item.reject_if_inflight_same_key, + reject_if_exist_same_key: item.reject_if_exist_same_key, + write_through: item.write_through, + preferred_sub_cluster: item.preferred_sub_cluster, + source_node_id: None, + }, + raw_bytes: Vec::new(), + }, + req_node_id.clone(), + ) + .await; + let part = resp.serialize_part; + items.push(BatchPutStartItemResp { + put_id: part.put_id, + node_id: part.node_id, + target_addr: part.target_addr, + src_addr: part.src_addr, + target_base_addr: part.target_base_addr, + src_base_addr: part.src_base_addr, + len: part.len, + error_code: part.error_code, + error_json: part.error_json, + }); + } + MsgPack { + serialize_part: BatchPutStartResp { + items, + error_code: msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + }, + raw_bytes: Vec::new(), + } +} + +pub async fn handle_batch_put_revoke( + view: MasterKvRouterView, + req: MsgPack, +) -> MsgPack { + let mut items = Vec::with_capacity(req.serialize_part.items.len()); + for item in req.serialize_part.items { + let key = item.key.clone(); + let put_id = item.put_id; + let resp = handle_put_revoke( + view.clone(), + MsgPack { + serialize_part: PutRevokeReq { key, put_id }, + raw_bytes: Vec::new(), + }, + ) + .await; + let part = resp.serialize_part; + items.push(BatchPutRevokeItemResp { + key: item.key, + put_id: item.put_id, + error_code: part.error_code, + error_json: part.error_json, + }); + } + MsgPack { + serialize_part: BatchPutRevokeResp { + items, + error_code: msg_and_error::OK, + error_json: String::new(), + }, + raw_bytes: Vec::new(), + } +} + +pub async fn handle_batch_put_done( + view: MasterKvRouterView, + req: MsgPack, +) -> MsgPack { + let mut items = Vec::with_capacity(req.serialize_part.items.len()); + for item in req.serialize_part.items { + let key = item.key.clone(); + let put_id = item.put_id; + let lease_id = item.lease_id; + let resp = handle_put_done( + view.clone(), + MsgPack { + serialize_part: PutDoneReq { + key, + put_id, + lease_id, + committed_slot: item.committed_slot, + publish_local_cache: item.publish_local_cache, + }, + raw_bytes: Vec::new(), + }, + ) + .await; + let part = resp.serialize_part; + items.push(BatchPutDoneItemResp { + key: item.key, + put_id: item.put_id, + error_code: part.error_code, + error_json: part.error_json, + local_cache_holder_id: part.local_cache_holder_id, + }); + } + MsgPack { + serialize_part: BatchPutDoneResp { + items, + error_code: msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + }, + raw_bytes: Vec::new(), + } +} + +pub async fn handle_put_append_start( + view: MasterKvRouterView, + req: MsgPack, + req_node_id: NodeID, +) -> MsgPack { + let key = req.serialize_part.key.clone(); + let put_id = req.serialize_part.put_id; + let current_route_still_needs_remote = view + .master_kv_router() + .inner() + .kv_routes + .get(&key) + .map(|route| current_route_needs_remote_replica(&route, &req_node_id, put_id)) + .unwrap_or(false); + if !current_route_still_needs_remote { + let _ = view + .master_kv_router() + .inner() + .inflight_put_appends + .remove(&(key.clone(), put_id.0, put_id.1)) + .await; + return MsgPack { + serialize_part: PutAppendStartResp { + scheduled: false, + error_code: msg_and_error::OK, + error_json: String::new(), + ..Default::default() + }, + raw_bytes: Vec::new(), + }; + } + + let Some(inflight) = view + .master_kv_router() + .inner() + .inflight_put_appends + .get(&(key.clone(), put_id.0, put_id.1)) + .await + else { + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "Write-back append reservation missing: key={} put_id=({},{}) requester_node_id={}", + key, put_id.0, put_id.1, req_node_id + ), + }); + let resp: PutAppendStartResp = crate::rpcresp_kvresult_convert::FromError::from_error(&err); + return MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + }; + }; + let (target_base_addr, target_addr, allocation_size) = { + let target_allocation_guard = inflight.target_allocation.lock(); + let Some(target_allocation): Option<&Allocation> = target_allocation_guard.as_ref() else { + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "Write-back append reservation allocation missing: key={} put_id=({},{}) requester_node_id={}", + key, put_id.0, put_id.1, req_node_id + ), + }); + let resp: PutAppendStartResp = + crate::rpcresp_kvresult_convert::FromError::from_error(&err); + return MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + }; + }; + let target_base_addr = target_allocation.base_addr(); + let target_addr = target_base_addr + target_allocation.addr(); + let allocation_size = target_allocation.size(); + (target_base_addr, target_addr, allocation_size) + }; + + MsgPack { + serialize_part: PutAppendStartResp { + scheduled: true, + node_id: inflight.node_id.clone().into(), + target_addr, + target_base_addr, + len: allocation_size, + error_code: msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + }, + raw_bytes: Vec::new(), + } +} + +pub async fn handle_put_append_revoke( + view: MasterKvRouterView, + req: MsgPack, +) -> MsgPack { + let put_id = req.serialize_part.put_id; + let key = req.serialize_part.key; + let _ = view + .master_kv_router() + .inner() + .inflight_put_appends + .remove(&(key, put_id.0, put_id.1)) + .await; + MsgPack { + serialize_part: PutAppendRevokeResp { + error_code: msg_and_error::OK, + error_json: String::new(), + }, + raw_bytes: Vec::new(), + } +} + +pub async fn handle_put_append_done( + view: MasterKvRouterView, + req: MsgPack, +) -> MsgPack { + let put_id = req.serialize_part.put_id; + let key = req.serialize_part.key.clone(); + let Some(inflight) = view + .master_kv_router() + .inner() + .inflight_put_appends + .remove(&(key.clone(), put_id.0, put_id.1)) + .await + else { + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "Put append operation not found for completion: key={} put_id=({},{})", + key, put_id.0, put_id.1 + ), + }); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), + raw_bytes: Vec::new(), + }; + }; + let Some(allocation) = inflight.target_allocation.lock().take() else { + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "Put append target allocation already taken: key={} put_id=({},{})", + key, put_id.0, put_id.1 + ), + }); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), + raw_bytes: Vec::new(), + }; + }; + let appended = append_current_route_replica_if_matching( + &view, + &key, + inflight.put_id, + inflight.node_id, + allocation, + ); + MsgPack { + serialize_part: PutAppendDoneResp { + appended, + error_code: msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, }, raw_bytes: Vec::new(), } diff --git a/fluxon_rs/fluxon_kv/src/master_lease_manager/lease_manager_test.rs b/fluxon_rs/fluxon_kv/src/master_lease_manager/lease_manager_test.rs index 5c20cc1..6b84528 100755 --- a/fluxon_rs/fluxon_kv/src/master_lease_manager/lease_manager_test.rs +++ b/fluxon_rs/fluxon_kv/src/master_lease_manager/lease_manager_test.rs @@ -22,7 +22,8 @@ async fn test1_lease_expire_removes_keys() { unsafe { std::env::set_var("FLUXON_LOG", "debug"); } - let (master_fw, client_fw) = start_master_and_client("lease_master_t1", "lease_client_t1").await; + let (master_fw, client_fw) = + start_master_and_client("lease_master_t1", "lease_client_t1").await; let client_view = client_fw.client_kv_api_view(); wait_master_ready(&client_view).await; @@ -48,14 +49,12 @@ async fn test1_lease_expire_removes_keys() { tracing::info!("[test1-verify-present-during-ttl] verifying keys exist within TTL window"); for _ in 0..3 { for k in &keys { - assert!( - client_view - .client_kv_api() - .inner() - .is_exist(k) - .await - .unwrap() - ); + assert!(client_view + .client_kv_api() + .inner() + .is_exist(k) + .await + .unwrap()); } sleep(Duration::from_millis(500)).await; } @@ -82,7 +81,8 @@ async fn test2_rebind_to_new_lease_preserves_until_new_expire() { unsafe { std::env::set_var("FLUXON_LOG", "debug"); } - let (master_fw, client_fw) = start_master_and_client("lease_master_t2", "lease_client_t2").await; + let (master_fw, client_fw) = + start_master_and_client("lease_master_t2", "lease_client_t2").await; let client_view = client_fw.client_kv_api_view(); wait_master_ready(&client_view).await; @@ -120,14 +120,12 @@ async fn test2_rebind_to_new_lease_preserves_until_new_expire() { // After l1 expiry, keys should still exist due to l2 sleep(Duration::from_secs(3)).await; for k in &keys { - assert!( - client_view - .client_kv_api() - .inner() - .is_exist(k) - .await - .unwrap() - ); + assert!(client_view + .client_kv_api() + .inner() + .is_exist(k) + .await + .unwrap()); } tracing::info!( "[test2-verify-still-present-after-first-expire] keys still exist after first lease expired, held by second lease" @@ -161,7 +159,8 @@ async fn test3_keepalive() { unsafe { std::env::set_var("FLUXON_LOG", "debug"); } - let (master_fw, client_fw) = start_master_and_client("lease_master_t3", "lease_client_t3").await; + let (master_fw, client_fw) = + start_master_and_client("lease_master_t3", "lease_client_t3").await; let client_view = client_fw.client_kv_api_view(); wait_master_ready(&client_view).await; @@ -193,14 +192,12 @@ async fn test3_keepalive() { .await .unwrap(); for k in &keys { - assert!( - client_view - .client_kv_api() - .inner() - .is_exist(k) - .await - .unwrap() - ); + assert!(client_view + .client_kv_api() + .inner() + .is_exist(k) + .await + .unwrap()); } if i % 2 == 0 { tracing::info!( @@ -214,14 +211,12 @@ async fn test3_keepalive() { // Stop keepalive, wait beyond TTL sleep(Duration::from_secs(3)).await; for k in &keys { - assert!( - !client_view - .client_kv_api() - .inner() - .is_exist(k) - .await - .unwrap() - ); + assert!(!client_view + .client_kv_api() + .inner() + .is_exist(k) + .await + .unwrap()); } tracing::info!( "[test3-stop-keepalive-wait-verify-missing] verified keys removed after stopping keepalive and waiting past TTL" @@ -236,7 +231,8 @@ async fn test4_delete_under_lease_then_get_fails() { unsafe { std::env::set_var("FLUXON_LOG", "debug"); } - let (master_fw, client_fw) = start_master_and_client("lease_master_t4", "lease_client_t4").await; + let (master_fw, client_fw) = + start_master_and_client("lease_master_t4", "lease_client_t4").await; let client_view = client_fw.client_kv_api_view(); wait_master_ready(&client_view).await; @@ -263,14 +259,12 @@ async fn test4_delete_under_lease_then_get_fails() { } sleep(Duration::from_secs(2)).await; for k in &keys { - assert!( - !client_view - .client_kv_api() - .inner() - .is_exist(k) - .await - .unwrap() - ); + assert!(!client_view + .client_kv_api() + .inner() + .is_exist(k) + .await + .unwrap()); } tracing::info!( "[test4-delete-keys-sleep-2s-verify-missing] deleted keys and verified not exist after delay" diff --git a/fluxon_rs/fluxon_kv/src/memholder/lifetime.rs b/fluxon_rs/fluxon_kv/src/memholder/lifetime.rs index ad23b4d..1ea35eb 100755 --- a/fluxon_rs/fluxon_kv/src/memholder/lifetime.rs +++ b/fluxon_rs/fluxon_kv/src/memholder/lifetime.rs @@ -1,5 +1,7 @@ use super::DeleteTargetMember; -use crate::client_kv_api::msg_pack::ExternalInvalidateWeakIndexReq; +use crate::client_kv_api::msg_pack::{ + ExternalInvalidateWeakIndexItem, ExternalInvalidateWeakIndexReq, +}; use crate::client_kv_api::{ClientKvApiView, ClientKvApiViewTrait, ExternalHoldingGetInfo}; use crate::cluster_manager::app_logic_ext::ClusterManagerAppLogicExt; use crate::external_client_api::{ExternalClientApiView, ExternalClientApiViewTrait}; @@ -786,18 +788,24 @@ impl MemholderManagerTrait for OwnerExternalMemMgr { target: Self::DeleteTarget, tasks: Vec, ) -> Result<(), String> { - let mut keys: Vec = tasks.into_iter().map(|task| task.key).collect(); - keys.sort(); - keys.dedup(); - - if keys.is_empty() { + let mut items: Vec = tasks + .into_iter() + .map(|task| ExternalInvalidateWeakIndexItem { key: task.key }) + .collect(); + items.sort_by(|a, b| a.key.cmp(&b.key)); + items.dedup_by(|a, b| a.key == b.key); + + if items.is_empty() { return Ok(()); } let rpc_caller = RPCCaller::::new(); rpc_caller.regist(ctx.p2p_module()); let req = MsgPack { - serialize_part: ExternalInvalidateWeakIndexReq { keys }, + serialize_part: ExternalInvalidateWeakIndexReq { + keys: Vec::new(), + items, + }, raw_bytes: Vec::new(), }; diff --git a/fluxon_rs/fluxon_kv/src/memholder/mod.rs b/fluxon_rs/fluxon_kv/src/memholder/mod.rs index db0ada2..37f2d81 100755 --- a/fluxon_rs/fluxon_kv/src/memholder/mod.rs +++ b/fluxon_rs/fluxon_kv/src/memholder/mod.rs @@ -24,6 +24,16 @@ use crate::{cluster_manager::NodeID, external_client_api::ExternalClientApiView} use bitcode::{Decode, Encode}; +#[derive(Clone, Debug)] +pub enum MemoryInfoDropAction { + OwnerDeleteAck, + ReleaseLocalReserveResidentSlot { + slot_size: u64, + grant_id: u64, + slot_index: u32, + }, +} + /// Memory metadata for owner/client user holders #[derive(Clone)] pub struct MemoryInfo { @@ -35,6 +45,7 @@ pub struct MemoryInfo { pub key: String, pub master_node_id: NodeID, pub view: ClientKvApiView, + pub drop_action: MemoryInfoDropAction, } impl std::fmt::Debug for MemoryInfo { @@ -46,6 +57,7 @@ impl std::fmt::Debug for MemoryInfo { .field("holder_id", &self.holder_id) .field("key", &self.key) .field("master_node_id", &self.master_node_id) + .field("drop_action", &self.drop_action) .finish() } } @@ -159,8 +171,50 @@ impl MemoryInfo { key, master_node_id, view, + drop_action: MemoryInfoDropAction::OwnerDeleteAck, + } + } + + pub async fn new_local_reserve_resident( + addr: u64, + len: u32, + key: String, + master_node_id: NodeID, + view: ClientKvApiView, + slot_size: u64, + grant_id: u64, + slot_index: u32, + ) -> Self { + let base_addr = { + let base_guard = view + .client_seg_pool() + .cpu_mem_read_guard() + .await + .expect("segment cpu mem must be available when creating resident MemoryInfo"); + base_guard.allocated_addr + }; + assert!( + addr >= base_addr, + "resident local reserve addr must be within client segment: addr={:#x} base_addr={:#x}", + addr, + base_addr + ); + Self { + offset: addr - base_addr, + addr, + len, + holder_id: 0, + key, + master_node_id, + view, + drop_action: MemoryInfoDropAction::ReleaseLocalReserveResidentSlot { + slot_size, + grant_id, + slot_index, + }, } } + pub fn bytes(&self) -> &[u8] { tracing::debug!( "MemHolder accessing memory: addr={:#x}, len={}", @@ -169,16 +223,62 @@ impl MemoryInfo { ); unsafe { std::slice::from_raw_parts(self.addr as *const u8, self.len as usize) } } + + pub fn local_reserve_resident_slot_ref(&self) -> Option<(u64, u64, u32)> { + match self.drop_action { + MemoryInfoDropAction::ReleaseLocalReserveResidentSlot { + slot_size, + grant_id, + slot_index, + } => Some((slot_size, grant_id, slot_index)), + MemoryInfoDropAction::OwnerDeleteAck => None, + } + } } + /// Represents a memory holder that keeps a reference to transferred data impl Drop for MemoryInfo { fn drop(&mut self) { - let ctx = OwnerDeleteAckCtx { - view: self.view.clone(), - key: self.key.clone(), - holder_id: self.holder_id, - }; - ctx.run_drop_ack(); + match &self.drop_action { + MemoryInfoDropAction::OwnerDeleteAck => { + let ctx = OwnerDeleteAckCtx { + view: self.view.clone(), + key: self.key.clone(), + holder_id: self.holder_id, + }; + ctx.run_drop_ack(); + } + MemoryInfoDropAction::ReleaseLocalReserveResidentSlot { + slot_size, + grant_id, + slot_index, + } => { + let spawn_view = self.view.clone(); + let release_view = self.view.clone(); + let key = self.key.clone(); + let slot_size = *slot_size; + let grant_id = *grant_id; + let slot_index = *slot_index; + let _ = spawn_view.spawn("resident_local_reserve_slot_release", async move { + if let Err(err) = release_view + .client_kv_api() + .inner() + .owner_release_local_reserve_resident_slot_holder( + slot_size, grant_id, slot_index, + ) + { + tracing::warn!( + "failed to release resident local reserve slot holder on MemoryInfo drop: key={} slot_size={} grant_id={} slot_index={} err={}", + key, + slot_size, + grant_id, + slot_index, + err + ); + } + }); + } + } } } diff --git a/fluxon_rs/fluxon_kv/src/metrics.rs b/fluxon_rs/fluxon_kv/src/metrics.rs index 88f1b9c..4f5d88e 100644 --- a/fluxon_rs/fluxon_kv/src/metrics.rs +++ b/fluxon_rs/fluxon_kv/src/metrics.rs @@ -26,6 +26,8 @@ pub struct MetricsHandle { // Pending put stats captured at put_start to attribute external-owner path at put_end. pending_put_stats: DashMap, + + locality_counters: KvLocalityCounters, } #[derive(Clone, Debug)] @@ -43,6 +45,7 @@ pub struct PendingPutStat { pub transfer_poll_wait_us: i64, pub transfer_poll_iters: i64, pub transfer_used_fast_path: bool, + pub transfer_used_nixl: bool, pub transfer_local_noop: bool, pub transfer_remote_transfer: bool, pub top_emitted: bool, @@ -54,6 +57,85 @@ pub enum OperationKind { Get, } +#[derive(Clone, Debug, Default)] +pub struct KvIoLocalitySnapshot { + pub op_count: u64, + pub bytes: u64, + pub transfer_us: u64, +} + +impl KvIoLocalitySnapshot { + pub fn bandwidth_gbps(&self) -> f64 { + if self.transfer_us == 0 { + return 0.0; + } + (self.bytes as f64) / (self.transfer_us as f64 / 1_000_000.0) / 1_000_000_000.0 + } +} + +#[derive(Clone, Debug, Default)] +pub struct KvLocalitySnapshot { + pub l2_local_hit_pages: u64, + pub l2_local_hit_bytes: u64, + pub l2_remote_hit_pages: u64, + pub l2_remote_hit_bytes: u64, + pub put_local: KvIoLocalitySnapshot, + pub put_remote: KvIoLocalitySnapshot, + pub get_local: KvIoLocalitySnapshot, + pub get_remote: KvIoLocalitySnapshot, +} + +#[derive(Default)] +struct KvLocalityCounters { + l2_local_hit_pages: AtomicU64, + l2_local_hit_bytes: AtomicU64, + l2_remote_hit_pages: AtomicU64, + l2_remote_hit_bytes: AtomicU64, + put_local_ops: AtomicU64, + put_local_bytes: AtomicU64, + put_local_transfer_us: AtomicU64, + put_remote_ops: AtomicU64, + put_remote_bytes: AtomicU64, + put_remote_transfer_us: AtomicU64, + get_local_ops: AtomicU64, + get_local_bytes: AtomicU64, + get_local_transfer_us: AtomicU64, + get_remote_ops: AtomicU64, + get_remote_bytes: AtomicU64, + get_remote_transfer_us: AtomicU64, +} + +impl KvLocalityCounters { + fn snapshot(&self) -> KvLocalitySnapshot { + KvLocalitySnapshot { + l2_local_hit_pages: self.l2_local_hit_pages.load(Ordering::Relaxed), + l2_local_hit_bytes: self.l2_local_hit_bytes.load(Ordering::Relaxed), + l2_remote_hit_pages: self.l2_remote_hit_pages.load(Ordering::Relaxed), + l2_remote_hit_bytes: self.l2_remote_hit_bytes.load(Ordering::Relaxed), + put_local: KvIoLocalitySnapshot { + op_count: self.put_local_ops.load(Ordering::Relaxed), + bytes: self.put_local_bytes.load(Ordering::Relaxed), + transfer_us: self.put_local_transfer_us.load(Ordering::Relaxed), + }, + put_remote: KvIoLocalitySnapshot { + op_count: self.put_remote_ops.load(Ordering::Relaxed), + bytes: self.put_remote_bytes.load(Ordering::Relaxed), + transfer_us: self.put_remote_transfer_us.load(Ordering::Relaxed), + }, + get_local: KvIoLocalitySnapshot { + op_count: self.get_local_ops.load(Ordering::Relaxed), + bytes: self.get_local_bytes.load(Ordering::Relaxed), + transfer_us: self.get_local_transfer_us.load(Ordering::Relaxed), + }, + get_remote: KvIoLocalitySnapshot { + op_count: self.get_remote_ops.load(Ordering::Relaxed), + bytes: self.get_remote_bytes.load(Ordering::Relaxed), + transfer_us: self.get_remote_transfer_us.load(Ordering::Relaxed), + }, + } + } +} + impl OperationKind { pub const fn as_label(self) -> &'static str { match self { @@ -147,6 +229,7 @@ impl MetricsHandle { get_metrics_queue: SegQueue::new(), latest_metrics_snapshot: RwLock::new(HashMap::new()), pending_put_stats: DashMap::new(), + locality_counters: KvLocalityCounters::default(), } } @@ -184,6 +267,78 @@ impl MetricsHandle { } } + pub fn get_locality_snapshot(&self) -> KvLocalitySnapshot { + self.locality_counters.snapshot() + } + + pub fn record_l2_hit_locality(&self, remote: bool, bytes: u64) { + if remote { + self.locality_counters + .l2_remote_hit_pages + .fetch_add(1, Ordering::Relaxed); + self.locality_counters + .l2_remote_hit_bytes + .fetch_add(bytes, Ordering::Relaxed); + } else { + self.locality_counters + .l2_local_hit_pages + .fetch_add(1, Ordering::Relaxed); + self.locality_counters + .l2_local_hit_bytes + .fetch_add(bytes, Ordering::Relaxed); + } + } + + pub fn record_put_io_locality(&self, remote: bool, bytes: u64, transfer_us: i64) { + let transfer_us = transfer_us.max(0) as u64; + if remote { + self.locality_counters + .put_remote_ops + .fetch_add(1, Ordering::Relaxed); + self.locality_counters + .put_remote_bytes + .fetch_add(bytes, Ordering::Relaxed); + self.locality_counters + .put_remote_transfer_us + .fetch_add(transfer_us, Ordering::Relaxed); + } else { + self.locality_counters + .put_local_ops + .fetch_add(1, Ordering::Relaxed); + self.locality_counters + .put_local_bytes + .fetch_add(bytes, Ordering::Relaxed); + self.locality_counters + .put_local_transfer_us + .fetch_add(transfer_us, Ordering::Relaxed); + } + } + + pub fn record_get_io_locality(&self, remote: bool, bytes: u64, transfer_us: i64) { + let transfer_us = transfer_us.max(0) as u64; + if remote { + self.locality_counters + .get_remote_ops + .fetch_add(1, Ordering::Relaxed); + self.locality_counters + .get_remote_bytes + .fetch_add(bytes, Ordering::Relaxed); + self.locality_counters + .get_remote_transfer_us + .fetch_add(transfer_us, Ordering::Relaxed); + } else { + self.locality_counters + .get_local_ops + .fetch_add(1, Ordering::Relaxed); + self.locality_counters + .get_local_bytes + .fetch_add(bytes, Ordering::Relaxed); + self.locality_counters + .get_local_transfer_us + .fetch_add(transfer_us, Ordering::Relaxed); + } + } + pub fn emit_op_end_bytes_pulse( &self, op: OperationKind, @@ -252,6 +407,39 @@ impl MetricsHandle { }); } + pub fn set_kv_holding_entries(&self, scope: &str, entries: u64) { + let _ = (scope, entries); + } + + pub fn set_kv_holding_bytes(&self, scope: &str, bytes: u64) { + let _ = (scope, bytes); + } + + pub fn set_kv_external_pending_put_entries(&self, entries: u64) { + let _ = entries; + } + + pub fn set_kv_replica_cache_entries(&self, owner_node: &str, entries: u64) { + let _ = (owner_node, entries); + } + + pub fn set_kv_replica_cache_weighted_bytes(&self, owner_node: &str, bytes: u64) { + let _ = (owner_node, bytes); + } + + pub fn set_kv_replica_cache_capacity_bytes( + &self, + owner_node: &str, + capacity_kind: &str, + bytes: u64, + ) { + let _ = (owner_node, capacity_kind, bytes); + } + + pub fn inc_kv_get_done_allocation(&self, allocation_mode: &str) { + let _ = allocation_mode; + } + pub fn set_fs_mount_fs_bytes( &self, mount_kind: FsMountKind, @@ -333,6 +521,7 @@ impl MetricsHandle { transfer_poll_wait_us, transfer_poll_iters, transfer_used_fast_path, + transfer_used_nixl, transfer_local_noop, transfer_remote_transfer, } = &metric @@ -356,7 +545,7 @@ impl MetricsHandle { if let Some(seq) = sampled_debug_seq(&PUT_METRIC_SUBMIT_SEQ) { tracing::debug!( - "submit kv op metric seq={} kind=put put_id={} key={} whole_us={} start_us={} transfer_us={} end_us={} rpc_us={} start_handle_us={} end_handle_us={} t1_us={} t2_us={} t3_us={} t4_us={} transfer_submit_blocking_us={} transfer_create_xfer_req_us={} transfer_post_xfer_req_us={} transfer_poll_wait_us={} transfer_poll_iters={} transfer_used_fast_path={} transfer_local_noop={} transfer_remote_transfer={}", + "submit kv op metric seq={} kind=put put_id={} key={} whole_us={} start_us={} transfer_us={} end_us={} rpc_us={} start_handle_us={} end_handle_us={} t1_us={} t2_us={} t3_us={} t4_us={} transfer_submit_blocking_us={} transfer_create_xfer_req_us={} transfer_post_xfer_req_us={} transfer_poll_wait_us={} transfer_poll_iters={} transfer_used_fast_path={} transfer_used_nixl={} transfer_local_noop={} transfer_remote_transfer={}", seq, put_id, sanitize_key(key), @@ -377,6 +566,7 @@ impl MetricsHandle { transfer_poll_wait_us, transfer_poll_iters, transfer_used_fast_path, + transfer_used_nixl, transfer_local_noop, transfer_remote_transfer ); @@ -537,6 +727,7 @@ impl MetricsHandle { transfer_poll_wait_us: 0, transfer_poll_iters: 0, transfer_used_fast_path: false, + transfer_used_nixl: false, transfer_local_noop: false, transfer_remote_transfer: false, top_emitted: false, @@ -580,6 +771,7 @@ impl MetricsHandle { transfer_poll_wait_us: i64, transfer_poll_iters: i64, transfer_used_fast_path: bool, + transfer_used_nixl: bool, transfer_local_noop: bool, transfer_remote_transfer: bool, ) { @@ -593,6 +785,7 @@ impl MetricsHandle { guard.transfer_poll_wait_us = transfer_poll_wait_us; guard.transfer_poll_iters = transfer_poll_iters; guard.transfer_used_fast_path = transfer_used_fast_path; + guard.transfer_used_nixl = transfer_used_nixl; guard.transfer_local_noop = transfer_local_noop; guard.transfer_remote_transfer = transfer_remote_transfer; } diff --git a/fluxon_rs/fluxon_kv/src/observe_kvope.rs b/fluxon_rs/fluxon_kv/src/observe_kvope.rs index 69c724d..d67ec67 100755 --- a/fluxon_rs/fluxon_kv/src/observe_kvope.rs +++ b/fluxon_rs/fluxon_kv/src/observe_kvope.rs @@ -245,6 +245,7 @@ pub fn obe_put_done_success( transfer_poll_wait_us, transfer_poll_iters, transfer_used_fast_path, + transfer_used_nixl: false, transfer_local_noop, transfer_remote_transfer, }); diff --git a/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/msg_and_error.rs b/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/msg_and_error.rs index 42a9cbc..75fe736 100644 --- a/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/msg_and_error.rs +++ b/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/msg_and_error.rs @@ -43,6 +43,34 @@ pub enum MsgId { CountPrefixResp = 3026, GetMasterOnlyMetricPartReq = 3027, GetMasterOnlyMetricPartResp = 3028, + BatchIsExistReq = 3031, + BatchIsExistResp = 3032, + PutAppendStartReq = 3033, + PutAppendStartResp = 3034, + PutAppendRevokeReq = 3035, + PutAppendRevokeResp = 3036, + PutAppendDoneReq = 3037, + PutAppendDoneResp = 3038, + BatchPutStartReq = 3039, + BatchPutStartResp = 3040, + BatchPutRevokeReq = 3041, + BatchPutRevokeResp = 3042, + BatchPutDoneReq = 3043, + BatchPutDoneResp = 3044, + BatchGetStartReq = 3045, + BatchGetStartResp = 3046, + BatchGetRevokeReq = 3047, + BatchGetRevokeResp = 3048, + BatchGetDoneReq = 3049, + BatchGetDoneResp = 3050, + ReserveLocalGrantReq = 3051, + ReserveLocalGrantResp = 3052, + ReleaseLocalGrantReq = 3053, + ReleaseLocalGrantResp = 3054, + BatchPreparePutKeysReq = 3055, + BatchPreparePutKeysResp = 3056, + BatchReleasePutKeyReservationsReq = 3057, + BatchReleasePutKeyReservationsResp = 3058, ExternalGetReq = 4001, ExternalGetResp = 4002, ExternalPutStartReq = 4003, @@ -51,6 +79,8 @@ pub enum MsgId { ExternalPutTransferEndResp = 4006, ExternalDeleteReq = 4009, ExternalDeleteResp = 4010, + ExternalBatchIsExistReq = 4015, + ExternalBatchIsExistResp = 4016, AllocateClientLeaseReq = 5001, AllocateClientLeaseResp = 5002, ClientLeaseKeepaliveReq = 5003, @@ -704,6 +734,9 @@ crate::define_err_group! { , (122, KeyBeingWritten { key: String }, msg: "Key is currently being written: key={key}") + , + (123, KeyAlreadyExists { key: String }, + msg: "Key already exists: key={key}") } } diff --git a/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/rpcresp_kvresult_convert.rs b/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/rpcresp_kvresult_convert.rs index b6eb7d6..30ee572 100755 --- a/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/rpcresp_kvresult_convert.rs +++ b/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/rpcresp_kvresult_convert.rs @@ -1,13 +1,23 @@ use super::msg_and_error::OK; -use super::msg_and_error::{ErrorCode, KvError, KvResult}; +use super::msg_and_error::{ + ApiError, ConfigError, ErrorCode, KvError, KvResult, SharedMemError, UnreachableError, +}; use crate::client_kv_api::msg_pack::{ - ExternalDeleteAckResp, ExternalDeleteResp, ExternalGetResp, ExternalIsExistResp, - ExternalPutCommitResp, ExternalPutRevokeResp, ExternalPutStartResp, ExternalPutTransferEndResp, + ExternalBatchGetCancelResp, ExternalBatchGetItemResp, ExternalBatchGetResp, + ExternalBatchGetStartResp, ExternalBatchGetTransferResp, ExternalBatchIsExistResp, + ExternalBatchPutCommitItemResp, ExternalBatchPutCommitResp, ExternalBatchPutStartItemResp, + ExternalBatchPutStartResp, ExternalBatchPutTransferEndItemResp, + ExternalBatchPutTransferEndResp, ExternalDeleteAckResp, ExternalDeleteResp, ExternalGetResp, + ExternalIsExistResp, ExternalObservabilitySnapshotResp, ExternalPutCommitResp, + ExternalPutRevokeResp, ExternalPutStartResp, ExternalPutTransferEndResp, }; use crate::master_kv_router::msg_pack::{ - BatchDeleteAckResp, BatchDeleteClientKvMetaCacheResp, DeleteAckResp, DeleteResp, GetDoneResp, - GetMasterOnlyMetricPartResp, GetMetaResp, GetRevokeResp, GetStartResp, MemHolderKeepAliveResp, - MemHolderReleaseResp, PutDoneResp, PutRevokeResp, PutStartResp, + BatchDeleteAckResp, BatchDeleteClientKvMetaCacheResp, BatchIsExistResp, + BatchPreparePutKeysResp, BatchReleasePutKeyReservationsResp, DeleteAckResp, DeleteResp, + GetDoneResp, GetMasterOnlyMetricPartResp, GetMetaResp, GetRevokeResp, GetStartResp, + MemHolderKeepAliveResp, MemHolderReleaseResp, PutAppendDoneResp, PutAppendRevokeResp, + PutAppendStartResp, PutDoneResp, PutRevokeResp, PutStartResp, ReleaseLocalGrantResp, + ReserveLocalGrantResp, }; use crate::master_seg_manager::msg_pack::RequestSegmentRegistrationResp; use crate::memholder::ExternalMemHolderInfo; @@ -58,6 +68,16 @@ impl ToResult for ExternalIsExistResp { } } +impl ToResult for ExternalBatchIsExistResp { + type Ok = Vec; + fn to_result(self) -> KvResult { + if self.error_code == OK { + return Ok(self.exists_list); + } + Err(KvError::from_json(self.error_code, &self.error_json)) + } +} + /// Convert ExternalDeleteResp into KvResult<()> impl ToResult for ExternalDeleteResp { type Ok = (); @@ -131,6 +151,16 @@ impl ToResult for ExternalDeleteAckResp { } } +impl ToResult for BatchIsExistResp { + type Ok = Vec; + fn to_result(self) -> KvResult { + if self.error_code == OK { + return Ok(self.exists_list); + } + Err(KvError::from_json(self.error_code, &self.error_json)) + } +} + /// Centralized: convert code+desc to KvError or Ok if code==Ok pub fn try_from_code(code: ErrorCode, json: String) -> KvResult<()> { if code == OK { @@ -222,6 +252,135 @@ impl FromError for ExternalIsExistResp { } } } +impl FromError for ExternalBatchIsExistResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + ..Default::default() + } + } +} +impl FromError for ExternalBatchGetResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + ..Default::default() + } + } +} +impl FromError for ExternalBatchGetItemResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + ..Default::default() + } + } +} +impl FromError for ExternalBatchGetStartResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + ..Default::default() + } + } +} +impl FromError for ExternalBatchGetTransferResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + ..Default::default() + } + } +} +impl FromError for ExternalBatchGetCancelResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + } + } +} +impl FromError for ExternalBatchPutStartResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + ..Default::default() + } + } +} +impl FromError for ExternalBatchPutStartItemResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + ..Default::default() + } + } +} +impl FromError for ExternalBatchPutTransferEndResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + ..Default::default() + } + } +} +impl FromError for ExternalBatchPutTransferEndItemResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + ..Default::default() + } + } +} +impl FromError for ExternalBatchPutCommitResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + ..Default::default() + } + } +} +impl FromError for ExternalBatchPutCommitItemResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + ..Default::default() + } + } +} +impl FromError for ExternalObservabilitySnapshotResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + ..Default::default() + } + } +} impl FromError for ExternalDeleteAckResp { fn from_error(e: &KvError) -> Self { let code = e.code(); @@ -294,6 +453,76 @@ impl FromError for PutDoneResp { } } } +impl FromError for ReserveLocalGrantResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + ..Default::default() + } + } +} +impl FromError for ReleaseLocalGrantResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + ..Default::default() + } + } +} +impl FromError for BatchPreparePutKeysResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + ..Default::default() + } + } +} +impl FromError for BatchReleasePutKeyReservationsResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + ..Default::default() + } + } +} +impl FromError for PutAppendStartResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + ..Default::default() + } + } +} +impl FromError for PutAppendRevokeResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + ..Default::default() + } + } +} +impl FromError for PutAppendDoneResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + ..Default::default() + } + } +} impl FromError for MemHolderKeepAliveResp { fn from_error(e: &KvError) -> Self { let code = e.code(); @@ -354,6 +583,16 @@ impl FromError for GetMetaResp { } } } +impl FromError for BatchIsExistResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + ..Default::default() + } + } +} impl FromError for BatchDeleteClientKvMetaCacheResp { fn from_error(e: &KvError) -> Self { let code = e.code(); diff --git a/fluxon_rs/fluxon_ops/build.rs b/fluxon_rs/fluxon_ops/build.rs index 585fbfc..51e95c4 100644 --- a/fluxon_rs/fluxon_ops/build.rs +++ b/fluxon_rs/fluxon_ops/build.rs @@ -59,9 +59,17 @@ print( } fn render_log_shard_helper(repo_root: &Path) -> String { - let helper_path = repo_root.join("deployment").join("utils").join("log_shard.py"); - fs::read_to_string(&helper_path) - .unwrap_or_else(|e| panic!("read log shard helper failed: {} ({})", helper_path.display(), e)) + let helper_path = repo_root + .join("deployment") + .join("utils") + .join("log_shard.py"); + fs::read_to_string(&helper_path).unwrap_or_else(|e| { + panic!( + "read log shard helper failed: {} ({})", + helper_path.display(), + e + ) + }) } fn main() { @@ -87,6 +95,10 @@ fn main() { ); println!( "cargo:rerun-if-changed={}", - repo_root.join("deployment").join("utils").join("log_shard.py").display() + repo_root + .join("deployment") + .join("utils") + .join("log_shard.py") + .display() ); } diff --git a/fluxon_rs/fluxon_ops/src/lib.rs b/fluxon_rs/fluxon_ops/src/lib.rs index 29d9434..3adb053 100644 --- a/fluxon_rs/fluxon_ops/src/lib.rs +++ b/fluxon_rs/fluxon_ops/src/lib.rs @@ -80,7 +80,8 @@ const DELETE_APPLY_NO_WAIT_DELAY_SECONDS: u64 = 30; const EMBEDDED_SELECTION_SUPERVISOR_SOURCE: &str = include_str!(concat!(env!("OUT_DIR"), "/selection_supervisor.py")); -const EMBEDDED_LOG_SHARD_HELPER_SOURCE: &str = include_str!(concat!(env!("OUT_DIR"), "/log_shard.py")); +const EMBEDDED_LOG_SHARD_HELPER_SOURCE: &str = + include_str!(concat!(env!("OUT_DIR"), "/log_shard.py")); // Ops controller uses Fluxon user-RPC to talk to ops agents. // Keep the timeout as a fixed constant to avoid config surface area. @@ -351,7 +352,10 @@ fn workload_log_latest_shard_identity(logical_path: &Path) -> anyhow::Result anyhow::Result Ok(resolved) } -fn ensure_embedded_selection_supervisor_runtime(workdir: &Path) -> anyhow::Result<(PathBuf, PathBuf)> { +fn ensure_embedded_selection_supervisor_runtime( + workdir: &Path, +) -> anyhow::Result<(PathBuf, PathBuf)> { let runtime_dir = workdir.join(OPS_SELECTION_SUPERVISOR_DIR_NAME); std::fs::create_dir_all(&runtime_dir).with_context(|| { format!( @@ -1657,10 +1663,11 @@ fn selection_owner_supervisor( scope_key: Option<&str>, exclude_pid: Option, ) -> anyhow::Result> { - let owners: Vec = live_selection_supervisors(snapshot, Some(label), scope_key)? - .into_iter() - .filter(|supervisor| exclude_pid != Some(supervisor.pid())) - .collect(); + let owners: Vec = + live_selection_supervisors(snapshot, Some(label), scope_key)? + .into_iter() + .filter(|supervisor| exclude_pid != Some(supervisor.pid())) + .collect(); if owners.is_empty() { return Ok(None); } @@ -2068,7 +2075,16 @@ fn wait_for_selection_attached( argv: &[String], cwd: Option<&str>, ) -> anyhow::Result { - wait_for_selection_attached_for_scope(kind, name, authority, None, apply_id, owner_ts_ms, argv, cwd) + wait_for_selection_attached_for_scope( + kind, + name, + authority, + None, + apply_id, + owner_ts_ms, + argv, + cwd, + ) } fn wait_for_selection_attached_without_present_for_scope( @@ -2803,10 +2819,9 @@ impl SupervisorBackedWorkloads { fn list_workloads(&self) -> anyhow::Result> { let mut out: Vec = Vec::new(); let snapshot = selection_supervisor_proc_snapshot()?; - for status in observe_all_selection_statuses_for_snapshot( - &snapshot, - Some(self.scope_key.as_str()), - )? { + for status in + observe_all_selection_statuses_for_snapshot(&snapshot, Some(self.scope_key.as_str()))? + { let kind = status.kind.with_context(|| { format!( "selection supervisor list item missing kind: label={}", @@ -3159,7 +3174,10 @@ impl UserRpcHandler for ReadWorkloadLogChunkHandler { None => { let Some(path) = resolve_readable_log_path(&logical_path) else { let resp = make_err_resp( - format!("log file is not available yet: logical_path={}", logical_path.display()), + format!( + "log file is not available yet: logical_path={}", + logical_path.display() + ), None, ); return Ok(serde_json::to_vec(&resp).unwrap()); @@ -3186,138 +3204,11 @@ impl UserRpcHandler for ReadWorkloadLogChunkHandler { }; let file_size = meta.len(); - let (start, end, start_cursor, end_cursor, effective_path, effective_file_size) = - match req.direction { - LogReadDirection::Forward => { - if let Some(cursor) = req.cursor.as_ref() { - if cursor.offset > file_size { - let resp = make_err_resp( - format!( - "cursor out of range: shard={} cursor={} file_size={}", - cursor.shard, cursor.offset, file_size - ), - Some(file_size), - ); - return Ok(serde_json::to_vec(&resp).unwrap()); - } - let mut effective_path = path.clone(); - let mut effective_shard = shard.clone(); - let mut effective_file_size = file_size; - let mut start = cursor.offset; - if cursor.offset == file_size { - if let Ok(Some(next_shard)) = - workload_log_next_shard(&logical_path, &cursor.shard) - { - let next_path = match workload_log_path_for_shard(&logical_path, &next_shard) { - Ok(v) => v, - Err(e) => { - let resp = make_err_resp(format!("{}", e), Some(file_size)); - return Ok(serde_json::to_vec(&resp).unwrap()); - } - }; - match std::fs::metadata(&next_path) { - Ok(next_meta) => { - effective_file_size = next_meta.len(); - effective_path = next_path; - effective_shard = next_shard; - start = 0; - } - Err(e) => { - let resp = make_err_resp( - format!( - "stat next log shard failed: path={} err={}", - next_path.display(), - e - ), - Some(file_size), - ); - return Ok(serde_json::to_vec(&resp).unwrap()); - } - } - } else if let Ok(Some(latest_shard)) = - workload_log_latest_shard_identity(&logical_path) - { - if latest_shard != cursor.shard { - let latest_path = - match workload_log_path_for_shard(&logical_path, &latest_shard) { - Ok(v) => v, - Err(e) => { - let resp = make_err_resp(format!("{}", e), Some(file_size)); - return Ok(serde_json::to_vec(&resp).unwrap()); - } - }; - match std::fs::metadata(&latest_path) { - Ok(latest_meta) => { - effective_file_size = latest_meta.len(); - effective_path = latest_path; - effective_shard = latest_shard; - start = 0; - } - Err(e) => { - let resp = make_err_resp( - format!( - "stat latest log shard failed: path={} err={}", - latest_path.display(), - e - ), - Some(file_size), - ); - return Ok(serde_json::to_vec(&resp).unwrap()); - } - } - } - } - } - let end = match max_bytes { - Some(max_bytes) => { - std::cmp::min(effective_file_size, start.saturating_add(max_bytes)) - } - None => effective_file_size, - }; - ( - start, - end, - Some(WorkloadLogCursor { - shard: effective_shard.clone(), - offset: start, - }), - Some(WorkloadLogCursor { - shard: effective_shard.clone(), - offset: end, - }), - effective_path, - effective_file_size, - ) - } else { - let end = file_size; - let start = match max_bytes { - Some(max_bytes) => end.saturating_sub(max_bytes), - None => 0, - }; - ( - start, - end, - Some(WorkloadLogCursor { - shard: shard.clone(), - offset: start, - }), - Some(WorkloadLogCursor { - shard: shard.clone(), - offset: end, - }), - path.clone(), - file_size, - ) - } - } - LogReadDirection::Backward => { - let Some(cursor) = req.cursor.as_ref() else { - let resp = make_err_resp( - "cursor is required for Backward reads".to_string(), - Some(file_size), - ); - return Ok(serde_json::to_vec(&resp).unwrap()); - }; + let (start, end, start_cursor, end_cursor, effective_path, effective_file_size) = match req + .direction + { + LogReadDirection::Forward => { + if let Some(cursor) = req.cursor.as_ref() { if cursor.offset > file_size { let resp = make_err_resp( format!( @@ -3331,30 +3222,31 @@ impl UserRpcHandler for ReadWorkloadLogChunkHandler { let mut effective_path = path.clone(); let mut effective_shard = shard.clone(); let mut effective_file_size = file_size; - let mut end = cursor.offset; - if cursor.offset == 0 { - if let Ok(Some(prev_shard)) = - workload_log_previous_shard(&logical_path, &cursor.shard) + let mut start = cursor.offset; + if cursor.offset == file_size { + if let Ok(Some(next_shard)) = + workload_log_next_shard(&logical_path, &cursor.shard) { - let prev_path = match workload_log_path_for_shard(&logical_path, &prev_shard) { - Ok(v) => v, - Err(e) => { - let resp = make_err_resp(format!("{}", e), Some(file_size)); - return Ok(serde_json::to_vec(&resp).unwrap()); - } - }; - match std::fs::metadata(&prev_path) { - Ok(prev_meta) => { - effective_file_size = prev_meta.len(); - effective_path = prev_path; - effective_shard = prev_shard; - end = effective_file_size; + let next_path = + match workload_log_path_for_shard(&logical_path, &next_shard) { + Ok(v) => v, + Err(e) => { + let resp = make_err_resp(format!("{}", e), Some(file_size)); + return Ok(serde_json::to_vec(&resp).unwrap()); + } + }; + match std::fs::metadata(&next_path) { + Ok(next_meta) => { + effective_file_size = next_meta.len(); + effective_path = next_path; + effective_shard = next_shard; + start = 0; } Err(e) => { let resp = make_err_resp( format!( - "stat previous log shard failed: path={} err={}", - prev_path.display(), + "stat next log shard failed: path={} err={}", + next_path.display(), e ), Some(file_size), @@ -3362,11 +3254,47 @@ impl UserRpcHandler for ReadWorkloadLogChunkHandler { return Ok(serde_json::to_vec(&resp).unwrap()); } } + } else if let Ok(Some(latest_shard)) = + workload_log_latest_shard_identity(&logical_path) + { + if latest_shard != cursor.shard { + let latest_path = + match workload_log_path_for_shard(&logical_path, &latest_shard) + { + Ok(v) => v, + Err(e) => { + let resp = + make_err_resp(format!("{}", e), Some(file_size)); + return Ok(serde_json::to_vec(&resp).unwrap()); + } + }; + match std::fs::metadata(&latest_path) { + Ok(latest_meta) => { + effective_file_size = latest_meta.len(); + effective_path = latest_path; + effective_shard = latest_shard; + start = 0; + } + Err(e) => { + let resp = make_err_resp( + format!( + "stat latest log shard failed: path={} err={}", + latest_path.display(), + e + ), + Some(file_size), + ); + return Ok(serde_json::to_vec(&resp).unwrap()); + } + } + } } } - let start = match max_bytes { - Some(max_bytes) => end.saturating_sub(max_bytes), - None => 0, + let end = match max_bytes { + Some(max_bytes) => { + std::cmp::min(effective_file_size, start.saturating_add(max_bytes)) + } + None => effective_file_size, }; ( start, @@ -3382,8 +3310,103 @@ impl UserRpcHandler for ReadWorkloadLogChunkHandler { effective_path, effective_file_size, ) + } else { + let end = file_size; + let start = match max_bytes { + Some(max_bytes) => end.saturating_sub(max_bytes), + None => 0, + }; + ( + start, + end, + Some(WorkloadLogCursor { + shard: shard.clone(), + offset: start, + }), + Some(WorkloadLogCursor { + shard: shard.clone(), + offset: end, + }), + path.clone(), + file_size, + ) } - }; + } + LogReadDirection::Backward => { + let Some(cursor) = req.cursor.as_ref() else { + let resp = make_err_resp( + "cursor is required for Backward reads".to_string(), + Some(file_size), + ); + return Ok(serde_json::to_vec(&resp).unwrap()); + }; + if cursor.offset > file_size { + let resp = make_err_resp( + format!( + "cursor out of range: shard={} cursor={} file_size={}", + cursor.shard, cursor.offset, file_size + ), + Some(file_size), + ); + return Ok(serde_json::to_vec(&resp).unwrap()); + } + let mut effective_path = path.clone(); + let mut effective_shard = shard.clone(); + let mut effective_file_size = file_size; + let mut end = cursor.offset; + if cursor.offset == 0 { + if let Ok(Some(prev_shard)) = + workload_log_previous_shard(&logical_path, &cursor.shard) + { + let prev_path = + match workload_log_path_for_shard(&logical_path, &prev_shard) { + Ok(v) => v, + Err(e) => { + let resp = make_err_resp(format!("{}", e), Some(file_size)); + return Ok(serde_json::to_vec(&resp).unwrap()); + } + }; + match std::fs::metadata(&prev_path) { + Ok(prev_meta) => { + effective_file_size = prev_meta.len(); + effective_path = prev_path; + effective_shard = prev_shard; + end = effective_file_size; + } + Err(e) => { + let resp = make_err_resp( + format!( + "stat previous log shard failed: path={} err={}", + prev_path.display(), + e + ), + Some(file_size), + ); + return Ok(serde_json::to_vec(&resp).unwrap()); + } + } + } + } + let start = match max_bytes { + Some(max_bytes) => end.saturating_sub(max_bytes), + None => 0, + }; + ( + start, + end, + Some(WorkloadLogCursor { + shard: effective_shard.clone(), + offset: start, + }), + Some(WorkloadLogCursor { + shard: effective_shard.clone(), + offset: end, + }), + effective_path, + effective_file_size, + ) + } + }; if end < start { let resp = make_err_resp( @@ -3416,7 +3439,11 @@ impl UserRpcHandler for ReadWorkloadLogChunkHandler { Ok(v) => v, Err(e) => { let resp = make_err_resp( - format!("open log failed: path={} err={}", effective_path.display(), e), + format!( + "open log failed: path={} err={}", + effective_path.display(), + e + ), Some(effective_file_size), ); return Ok(serde_json::to_vec(&resp).unwrap()); @@ -3425,7 +3452,11 @@ impl UserRpcHandler for ReadWorkloadLogChunkHandler { if let Err(e) = std::io::Seek::seek(&mut f, std::io::SeekFrom::Start(start)) { let resp = make_err_resp( - format!("seek log failed: path={} err={}", effective_path.display(), e), + format!( + "seek log failed: path={} err={}", + effective_path.display(), + e + ), Some(effective_file_size), ); return Ok(serde_json::to_vec(&resp).unwrap()); @@ -3434,7 +3465,11 @@ impl UserRpcHandler for ReadWorkloadLogChunkHandler { let mut buf: Vec = vec![0; len]; if let Err(e) = std::io::Read::read_exact(&mut f, &mut buf) { let resp = make_err_resp( - format!("read log failed: path={} err={}", effective_path.display(), e), + format!( + "read log failed: path={} err={}", + effective_path.display(), + e + ), Some(effective_file_size), ); return Ok(serde_json::to_vec(&resp).unwrap()); @@ -4067,8 +4102,7 @@ fn desired_workload_matches_running( &desired.name, &desired.authority, Some(workloads.scope_key.as_str()), - ) - else { + ) else { return false; }; desired_workload_status_matches_goal(&status, desired) @@ -14337,14 +14371,14 @@ mod tests { assert_eq!(scoped_b.len(), 1); assert_eq!(scoped_b[0].pid(), 22); - let listed_a = observe_all_selection_statuses_for_snapshot(&snapshot, Some("/tmp/scope-a")) - .unwrap(); + let listed_a = + observe_all_selection_statuses_for_snapshot(&snapshot, Some("/tmp/scope-a")).unwrap(); assert_eq!(listed_a.len(), 1); assert_eq!(listed_a[0].label, "DaemonSet/target"); assert_eq!(listed_a[0].pid, Some(11)); - let listed_b = observe_all_selection_statuses_for_snapshot(&snapshot, Some("/tmp/scope-b")) - .unwrap(); + let listed_b = + observe_all_selection_statuses_for_snapshot(&snapshot, Some("/tmp/scope-b")).unwrap(); assert_eq!(listed_b.len(), 1); assert_eq!(listed_b[0].label, "DaemonSet/target"); assert_eq!(listed_b[0].pid, Some(22)); @@ -14548,8 +14582,8 @@ mod tests { zombie_infos: Vec::new(), }; - let listed = observe_apply_runtime_statuses_for_snapshot("apply-1", &snapshot, None) - .unwrap(); + let listed = + observe_apply_runtime_statuses_for_snapshot("apply-1", &snapshot, None).unwrap(); assert_eq!(listed.len(), 1); assert_eq!(listed[0].name.as_deref(), Some("target-present")); assert!(listed[0].present); @@ -14774,12 +14808,8 @@ mod tests { None )); - let delete_old = workloads.delete_generation( - WorkloadKind::Deployment, - &name, - &name, - Some("apply-1"), - ); + let delete_old = + workloads.delete_generation(WorkloadKind::Deployment, &name, &name, Some("apply-1")); if !delete_old.ok { let err = delete_old.err.as_deref().unwrap_or_default(); assert!( @@ -14813,8 +14843,7 @@ mod tests { delete_current.ok, "unguarded delete should bind and retire the current visible generation: {delete_current:?}" ); - wait_for_selection_absent(WorkloadKind::Deployment, &name, &name, Some("apply-2")) - .unwrap(); + wait_for_selection_absent(WorkloadKind::Deployment, &name, &name, Some("apply-2")).unwrap(); } #[test] @@ -14826,9 +14855,12 @@ mod tests { python_exe.display() ); let workdir = tempfile::tempdir().unwrap(); - let runtime = - SelectionSupervisorRuntime::materialize(workdir.path(), workdir.path(), python_exe.as_path()) - .unwrap(); + let runtime = SelectionSupervisorRuntime::materialize( + workdir.path(), + workdir.path(), + python_exe.as_path(), + ) + .unwrap(); assert!(runtime.script_path.exists()); assert!( runtime @@ -14849,9 +14881,12 @@ mod tests { python_exe.display() ); let workdir = tempfile::tempdir().unwrap(); - let runtime = - SelectionSupervisorRuntime::materialize(workdir.path(), workdir.path(), python_exe.as_path()) - .unwrap(); + let runtime = SelectionSupervisorRuntime::materialize( + workdir.path(), + workdir.path(), + python_exe.as_path(), + ) + .unwrap(); let log_path = workdir.path().join("startup.log"); let command = vec![ python_exe.display().to_string(), @@ -14876,7 +14911,9 @@ mod tests { "--".to_string(), "/bin/true".to_string(), ]; - let pid = runtime.spawn_detached_command(&log_path, command.as_slice()).unwrap(); + let pid = runtime + .spawn_detached_command(&log_path, command.as_slice()) + .unwrap(); let deadline = Instant::now() + Duration::from_secs(10); let expected = "owner-ts-ms must be positive"; let mut saw_expected = false; @@ -15164,7 +15201,9 @@ mod tests { }), max_bytes: Some(65536), }; - let raw = handler.handle("n1".into(), &serde_json::to_vec(&req).unwrap()).unwrap(); + let raw = handler + .handle("n1".into(), &serde_json::to_vec(&req).unwrap()) + .unwrap(); let resp: ReadWorkloadLogResp = serde_json::from_slice(&raw).unwrap(); assert!(resp.ok, "{resp:?}"); assert_eq!(resp.text.as_deref(), Some("new\n")); @@ -15209,7 +15248,9 @@ mod tests { }), max_bytes: Some(65536), }; - let raw = handler.handle("n1".into(), &serde_json::to_vec(&req).unwrap()).unwrap(); + let raw = handler + .handle("n1".into(), &serde_json::to_vec(&req).unwrap()) + .unwrap(); let resp: ReadWorkloadLogResp = serde_json::from_slice(&raw).unwrap(); assert!(resp.ok, "{resp:?}"); assert_eq!(resp.text.as_deref(), Some("old\n")); diff --git a/fluxon_rs/fluxon_pyo3/src/error.rs b/fluxon_rs/fluxon_pyo3/src/error.rs index 97ab680..652ef0b 100644 --- a/fluxon_rs/fluxon_pyo3/src/error.rs +++ b/fluxon_rs/fluxon_pyo3/src/error.rs @@ -1,6 +1,6 @@ -use pyo3::PyErr; use pyo3::prelude::*; use pyo3::types::PyDict; +use pyo3::PyErr; use fluxon_mq::MpscError as CoreMpscError; // Re-export the core MPSC error type for callers who want to depend on a single error hub. @@ -221,6 +221,23 @@ pub(crate) fn new_key_being_written_error( error_class.call((), Some(&kwargs)).unwrap().into() } +pub(crate) fn new_key_already_exists_error( + py: Python<'_>, + message: &str, + key: Option<&str>, +) -> PyObject { + let api_error_module = py.import_bound("fluxon_py.api_error").unwrap(); + let error_class = api_error_module.getattr("KeyAlreadyExistsError").unwrap(); + + let kwargs = PyDict::new_bound(py); + kwargs.set_item("message", message).unwrap(); + if let Some(k) = key { + kwargs.set_item("key", k).unwrap(); + } + + error_class.call((), Some(&kwargs)).unwrap().into() +} + pub(crate) fn new_storage_full_error( py: Python<'_>, message: &str, @@ -352,6 +369,7 @@ pub(crate) fn new_payload_lease_not_found_error( /// - TransferEngine::TransferFailedForBlock -> TransferBlockFailedError(可重试) /// - Api::InvalidPutMasterState -> PutDoneFailedError /// - Api::KeyNotFound -> KeyNotFoundError(携带 key) +/// - Api::KeyAlreadyExists -> KeyAlreadyExistsError(携带 key) /// - Api::KeyBeingWritten -> KeyBeingWrittenError(携带 key) /// - Api::NoSpace -> StorageFullError(available_space=free_capacity) /// - 其他 -> NetworkError(携带格式化消息) @@ -381,6 +399,11 @@ pub(crate) fn py_error_from_kv_error( &format!("{}: Key not found: {}", prefix, key), Some(key), ), + KvError::Api(CoreApiError::KeyAlreadyExists { key }) => new_key_already_exists_error( + py, + &format!("{}: Key already exists: {}", prefix, key), + Some(key), + ), KvError::Api(CoreApiError::KeyBeingWritten { key }) => new_key_being_written_error( py, &format!("{}: Key is currently being written: {}", prefix, key), diff --git a/fluxon_rs/fluxon_pyo3/src/lib.rs b/fluxon_rs/fluxon_pyo3/src/lib.rs index 631f1ea..e86ef21 100644 --- a/fluxon_rs/fluxon_pyo3/src/lib.rs +++ b/fluxon_rs/fluxon_pyo3/src/lib.rs @@ -1,43 +1,62 @@ -use std::collections::{BTreeMap, BTreeSet}; +use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::panic::{self, AssertUnwindSafe}; use std::path::{Path, PathBuf}; use std::slice; -use std::sync::Arc; -use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use std::sync::{Arc, Mutex, RwLock}; use std::thread; use bytes::Bytes; use fluxon_cli::config::MonitorConfigYaml as MonitorCliConfigYaml; use fluxon_fs::config::{ + FluxonFsRequestIdentity, FluxonFsS3KvMissPolicy, FsAgentDeclaredExportWire, FLUXON_FS_CONTROL_SCHEMA_VERSION, FS_AGENT_DECLARED_EXPORT_JSON_KEY, FS_AGENT_EXPORT_PUBLISH_RPC_PATH, FS_AGENT_EXPORT_UNPUBLISH_RPC_PATH, - FS_MASTER_CONFIG_RPC_PATH, FluxonFsRequestIdentity, FluxonFsS3KvMissPolicy, - FsAgentDeclaredExportWire, + FS_MASTER_CONFIG_RPC_PATH, +}; +use fluxon_kv::client_kv_api::msg_pack::{ + ExternalBatchPutCommitItemReq, ExternalBatchPutCommitReq, ExternalBatchPutStartItemReq, + ExternalBatchPutStartReq, ExternalBatchPutTransferEndItemReq, ExternalBatchPutTransferEndReq, + ExternalPutRevokeReq, }; use fluxon_kv::client_kv_api::ClientKvApiViewTrait; -use fluxon_kv::cluster_manager::ClusterManagerViewTrait; +use fluxon_kv::client_kv_api::{ + ClientKvApiInner, OwnerLocalReserveSlotLease, OwnerLocalReserveSlotRef, OwnerReservedPutItem, +}; +use fluxon_kv::client_seg_pool::ClientSegPoolViewTrait; use fluxon_kv::cluster_manager::app_logic_ext::ClusterManagerAppLogicExt; +use fluxon_kv::cluster_manager::ClusterManagerViewTrait; use fluxon_kv::config::{ClientConfigYaml, MasterConfigYaml}; +use fluxon_kv::external_client_api::ExternalClientApiViewTrait; +use fluxon_kv::master_kv_router::msg_pack::{ + BatchPreparePutKeyItemReq, BatchPutDoneItemReq, BatchPutRevokeItemReq, BatchPutStartItemReq, + PutDoneCommittedSlot, +}; use fluxon_kv::master_lease_manager::msg_pack::{AllocateClientLeaseReq, ClientLeaseKeepaliveReq}; -use fluxon_kv::p2p::msg_pack::{MsgPack, RPCCaller, call_rpc}; +use fluxon_kv::memholder::kvclient_encode::{flat_kv_decode_borrowed, BorrowedFlatKvValueRange}; +use fluxon_kv::memholder::{ + ExternalMemHolder as RustExternalMemHolder, MemoryInfo as RustMemoryInfo, + UserMemHolder as RustUserMemHolder, +}; +use fluxon_kv::p2p::msg_pack::{call_rpc, MsgPack, RPCCaller}; use fluxon_kv::p2p::p2p_module::P2pModuleViewTrait; -use fluxon_kv::p2p::p2p_module::{UserRpcHandler, user_rpc_register_handler}; +use fluxon_kv::p2p::p2p_module::{user_rpc_register_handler, UserRpcHandler}; use fluxon_kv::rpcresp_kvresult_convert::msg_and_error::{ ApiError as CoreApiError, KvError as CoreKvError, KvResult, OK, }; use fluxon_kv::user_api::FlatDict; use fluxon_kv::user_api::FlatValue; use fluxon_kv::user_api::FluxonUserApi; +use fluxon_kv::OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES; use fluxon_kv::{ - ConfigArg, Framework, KvClientTrait, KvGetResult, config::{ClientConfig, MasterConfig}, - run_client, run_master, + run_client, run_master, ConfigArg, Framework, KvClientTrait, KvGetResult, }; use fluxon_ops; use fluxon_proxy; -use fluxon_util::run_async_from_sync::{SyncAsyncBridge, borrow_stable_owner}; +use fluxon_util::run_async_from_sync::{borrow_stable_owner, SyncAsyncBridge}; use fluxon_util::{ - FluxonCliProxyDescriptorV2, FluxonCliProxyTransportV2, fluxon_cli_proxy_desc_etcd_key_v2, + fluxon_cli_proxy_desc_etcd_key_v2, FluxonCliProxyDescriptorV2, FluxonCliProxyTransportV2, }; use futures::Future; use pyo3::exceptions::{PyOSError, PyPermissionError, PyRuntimeError, PyValueError}; @@ -58,6 +77,7 @@ include!(env!("FLUXON_PYO3_TEST_PYTHON_LINK_RS")); mod memholder; pub use memholder::{ExternalMemHolder, MemHolder}; mod flatdict_zerocopy; +use flatdict_zerocopy::{decode_flat_dict_to_wrapped_py_object, FlatDictDataOwner}; mod kvfuture; pub use kvfuture::KvFuture; mod error; @@ -1930,6 +1950,451 @@ fn new_store_closed_error(py: Python, message: &str) -> PyObject { crate::error::new_store_closed_error(py, message) } +#[derive(Clone, Copy, Debug)] +struct RegisteredBufferRange { + start: usize, + end: usize, +} + +impl RegisteredBufferRange { + fn contains(&self, ptr: usize, len: usize) -> bool { + if len == 0 { + return ptr >= self.start && ptr <= self.end; + } + let Some(req_end) = ptr.checked_add(len) else { + return false; + }; + ptr >= self.start && req_end <= self.end + } +} + +#[derive(Default, Debug)] +struct RegisteredBufferRegistry { + ranges: Vec, +} + +impl RegisteredBufferRegistry { + fn register(&mut self, ptr: usize, len: usize) { + let end = ptr.saturating_add(len); + self.ranges.push(RegisteredBufferRange { start: ptr, end }); + } + + fn contains(&self, ptr: usize, len: usize) -> bool { + self.ranges.iter().any(|range| range.contains(ptr, len)) + } +} + +const DEFAULT_PYO3_BATCH_CONCURRENCY: usize = 128; + +fn kv_error_to_ret_code(err: &CoreKvError) -> i32 { + match err { + CoreKvError::Config(inner) => -(inner.code() as i32), + CoreKvError::Api(inner) => -(inner.code() as i32), + CoreKvError::P2p(inner) => -(inner.code() as i32), + CoreKvError::SharedMem(inner) => -(inner.code() as i32), + CoreKvError::Unreachable(inner) => -(inner.code() as i32), + CoreKvError::ClusterManagerExt(inner) => -(inner.code() as i32), + CoreKvError::Metric(inner) => -(inner.code() as i32), + CoreKvError::LeaseMgr(inner) => -(inner.code() as i32), + CoreKvError::TransferEngine(inner) => -(inner.code() as i32), + CoreKvError::P2pTransfer(inner) => -(inner.code() as i32), + } +} + +fn rpc_item_error_to_ret_code(error_code: u32, error_json: &str) -> i32 { + if error_code == OK { + 0 + } else { + let err = CoreKvError::from_json(error_code, error_json); + kv_error_to_ret_code(&err) + } +} + +fn payload_slice_from_get_result<'a>(key: &str, get_result: &'a KvGetResult) -> KvResult<&'a [u8]> { + let data = match get_result { + KvGetResult::Owner(Some(holder)) => holder.bytes(), + KvGetResult::External(Some(holder)) => holder.bytes(), + KvGetResult::Owner(None) | KvGetResult::External(None) => { + return Err(CoreKvError::Api(CoreApiError::KeyNotFound { + key: key.to_string(), + })); + } + }; + + let entries = flat_kv_decode_borrowed(data).map_err(|detail| { + CoreKvError::Api(CoreApiError::Unknown { + detail: format!("decode flat dict for key {} failed: {}", key, detail), + }) + })?; + for entry in entries { + if entry.key != "payload" { + continue; + } + if let BorrowedFlatKvValueRange::BytesRange { start, len } = entry.value { + let end = start.checked_add(len).ok_or_else(|| { + CoreKvError::Api(CoreApiError::Unknown { + detail: format!("payload range overflow for key {}", key), + }) + })?; + if end > data.len() { + return Err(CoreKvError::Api(CoreApiError::Unknown { + detail: format!( + "payload range out of bounds for key {}: end={} data_len={}", + key, + end, + data.len() + ), + })); + } + return Ok(&data[start..end]); + } + return Err(CoreKvError::Api(CoreApiError::InvalidArgument { + detail: format!("key {} payload field is not bytes", key), + })); + } + + Err(CoreKvError::Api(CoreApiError::InvalidArgument { + detail: format!("key {} does not contain payload field", key), + })) +} + +const FLUXON_PLAN_BLOB_MAGIC: u64 = 0x4658_504c_414e_5631; + +#[derive(Clone)] +enum FluxonPlanRegistryEntry { + Put(Arc), + Get(Arc), +} + +enum FluxonPutPlanState { + Prepared(StagedPutPlanData), + Committing, +} + +struct FluxonPutPlan { + blob: Box<[u64]>, + state: Mutex, +} + +struct FluxonGetViewsPlan { + blob: Box<[u64]>, + _holders: Vec, +} + +enum StagedGetViewHolder { + Owner { _holder: Arc }, + External { _holder: Arc }, +} + +fn external_get_start_result_to_py( + started: &fluxon_kv::external_client_api::ExternalClientGetStartResp, + py: Python, +) -> PyObject { + let out = PyDict::new_bound(py); + out.set_item("handle", started.handle).expect("set handle"); + out.set_item("raw_prefix_hit_len", started.raw_prefix_hit_len as u64) + .expect("set raw_prefix_hit_len"); + out.into_py(py) +} + +#[derive(Clone)] +enum StagedPutPlanData { + Owner(StagedOwnerPutPlanData), + External(StagedExternalPutPlanData), +} + +#[derive(Clone)] +struct StagedOwnerPutPlanData { + keys: Vec, + value_len: u64, + write_through: bool, + key_reservation_ids: Vec, + slot_lease: OwnerLocalReserveSlotLease, +} + +#[derive(Clone)] +struct StagedExternalPutPlanData { + keys: Vec, + value_len: u64, + write_through: bool, + started_time: i64, + items: Vec, + short_circuit_payload: bool, +} + +#[derive(Clone)] +struct StagedExternalPutItem { + put_id: fluxon_kv::master_kv_router::put::PutIDForAKey, + src_offset: u64, + target_offset: u64, + transfer_target_offset: Option, + peer_id: Option, + target_base_addr: u64, +} + +#[derive(Clone)] +struct StagedPutCommitItem { + idx: usize, + reserved_item: OwnerReservedPutItem, + slot_ref: OwnerLocalReserveSlotRef, +} + +#[derive(Clone, Debug, Default)] +struct FluxonIoLocalitySnapshot { + op_count: u64, + bytes: u64, + transfer_us: u64, +} + +impl FluxonIoLocalitySnapshot { + fn bandwidth_gbps(&self) -> f64 { + if self.transfer_us == 0 { + return 0.0; + } + (self.bytes as f64) / (self.transfer_us as f64 / 1_000_000.0) / 1_000_000_000.0 + } +} + +#[derive(Clone, Debug, Default)] +struct FluxonLocalitySnapshot { + l2_local_hit_pages: u64, + l2_local_hit_bytes: u64, + l2_remote_hit_pages: u64, + l2_remote_hit_bytes: u64, + put_local: FluxonIoLocalitySnapshot, + put_remote: FluxonIoLocalitySnapshot, + get_local: FluxonIoLocalitySnapshot, + get_remote: FluxonIoLocalitySnapshot, +} + +#[derive(Default)] +struct FluxonLocalityCounters { + l2_local_hit_pages: AtomicU64, + l2_local_hit_bytes: AtomicU64, + l2_remote_hit_pages: AtomicU64, + l2_remote_hit_bytes: AtomicU64, + put_local_ops: AtomicU64, + put_local_bytes: AtomicU64, + put_local_transfer_us: AtomicU64, + put_remote_ops: AtomicU64, + put_remote_bytes: AtomicU64, + put_remote_transfer_us: AtomicU64, + get_local_ops: AtomicU64, + get_local_bytes: AtomicU64, + get_local_transfer_us: AtomicU64, + get_remote_ops: AtomicU64, + get_remote_bytes: AtomicU64, + get_remote_transfer_us: AtomicU64, +} + +impl FluxonLocalityCounters { + fn snapshot(&self) -> FluxonLocalitySnapshot { + FluxonLocalitySnapshot { + l2_local_hit_pages: self.l2_local_hit_pages.load(Ordering::Relaxed), + l2_local_hit_bytes: self.l2_local_hit_bytes.load(Ordering::Relaxed), + l2_remote_hit_pages: self.l2_remote_hit_pages.load(Ordering::Relaxed), + l2_remote_hit_bytes: self.l2_remote_hit_bytes.load(Ordering::Relaxed), + put_local: FluxonIoLocalitySnapshot { + op_count: self.put_local_ops.load(Ordering::Relaxed), + bytes: self.put_local_bytes.load(Ordering::Relaxed), + transfer_us: self.put_local_transfer_us.load(Ordering::Relaxed), + }, + put_remote: FluxonIoLocalitySnapshot { + op_count: self.put_remote_ops.load(Ordering::Relaxed), + bytes: self.put_remote_bytes.load(Ordering::Relaxed), + transfer_us: self.put_remote_transfer_us.load(Ordering::Relaxed), + }, + get_local: FluxonIoLocalitySnapshot { + op_count: self.get_local_ops.load(Ordering::Relaxed), + bytes: self.get_local_bytes.load(Ordering::Relaxed), + transfer_us: self.get_local_transfer_us.load(Ordering::Relaxed), + }, + get_remote: FluxonIoLocalitySnapshot { + op_count: self.get_remote_ops.load(Ordering::Relaxed), + bytes: self.get_remote_bytes.load(Ordering::Relaxed), + transfer_us: self.get_remote_transfer_us.load(Ordering::Relaxed), + }, + } + } + + fn record_l2_hit(&self, remote: bool, bytes: u64) { + if remote { + self.l2_remote_hit_pages.fetch_add(1, Ordering::Relaxed); + self.l2_remote_hit_bytes.fetch_add(bytes, Ordering::Relaxed); + } else { + self.l2_local_hit_pages.fetch_add(1, Ordering::Relaxed); + self.l2_local_hit_bytes.fetch_add(bytes, Ordering::Relaxed); + } + } + + fn record_put(&self, remote: bool, bytes: u64, transfer_us: i64) { + let transfer_us = transfer_us.max(0) as u64; + if remote { + self.put_remote_ops.fetch_add(1, Ordering::Relaxed); + self.put_remote_bytes.fetch_add(bytes, Ordering::Relaxed); + self.put_remote_transfer_us + .fetch_add(transfer_us, Ordering::Relaxed); + } else { + self.put_local_ops.fetch_add(1, Ordering::Relaxed); + self.put_local_bytes.fetch_add(bytes, Ordering::Relaxed); + self.put_local_transfer_us + .fetch_add(transfer_us, Ordering::Relaxed); + } + } + + fn record_get(&self, remote: bool, bytes: u64, transfer_us: i64) { + let transfer_us = transfer_us.max(0) as u64; + if remote { + self.get_remote_ops.fetch_add(1, Ordering::Relaxed); + self.get_remote_bytes.fetch_add(bytes, Ordering::Relaxed); + self.get_remote_transfer_us + .fetch_add(transfer_us, Ordering::Relaxed); + } else { + self.get_local_ops.fetch_add(1, Ordering::Relaxed); + self.get_local_bytes.fetch_add(bytes, Ordering::Relaxed); + self.get_local_transfer_us + .fetch_add(transfer_us, Ordering::Relaxed); + } + } +} + +fn build_plan_blob(value_ptrs: &[u64]) -> Box<[u64]> { + let mut words = Vec::with_capacity(2 + value_ptrs.len()); + words.push(FLUXON_PLAN_BLOB_MAGIC); + words.push(value_ptrs.len() as u64); + words.extend_from_slice(value_ptrs); + words.into_boxed_slice() +} + +fn plan_ptr_from_blob(blob: &[u64]) -> usize { + blob.as_ptr() as usize +} + +fn plan_ptr_u64_to_usize(plan_ptr: u64, py: Python) -> Result { + let plan_ptr_usize = usize::try_from(plan_ptr) + .map_err(|_| new_invalid_argument_error(py, "plan_ptr out of range"))?; + if plan_ptr_usize == 0 { + return Err(new_invalid_argument_error(py, "plan_ptr must be non-zero")); + } + Ok(plan_ptr_usize) +} + +fn cleanup_plan_registry_entry( + registry: &Arc>>, + plan_ptr: usize, +) { + let mut guard = registry.write().expect("plan_registry poisoned"); + guard.remove(&plan_ptr); +} + +async fn release_staged_put_resources( + inner: &ClientKvApiInner, + key_reservation_ids: Vec, + slot_lease: OwnerLocalReserveSlotLease, +) -> KvResult<()> { + let release_keys_result = inner + .batch_release_put_key_reservations(key_reservation_ids) + .await; + let release_slot_result = inner + .owner_release_local_reserve_slot_lease(slot_lease) + .await; + match (release_keys_result, release_slot_result) { + (Ok(_), Ok(_)) => Ok(()), + (Err(err), Ok(_)) => Err(err), + (Ok(_), Err(err)) => Err(err), + (Err(primary_err), Err(cleanup_err)) => Err(CoreKvError::Api(CoreApiError::Unknown { + detail: format!( + "release_staged_put_resources failed twice: batch_release_put_key_reservations_err={} release_local_slot_lease_err={}", + primary_err, cleanup_err + ), + })), + } +} + +async fn release_put_key_reservations_only( + inner: &ClientKvApiInner, + key_reservation_ids: Vec, +) -> KvResult<()> { + inner + .batch_release_put_key_reservations(key_reservation_ids) + .await + .map(|_| ()) +} + +fn staged_put_uses_direct_local_commit(item: &OwnerReservedPutItem) -> bool { + !item.write_through || (item.peer_node_id.is_none() && item.src_addr == item.target_addr) +} + +fn combine_kv_errors( + context: &str, + primary_err: CoreKvError, + secondary_err: CoreKvError, +) -> CoreKvError { + CoreKvError::Api(CoreApiError::Unknown { + detail: format!( + "{}: primary_err={} secondary_err={}", + context, primary_err, secondary_err + ), + }) +} + +fn remove_precommit_local_visible_infos( + inner: &ClientKvApiInner, + keys: &[String], + memory_infos: &[Arc], +) { + for (key, memory_info) in keys.iter().zip(memory_infos.iter()) { + let _ = inner.remove_precommit_local_reserve_resident_slot_if_same(key, memory_info); + } +} + +fn remove_precommit_local_visible_infos_for_items( + inner: &ClientKvApiInner, + items: &[StagedPutCommitItem], + memory_infos: &[Arc], +) { + for item in items { + let _ = inner.remove_precommit_local_reserve_resident_slot_if_same( + &item.reserved_item.key, + &memory_infos[item.idx], + ); + } +} + +async fn revoke_staged_put_items( + inner: &ClientKvApiInner, + items: &[StagedPutCommitItem], +) -> KvResult<()> { + if items.is_empty() { + return Ok(()); + } + inner + .batch_put_revoke( + items + .iter() + .map(|item| BatchPutRevokeItemReq { + key: item.reserved_item.key.clone(), + put_id: item.reserved_item.put_id, + }) + .collect(), + ) + .await + .map(|_| ()) +} + +#[pyfunction] +fn decode_flat_dict_payload(payload: Vec, py: Python<'_>) -> PyObject { + match decode_flat_dict_to_wrapped_py_object(py, FlatDictDataOwner::from_owned_bytes(payload)) { + Ok(value) => ApiResult::new_success(value).into_py_object(py), + Err(err) => ApiResult::::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "flat dict decode failed", + )) + .into_py_object(py), + } +} + #[pyfunction] fn monitor_render_cli(config_path: String, workdir: String) -> PyResult { let cfg_yaml = MonitorCliConfigYaml::from_file(std::path::Path::new(&config_path)) @@ -2676,6 +3141,9 @@ pub struct KvClient { // - Futures must not hold Arc; they should spawn via Handle clones only. runtime: Option, config: ClientConfig, + registered_buffers: RwLock, + plan_registry: Arc>>, + locality_counters: Arc, } #[pymethods] @@ -2751,6 +3219,9 @@ impl KvClient { framework: Some(framework), runtime: Some(runtime), config: final_config, + registered_buffers: RwLock::new(RegisteredBufferRegistry::default()), + plan_registry: Arc::new(RwLock::new(HashMap::new())), + locality_counters: Arc::new(FluxonLocalityCounters::default()), }; match Py::new(py, client) { @@ -2800,28 +3271,9 @@ impl KvClient { self.config.cluster_name.clone() } - /// Allocate a fluxon-kv lease id synchronously. - /// Always allocate a new lease id (no reuse by requested id). - /// Allocate with the provided TTL seconds (must be >= MIN_CLIENT_TTL_SECONDS). - #[pyo3(signature = (ttl_seconds))] - fn allocate_lease(&self, ttl_seconds: u64, py: Python) -> PyObject { - fn allocate_lease_inner( - client: &KvClient, - ttl_seconds: u64, - py: Python, - ) -> ApiResult { - // Enforce minimum TTL at the PyO3 boundary so obvious mistakes fail fast. - if ttl_seconds - < fluxon_kv::master_lease_manager::MasterLeaseManager::MIN_CLIENT_TTL_SECONDS - { - return ApiResult::new_error(new_invalid_argument_error( - py, - &format!( - "allocate_lease(ttl_seconds) requires ttl_seconds >= {} seconds", - fluxon_kv::master_lease_manager::MasterLeaseManager::MIN_CLIENT_TTL_SECONDS, - ), - )); - } + /// Wait until the local segment mapping is ready for direct hostless access. + fn wait_local_segments_ready(&self, py: Python) -> PyObject { + fn wait_local_segments_ready_inner(client: &KvClient, py: Python) -> ApiResult { let framework = match require_kv_framework_api(client, py) { Ok(v) => v, Err(e) => return ApiResult::new_error(e), @@ -2835,64 +3287,121 @@ impl KvClient { )); } }; - // Blocking call on the client's runtime; simple and predictable for callers. - let r: Result = match py.allow_threads(|| { + + if framework.is_external_mode() { + let framework_for_wait = framework.clone(); + let ready_result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + framework_for_wait + .external_client_api_view() + .external_client_api() + .inner() + .wait_current_owner_mapped_range() + .await + }) + }) { + Ok(v) => v, + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); + } + }; + return match ready_result { + Ok((node_id, owner_start_time, write_ptr, read_ptr, len)) => { + let item = PyDict::new_bound(py); + item.set_item("segment_label", "external_owner:0") + .expect("set segment_label"); + item.set_item("write_ptr", write_ptr) + .expect("set write_ptr"); + item.set_item("read_ptr", read_ptr).expect("set read_ptr"); + item.set_item("len", len).expect("set len"); + item.set_item("generation", owner_start_time) + .expect("set generation"); + item.set_item("node_id", node_id).expect("set node_id"); + let out = PyList::empty_bound(py); + out.append(item).expect("append external owner segment"); + ApiResult::new_success(out.into_py(py)) + } + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "wait_local_segments_ready failed", + )), + }; + } + + let self_info = framework + .cluster_manager_view() + .cluster_manager() + .get_self_info(); + let framework_for_wait = framework.clone(); + let ready_result = match py.allow_threads(|| { runtime.run_async_from_sync(async move { - framework - .kv_allocate_lease(ttl_seconds) + framework_for_wait + .client_seg_pool_view() + .client_seg_pool() + .mapped_range() .await - .map_err(|e| e.to_string()) + .ok_or_else(|| { + CoreKvError::Api(CoreApiError::Unknown { + detail: "local owner segment is not mounted".to_string(), + }) + }) }) }) { Ok(v) => v, - Err(e) => Err(format!("runtime bridge failed: {}", e)), + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); + } }; - match r { - Ok(id) => ApiResult::new_success(Python::with_gil(|py| id.into_py(py))), - Err(e) => ApiResult::new_error(Python::with_gil(|py| { - new_network_error(py, &format!("Allocate lease failed: {}", e), None) - })), + match ready_result { + Ok((write_ptr, read_ptr, len)) => { + let item = PyDict::new_bound(py); + item.set_item("segment_label", "cpu:0") + .expect("set segment_label"); + item.set_item("write_ptr", write_ptr) + .expect("set write_ptr"); + item.set_item("read_ptr", read_ptr).expect("set read_ptr"); + item.set_item("len", len).expect("set len"); + item.set_item("generation", self_info.node_start_time) + .expect("set generation"); + item.set_item("node_id", self_info.id).expect("set node_id"); + let out = PyList::empty_bound(py); + out.append(item).expect("append local segment"); + ApiResult::new_success(out.into_py(py)) + } + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "wait_local_segments_ready failed", + )), } } - allocate_lease_inner(self, ttl_seconds, py).into_py_object(py) + + wait_local_segments_ready_inner(self, py).into_py_object(py) } - /// Keepalive a lease synchronously. Type must be specified to avoid ambiguity. - /// This uses the lease's existing TTL on the master. - #[pyo3(signature = (lease_id, lease_type))] - fn keepalive_lease( - &self, - lease_id: u64, - lease_type: &Bound<'_, PyAny>, - py: Python, - ) -> PyObject { - fn keepalive_lease_inner( + #[pyo3(signature = ())] + fn reserve_local_grant_blocking(&self, py: Python) -> PyObject { + fn reserve_local_grant_blocking_inner( client: &KvClient, - lease_id: u64, - lease_type: &Bound<'_, PyAny>, py: Python, ) -> ApiResult { - // Accept simple enum-like strings: "kvclient" | "etcd" - let lease_type_str = match lease_type.extract::() { - Ok(s) => s.to_ascii_lowercase(), - Err(_) => { - return ApiResult::new_error(new_invalid_argument_error( - py, - "lease_type must be 'kvclient' or 'etcd'", - )); - } + let framework = match require_kv_framework_api(client, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), }; - - if lease_type_str != "kvclient" { + if framework.is_external_mode() { return ApiResult::new_error(new_invalid_argument_error( py, - "keepalive_lease(type=etcd) is not supported in fluxon_pyo3; use fluxon_mq.LeaseManagerHandle for etcd leases", + "reserve_local_grant_blocking currently only supports owner mode", )); } - let framework = match require_kv_framework_api(client, py) { - Ok(v) => v, - Err(e) => return ApiResult::new_error(e), - }; let runtime = match client.runtime.as_ref() { Some(v) => v, None => { @@ -2902,34 +3411,1514 @@ impl KvClient { )); } }; - let r: Result<(), String> = match py.allow_threads(|| { + let framework_for_reserve = framework.clone(); + let reserve_resp = match py.allow_threads(|| { runtime.run_async_from_sync(async move { - framework - .kv_keepalive_lease(lease_id) + framework_for_reserve + .client_kv_api_view() + .client_kv_api() + .inner() + .reserve_local_grant() .await - .map_err(|e| e.to_string()) }) }) { Ok(v) => v, - Err(e) => Err(format!("runtime bridge failed: {}", e)), - }; - match r { - Ok(_) => { - ApiResult::new_success(Python::with_gil(|py| new_none_success_instance(py))) + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); } - Err(e) => ApiResult::new_error(Python::with_gil(|py| { - new_network_error(py, &format!("Keepalive lease failed: {}", e), None) - })), + }; + match reserve_resp { + Ok(resp) => ApiResult::new_success( + (resp.grant_id, resp.addr, resp.base_addr, resp.len).into_py(py), + ), + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + &format!( + "reserve_local_grant_blocking failed for fixed quantum={}B", + OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES + ), + )), } } - keepalive_lease_inner(self, lease_id, lease_type, py).into_py_object(py) + + reserve_local_grant_blocking_inner(self, py).into_py_object(py) } - /// Put a key-value pair (non-blocking) by encoding a flat dict from raw entries. - /// - /// `ptrs` is a list of `(type_id, dict_key_ptr, dict_key_len, val_u64, val_len, extra)`: - /// - `dict_key_ptr/dict_key_len`: UTF-8 bytes of the dict field key. - /// - For scalar types (bool/int64/float64), `val_u64` stores raw bits and `val_len` is fixed. + #[pyo3(signature = (grant_id))] + fn release_local_grant_blocking(&self, grant_id: u64, py: Python) -> PyObject { + fn release_local_grant_blocking_inner( + client: &KvClient, + grant_id: u64, + py: Python, + ) -> ApiResult { + let framework = match require_kv_framework_api(client, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + if framework.is_external_mode() { + return ApiResult::new_error(new_invalid_argument_error( + py, + "release_local_grant_blocking currently only supports owner mode", + )); + } + let runtime = match client.runtime.as_ref() { + Some(v) => v, + None => { + return ApiResult::new_error(new_general_error( + py, + "Client runtime is missing", + )); + } + }; + let framework_for_release = framework.clone(); + let release_result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + framework_for_release + .client_kv_api_view() + .client_kv_api() + .inner() + .release_local_grant(grant_id) + .await + }) + }) { + Ok(v) => v, + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); + } + }; + match release_result { + Ok(()) => ApiResult::new_success(0i32.into_py(py)), + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "release_local_grant_blocking failed", + )), + } + } + + release_local_grant_blocking_inner(self, grant_id, py).into_py_object(py) + } + + #[pyo3(signature = (keys, value_len, reject_if_inflight_same_key=false, reject_if_exist_same_key=false, write_through=true))] + fn local_fast_put_start( + &self, + keys: Vec, + value_len: u64, + reject_if_inflight_same_key: bool, + reject_if_exist_same_key: bool, + write_through: bool, + py: Python, + ) -> PyObject { + fn local_fast_put_start_inner( + client: &KvClient, + keys: Vec, + value_len: u64, + reject_if_inflight_same_key: bool, + reject_if_exist_same_key: bool, + write_through: bool, + py: Python, + ) -> ApiResult { + if keys.is_empty() { + return ApiResult::new_error(new_invalid_argument_error( + py, + "local_fast_put_start requires at least one key", + )); + } + if value_len == 0 { + return ApiResult::new_error(new_invalid_argument_error( + py, + "local_fast_put_start requires value_len > 0", + )); + } + if value_len > u32::MAX as u64 { + return ApiResult::new_error(new_invalid_argument_error( + py, + "local_fast_put_start value_len exceeds u32 limit", + )); + } + let framework = match require_kv_framework_api(client, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + let runtime = match client.runtime.as_ref() { + Some(v) => v, + None => { + return ApiResult::new_error(new_general_error( + py, + "Client runtime is missing", + )); + } + }; + + if framework.is_external_mode() { + let framework_for_start = framework.clone(); + let keys_for_req = keys.clone(); + let external_start_result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + let external_api_view = framework_for_start.external_client_api_view(); + let inner = external_api_view.external_client_api().inner(); + let started_time = inner.current_owner_start_time().await; + let base_addr = inner.base_ptr().await?; + let short_circuit_payload = inner.short_circuit_put_payload_path_enabled(); + let resp = inner + .external_batch_put_start_rpc(ExternalBatchPutStartReq { + items: keys_for_req + .iter() + .map(|key| ExternalBatchPutStartItemReq { + key: key.clone(), + len: value_len, + reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, + preferred_sub_cluster: None, + }) + .collect(), + started_time, + }) + .await?; + Ok::<_, CoreKvError>((base_addr, started_time, short_circuit_payload, resp)) + }) + }) { + Ok(v) => v, + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); + } + }; + let (base_addr, started_time, short_circuit_payload, resp) = + match external_start_result { + Ok(v) => v, + Err(err) => { + return ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "local_fast_put_start failed", + )); + } + }; + let revoke_started_puts = |started_items: Vec<( + String, + fluxon_kv::master_kv_router::put::PutIDForAKey, + )>| + -> Option { + if started_items.is_empty() { + return None; + } + let framework_for_revoke = framework.clone(); + match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + let external_api_view = framework_for_revoke.external_client_api_view(); + let inner = external_api_view.external_client_api().inner(); + for (key, put_id) in started_items { + inner + .external_put_revoke_rpc(ExternalPutRevokeReq { + key, + put_id: Some(put_id), + started_time, + }) + .await?; + } + Ok::<(), CoreKvError>(()) + }) + }) { + Ok(Ok(())) => None, + Ok(Err(err)) => Some(err), + Err(err) => Some(CoreKvError::Api(CoreApiError::Unknown { + detail: format!( + "runtime bridge failed during external local_fast_put_start cleanup: {}", + err + ), + })), + } + }; + let local_fast_put_start_error = |primary_err: CoreKvError, + cleanup_err: Option| + -> ApiResult { + let err = match cleanup_err { + Some(cleanup_err) => combine_kv_errors( + "local_fast_put_start external cleanup failed", + primary_err, + cleanup_err, + ), + None => primary_err, + }; + ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "local_fast_put_start failed", + )) + }; + if resp.items.len() != keys.len() { + let started_items = keys + .iter() + .zip(resp.items.iter()) + .filter_map(|(key, item)| { + if item.error_code == OK { + item.put_id.map(|put_id| (key.clone(), put_id)) + } else { + None + } + }) + .collect::>(); + let err = CoreKvError::Api(CoreApiError::Unknown { + detail: format!( + "local_fast_put_start external response length mismatch: expected={} got={}", + keys.len(), + resp.items.len() + ), + }); + return local_fast_put_start_error(err, revoke_started_puts(started_items)); + } + let mut value_ptrs = Vec::with_capacity(keys.len()); + let mut items = Vec::with_capacity(keys.len()); + let mut started_items = Vec::with_capacity(keys.len()); + for (key, item) in keys.iter().zip(resp.items.into_iter()) { + if item.error_code != OK { + let err = CoreKvError::from_json(item.error_code, &item.error_json); + return local_fast_put_start_error(err, revoke_started_puts(started_items)); + } + let Some(put_id) = item.put_id else { + let err = CoreKvError::Api(CoreApiError::Unknown { + detail: format!( + "local_fast_put_start external missing put_id in success response for key={}", + key + ), + }); + return local_fast_put_start_error(err, revoke_started_puts(started_items)); + }; + started_items.push((key.clone(), put_id)); + let value_ptr = (base_addr as u64) + .checked_add(item.target_offset) + .ok_or_else(|| { + CoreKvError::Api(CoreApiError::Unknown { + detail: "local_fast_put_start external value ptr overflow" + .to_string(), + }) + }); + let value_ptr = match value_ptr { + Ok(v) => v, + Err(err) => { + return local_fast_put_start_error( + err, + revoke_started_puts(started_items), + ); + } + }; + value_ptrs.push(value_ptr); + items.push(StagedExternalPutItem { + put_id, + src_offset: item.src_offset, + target_offset: item.target_offset, + transfer_target_offset: item.transfer_target_offset, + peer_id: item.peer_id, + target_base_addr: item.target_base_addr, + }); + } + let plan = Arc::new(FluxonPutPlan { + blob: build_plan_blob(&value_ptrs), + state: Mutex::new(FluxonPutPlanState::Prepared(StagedPutPlanData::External( + StagedExternalPutPlanData { + keys, + value_len, + write_through, + started_time, + items, + short_circuit_payload, + }, + ))), + }); + let plan_ptr = plan_ptr_from_blob(plan.blob.as_ref()); + client + .plan_registry + .write() + .expect("plan_registry poisoned") + .insert(plan_ptr, FluxonPlanRegistryEntry::Put(plan)); + return ApiResult::new_success((plan_ptr as u64).into_py(py)); + } + + let key_count = keys.len(); + let framework_for_start = framework.clone(); + let prepare_items = keys + .iter() + .map(|key| BatchPreparePutKeyItemReq { + key: key.clone(), + reject_if_inflight_same_key, + reject_if_exist_same_key, + }) + .collect::>(); + + let prepare_and_slot_lease_result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + let client_kv_api_view = framework_for_start.client_kv_api_view(); + let inner = client_kv_api_view.client_kv_api().inner(); + let prepared = inner.batch_prepare_put_keys(prepare_items).await?; + if prepared.reservation_ids.len() != key_count { + let cleanup_result = inner + .batch_release_put_key_reservations(prepared.reservation_ids.clone()) + .await; + return match cleanup_result { + Ok(_) => Err(CoreKvError::Api(CoreApiError::Unknown { + detail: format!( + "local_fast_put_start reservation length mismatch: expected={} got={}", + key_count, + prepared.reservation_ids.len() + ), + })), + Err(cleanup_err) => Err(CoreKvError::Api(CoreApiError::Unknown { + detail: format!( + "local_fast_put_start reservation length mismatch and cleanup failed: expected={} got={} cleanup_err={}", + key_count, + prepared.reservation_ids.len(), + cleanup_err + ), + })), + }; + } + let slot_lease = match inner + .owner_claim_local_reserve_slot_lease(value_len, key_count) + .await + { + Ok(slot_lease) => slot_lease, + Err(err) => { + let cleanup_result = inner + .batch_release_put_key_reservations(prepared.reservation_ids.clone()) + .await; + return match cleanup_result { + Ok(_) => Err(err), + Err(cleanup_err) => Err(CoreKvError::Api(CoreApiError::Unknown { + detail: format!( + "local_fast_put_start reserve_local_grant failed: {} cleanup_err={}", + err, cleanup_err + ), + })), + }; + } + }; + Ok((prepared.reservation_ids, slot_lease)) + }) + }) { + Ok(v) => v, + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); + } + }; + + let (key_reservation_ids, slot_lease) = match prepare_and_slot_lease_result { + Ok(v) => v, + Err(err) => { + return ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "local_fast_put_start failed", + )); + } + }; + + let value_ptrs = slot_lease.value_ptrs(); + + let plan = Arc::new(FluxonPutPlan { + blob: build_plan_blob(&value_ptrs), + state: Mutex::new(FluxonPutPlanState::Prepared(StagedPutPlanData::Owner( + StagedOwnerPutPlanData { + keys, + value_len, + write_through, + key_reservation_ids, + slot_lease, + }, + ))), + }); + let plan_ptr = plan_ptr_from_blob(plan.blob.as_ref()); + client + .plan_registry + .write() + .expect("plan_registry poisoned") + .insert(plan_ptr, FluxonPlanRegistryEntry::Put(plan)); + ApiResult::new_success((plan_ptr as u64).into_py(py)) + } + + local_fast_put_start_inner( + self, + keys, + value_len, + reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, + py, + ) + .into_py_object(py) + } + + #[pyo3(signature = (plan_ptr))] + fn local_fast_put_commit(&self, plan_ptr: u64, py: Python) -> PyObject { + fn local_fast_put_commit_inner( + client: &KvClient, + plan_ptr: u64, + py: Python, + ) -> ApiResult { + let plan_ptr_usize = match plan_ptr_u64_to_usize(plan_ptr, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + let framework = match require_kv_framework_api(client, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + let runtime_handle = match client.runtime.as_ref() { + Some(v) => v.handle().clone(), + None => { + return ApiResult::new_error(new_general_error( + py, + "Client runtime is missing", + )); + } + }; + let registry_entry = { + let guard = client.plan_registry.read().expect("plan_registry poisoned"); + guard.get(&plan_ptr_usize).cloned() + }; + let Some(FluxonPlanRegistryEntry::Put(plan)) = registry_entry else { + return ApiResult::new_error(new_invalid_argument_error( + py, + "local_fast_put_commit requires a live put plan_ptr", + )); + }; + let plan_data = { + let mut state_guard = plan.state.lock().expect("put plan state poisoned"); + match std::mem::replace(&mut *state_guard, FluxonPutPlanState::Committing) { + FluxonPutPlanState::Prepared(data) => data, + FluxonPutPlanState::Committing => { + return ApiResult::new_error(new_invalid_argument_error( + py, + "local_fast_put_commit cannot be called twice on the same plan_ptr", + )); + } + } + }; + let framework_for_commit = framework.clone(); + let plan_registry = client.plan_registry.clone(); + let transfer_concurrency = 128usize; + let future = async move { + let ret_codes = match plan_data { + StagedPutPlanData::External(external_data) => { + let external_api_view = framework_for_commit.external_client_api_view(); + let inner = external_api_view.external_client_api().inner(); + let keys = external_data.keys; + let items = external_data.items; + let result = if external_data.short_circuit_payload { + inner + .external_batch_put_commit_rpc(ExternalBatchPutCommitReq { + items: keys + .iter() + .zip(items.iter()) + .map(|(key, item)| ExternalBatchPutCommitItemReq { + key: key.clone(), + len: external_data.value_len, + src_offset: item.src_offset, + remote_target: item.peer_id.is_some(), + put_id: Some(item.put_id), + lease_id: None, + write_through: external_data.write_through, + }) + .collect(), + started_time: external_data.started_time, + }) + .await + .map(|resp| { + resp.items + .into_iter() + .map(|item| { + rpc_item_error_to_ret_code( + item.error_code, + &item.error_json, + ) + }) + .collect::>() + }) + } else { + inner + .external_batch_put_transfer_end_rpc( + ExternalBatchPutTransferEndReq { + items: keys + .iter() + .zip(items.iter()) + .map(|(key, item)| ExternalBatchPutTransferEndItemReq { + key: key.clone(), + len: external_data.value_len, + src_offset: item.src_offset, + target_offset: item + .transfer_target_offset + .unwrap_or(item.target_offset), + peer_id: item.peer_id.clone(), + target_base_addr: if item.peer_id.is_some() { + Some(item.target_base_addr) + } else { + None + }, + put_id: Some(item.put_id), + write_through: external_data.write_through, + lease_id: None, + }) + .collect(), + started_time: external_data.started_time, + transfer_concurrency, + }, + ) + .await + .map(|resp| { + resp.items + .into_iter() + .map(|item| { + rpc_item_error_to_ret_code( + item.error_code, + &item.error_json, + ) + }) + .collect::>() + }) + }; + match result { + Ok(ret_codes) => ret_codes, + Err(err) => vec![kv_error_to_ret_code(&err); keys.len()], + } + } + StagedPutPlanData::Owner(owner_data) => { + let client_kv_api_view = framework_for_commit.client_kv_api_view(); + let inner = client_kv_api_view.client_kv_api().inner(); + let start_items = owner_data + .keys + .iter() + .map(|key| BatchPutStartItemReq { + key: key.clone(), + len: owner_data.value_len, + reject_if_inflight_same_key: false, + reject_if_exist_same_key: false, + write_through: owner_data.write_through, + preferred_sub_cluster: None, + }) + .collect::>(); + let slot_refs = owner_data.slot_lease.slots.clone(); + let slot_size = owner_data.slot_lease.slot_size; + let value_len_usize = match usize::try_from(owner_data.value_len) { + Ok(value) => value, + Err(_) => { + let err = CoreKvError::Api(CoreApiError::InvalidArgument { + detail: + "local_fast_put_commit value_len does not fit into usize" + .to_string(), + }); + let _ = release_staged_put_resources( + inner, + owner_data.key_reservation_ids, + owner_data.slot_lease, + ) + .await; + return ApiResult::new_success(vec![ + kv_error_to_ret_code(&err); + owner_data.keys.len() + ]); + } + }; + let mut memory_infos = Vec::with_capacity(owner_data.keys.len()); + for (key, slot_ref) in owner_data.keys.iter().zip(slot_refs.iter()) { + let memory_info = inner + .build_local_reserve_resident_memory_info( + key, + slot_ref.ptr, + owner_data.value_len as u32, + slot_size, + slot_ref.grant_id, + slot_ref.slot_index, + ) + .await; + inner.install_precommit_local_visible_memory_info( + key, + memory_info.clone(), + ); + memory_infos.push(memory_info); + } + let mut ret_codes = Vec::with_capacity(owner_data.keys.len()); + match inner + .owner_batch_put_start_reserved(start_items, None) + .await + { + Ok(prepared_items) if prepared_items.len() == slot_refs.len() => { + let mut direct_items = Vec::new(); + let mut copy_items = Vec::new(); + for (idx, (reserved_item, slot_ref)) in prepared_items + .into_iter() + .zip(slot_refs.iter().cloned()) + .enumerate() + { + let item = StagedPutCommitItem { + idx, + reserved_item, + slot_ref, + }; + if staged_put_uses_direct_local_commit(&item.reserved_item) { + direct_items.push(item); + } else { + copy_items.push(item); + } + } + + let mut item_results: Vec> = + (0..slot_refs.len()).map(|_| None).collect(); + + if !copy_items.is_empty() { + let reserved_copy_items = copy_items + .iter() + .map(|item| item.reserved_item.clone()) + .collect::>(); + for item in ©_items { + unsafe { + std::ptr::copy_nonoverlapping( + item.slot_ref.ptr as *const u8, + item.reserved_item.src_addr as *mut u8, + value_len_usize, + ); + } + } + match inner + .owner_batch_put_commit_reserved( + reserved_copy_items, + transfer_concurrency, + ) + .await + { + Ok(copy_results) + if copy_results.len() == copy_items.len() => + { + for (item, result) in + copy_items.iter().zip(copy_results.into_iter()) + { + item_results[item.idx] = Some(match result { + Ok(()) => 0, + Err(err) => kv_error_to_ret_code(&err), + }); + } + } + Ok(copy_results) => { + let err = CoreKvError::Api(CoreApiError::Unknown { + detail: format!( + "local_fast_put_commit copy result length mismatch: expected={} got={}", + copy_items.len(), + copy_results.len() + ), + }); + let code = kv_error_to_ret_code(&err); + for item in ©_items { + item_results[item.idx] = Some(code); + } + } + Err(err) => { + let code = kv_error_to_ret_code(&err); + for item in ©_items { + item_results[item.idx] = Some(code); + } + } + } + remove_precommit_local_visible_infos_for_items( + inner, + ©_items, + &memory_infos, + ); + } + + if !direct_items.is_empty() { + let direct_done_req_items = direct_items + .iter() + .map(|item| BatchPutDoneItemReq { + key: item.reserved_item.key.clone(), + put_id: item.reserved_item.put_id, + lease_id: item.reserved_item.lease_id, + committed_slot: Some(PutDoneCommittedSlot { + grant_id: item.slot_ref.grant_id, + slot_index: item.slot_ref.slot_index, + slot_size, + addr: item.slot_ref.ptr, + base_addr: item.slot_ref.base_addr, + len: owner_data.value_len, + }), + publish_local_cache: false, + }) + .collect::>(); + match inner.batch_put_done(direct_done_req_items).await { + Ok(done_resp) + if done_resp.items.len() == direct_items.len() => + { + for (item, done_item) in + direct_items.iter().zip(done_resp.items.into_iter()) + { + let result = + fluxon_kv::rpcresp_kvresult_convert::try_from_code( + done_item.error_code, + done_item.error_json.clone(), + ); + if result.is_ok() { + let promote = inner + .promote_precommit_local_reserve_resident_slot_if_same( + &item.reserved_item.key, + item.reserved_item.put_id, + memory_infos[item.idx].clone(), + ); + if item.reserved_item.enqueue_write_back_append + { + if let Err(err) = inner + .enqueue_write_back_remote_append( + &item.reserved_item.key, + item.reserved_item.put_id, + item.reserved_item + .preferred_sub_cluster + .as_deref(), + ) + .await + { + tracing::warn!( + "local_fast_put_commit write-back remote append enqueue failed after direct local commit: key={} put_id=({},{}) err={}", + item.reserved_item.key, + item.reserved_item.put_id.0, + item.reserved_item.put_id.1, + err + ); + } + } + inner.record_put_locality( + false, + owner_data.value_len, + 0, + ); + item_results[item.idx] = Some(match promote { + Ok(()) => 0, + Err(err) => kv_error_to_ret_code(&err), + }); + } else if let Err(err) = result { + item_results[item.idx] = + Some(kv_error_to_ret_code(&err)); + let _ = inner + .remove_precommit_local_reserve_resident_slot_if_same( + &item.reserved_item.key, + &memory_infos[item.idx], + ); + } + } + } + Ok(done_resp) => { + let err = CoreKvError::Api(CoreApiError::Unknown { + detail: format!( + "local_fast_put_commit direct done response length mismatch: expected={} got={}", + direct_items.len(), + done_resp.items.len() + ), + }); + let code = kv_error_to_ret_code(&err); + for item in &direct_items { + item_results[item.idx] = Some(code); + } + remove_precommit_local_visible_infos_for_items( + inner, + &direct_items, + &memory_infos, + ); + } + Err(err) => { + let code = kv_error_to_ret_code(&err); + for item in &direct_items { + item_results[item.idx] = Some(code); + } + let _ = + revoke_staged_put_items(inner, &direct_items).await; + remove_precommit_local_visible_infos_for_items( + inner, + &direct_items, + &memory_infos, + ); + } + } + } + + for item in item_results { + ret_codes.push(item.unwrap_or_else(|| { + let err = CoreKvError::Api(CoreApiError::Unknown { + detail: "local_fast_put_commit result slot missing" + .to_string(), + }); + kv_error_to_ret_code(&err) + })); + } + } + Ok(prepared_items) => { + let err = CoreKvError::Api(CoreApiError::Unknown { + detail: format!( + "local_fast_put_commit final reserve length mismatch: expected={} got={}", + slot_refs.len(), + prepared_items.len() + ), + }); + let _ = inner.owner_batch_put_abort_reserved(prepared_items).await; + remove_precommit_local_visible_infos( + inner, + &owner_data.keys, + &memory_infos, + ); + ret_codes = vec![kv_error_to_ret_code(&err); owner_data.keys.len()]; + } + Err(err) => { + remove_precommit_local_visible_infos( + inner, + &owner_data.keys, + &memory_infos, + ); + ret_codes = vec![kv_error_to_ret_code(&err); owner_data.keys.len()]; + } + } + if let Err(err) = + release_put_key_reservations_only(inner, owner_data.key_reservation_ids) + .await + { + tracing::warn!( + "local_fast_put_commit key reservation cleanup failed: {}", + err + ); + } + ret_codes + } + }; + cleanup_plan_registry_entry(&plan_registry, plan_ptr_usize); + ApiResult::new_success(ret_codes) + }; + match KvFuture::new(future, runtime_handle, py) { + Ok(v) => ApiResult::new_success(v.into_any()), + Err(e) => ApiResult::new_error(new_general_error( + py, + &format!("Failed to create future: {}", e), + )), + } + } + + local_fast_put_commit_inner(self, plan_ptr, py).into_py_object(py) + } + + #[pyo3(signature = (plan_ptr))] + fn put_abort(&self, plan_ptr: u64, py: Python) -> PyObject { + fn put_abort_inner(client: &KvClient, plan_ptr: u64, py: Python) -> ApiResult { + let plan_ptr_usize = match plan_ptr_u64_to_usize(plan_ptr, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + let framework = match require_kv_framework_api(client, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + let runtime = match client.runtime.as_ref() { + Some(v) => v, + None => { + return ApiResult::new_error(new_general_error( + py, + "Client runtime is missing", + )); + } + }; + let removed = { + let mut guard = client + .plan_registry + .write() + .expect("plan_registry poisoned"); + guard.remove(&plan_ptr_usize) + }; + let Some(FluxonPlanRegistryEntry::Put(plan)) = removed else { + return ApiResult::new_error(new_invalid_argument_error( + py, + "put_abort requires a live put plan_ptr", + )); + }; + let plan_data = { + let mut state_guard = plan.state.lock().expect("put plan state poisoned"); + match std::mem::replace(&mut *state_guard, FluxonPutPlanState::Committing) { + FluxonPutPlanState::Prepared(data) => data, + FluxonPutPlanState::Committing => { + return ApiResult::new_error(new_invalid_argument_error( + py, + "put_abort cannot be used after local_fast_put_commit", + )); + } + } + }; + let abort_result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + match plan_data { + StagedPutPlanData::External(external_data) => { + let external_api_view = framework.external_client_api_view(); + let inner = external_api_view.external_client_api().inner(); + for (key, item) in + external_data.keys.iter().zip(external_data.items.iter()) + { + inner + .external_put_revoke_rpc(ExternalPutRevokeReq { + key: key.clone(), + put_id: Some(item.put_id), + started_time: external_data.started_time, + }) + .await?; + } + Ok::<(), CoreKvError>(()) + } + StagedPutPlanData::Owner(owner_data) => { + let client_kv_api_view = framework.client_kv_api_view(); + let inner = client_kv_api_view.client_kv_api().inner(); + release_staged_put_resources( + inner, + owner_data.key_reservation_ids, + owner_data.slot_lease, + ) + .await + } + } + }) + }) { + Ok(v) => v, + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); + } + }; + match abort_result { + Ok(()) => ApiResult::new_success(0i32.into_py(py)), + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "put_abort failed", + )), + } + } + + put_abort_inner(self, plan_ptr, py).into_py_object(py) + } + + #[pyo3(signature = (keys, concurrency=None))] + fn get_views(&self, keys: Vec, concurrency: Option, py: Python) -> PyObject { + fn get_views_inner( + client: &KvClient, + keys: Vec, + concurrency: Option, + py: Python, + ) -> ApiResult { + if keys.is_empty() { + return ApiResult::new_error(new_invalid_argument_error( + py, + "get_views requires at least one key", + )); + } + if matches!(concurrency, Some(0)) { + return ApiResult::new_error(new_invalid_argument_error( + py, + "batch_concurrency must be > 0", + )); + } + let framework = match require_kv_framework_api(client, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + let runtime = match client.runtime.as_ref() { + Some(v) => v, + None => { + return ApiResult::new_error(new_general_error( + py, + "Client runtime is missing", + )); + } + }; + let keys_for_get = keys.clone(); + let locality_counters = client.locality_counters.clone(); + let result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + let mut holders = Vec::with_capacity(keys_for_get.len()); + let mut value_ptrs = Vec::with_capacity(keys_for_get.len()); + for key in &keys_for_get { + match framework.kv_get(key).await? { + KvGetResult::Owner(Some(holder)) => { + let bytes = holder.bytes().len() as u64; + locality_counters.record_l2_hit(false, bytes); + locality_counters.record_get(false, bytes, 0); + value_ptrs.push(holder.bytes().as_ptr() as u64); + holders.push(StagedGetViewHolder::Owner { _holder: holder }); + } + KvGetResult::External(Some(holder)) => { + let bytes = holder.bytes().len() as u64; + locality_counters.record_l2_hit(true, bytes); + locality_counters.record_get(true, bytes, 0); + value_ptrs.push(holder.bytes().as_ptr() as u64); + holders.push(StagedGetViewHolder::External { _holder: holder }); + } + KvGetResult::Owner(None) | KvGetResult::External(None) => { + return Err(CoreKvError::Api(CoreApiError::KeyNotFound { + key: key.clone(), + })); + } + } + } + Ok::<_, CoreKvError>((value_ptrs, holders)) + }) + }) { + Ok(v) => v, + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); + } + }; + let (value_ptrs, holders) = match result { + Ok(v) => v, + Err(err) => { + return ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "get_views failed", + )); + } + }; + let plan = Arc::new(FluxonGetViewsPlan { + blob: build_plan_blob(&value_ptrs), + _holders: holders, + }); + let plan_ptr = plan_ptr_from_blob(plan.blob.as_ref()); + client + .plan_registry + .write() + .expect("plan_registry poisoned") + .insert(plan_ptr, FluxonPlanRegistryEntry::Get(plan)); + ApiResult::new_success((plan_ptr as u64).into_py(py)) + } + + get_views_inner(self, keys, concurrency, py).into_py_object(py) + } + + #[pyo3(signature = (plan_ptr))] + fn release_views(&self, plan_ptr: u64, py: Python) -> PyObject { + fn release_views_inner( + client: &KvClient, + plan_ptr: u64, + py: Python, + ) -> ApiResult { + let plan_ptr_usize = match plan_ptr_u64_to_usize(plan_ptr, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + let removed = { + let mut guard = client + .plan_registry + .write() + .expect("plan_registry poisoned"); + guard.remove(&plan_ptr_usize) + }; + match removed { + Some(FluxonPlanRegistryEntry::Get(_plan)) => { + ApiResult::new_success(0i32.into_py(py)) + } + Some(FluxonPlanRegistryEntry::Put(_)) => ApiResult::new_error( + new_invalid_argument_error(py, "release_views requires a get-views plan_ptr"), + ), + None => ApiResult::new_error(new_invalid_argument_error( + py, + "release_views requires a live get-views plan_ptr", + )), + } + } + + release_views_inner(self, plan_ptr, py).into_py_object(py) + } + + #[pyo3(signature = (keys, prefix_best_effort=true, atomic_group_lens=None, concurrency=None))] + fn get_start( + &self, + keys: Vec, + prefix_best_effort: bool, + atomic_group_lens: Option>, + concurrency: Option, + py: Python, + ) -> PyObject { + fn get_start_inner( + client: &KvClient, + keys: Vec, + prefix_best_effort: bool, + atomic_group_lens: Option>, + concurrency: Option, + py: Python, + ) -> ApiResult { + if keys.is_empty() { + return ApiResult::new_error(new_invalid_argument_error( + py, + "get_start requires at least one key", + )); + } + let framework = match require_kv_framework_api(client, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + if !framework.is_external_mode() { + return ApiResult::new_error(new_invalid_argument_error( + py, + "get_start is supported only in external-client mode", + )); + } + let runtime = match client.runtime.as_ref() { + Some(v) => v, + None => { + return ApiResult::new_error(new_general_error( + py, + "Client runtime is missing", + )); + } + }; + let batch_concurrency = match concurrency.unwrap_or(DEFAULT_PYO3_BATCH_CONCURRENCY) { + 0 => { + return ApiResult::new_error(new_invalid_argument_error( + py, + "batch_concurrency must be > 0", + )); + } + v => v, + }; + let framework_for_start = framework.clone(); + let started = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + framework_for_start + .external_client_api_view() + .external_client_api() + .inner() + .get_start( + keys, + prefix_best_effort, + atomic_group_lens, + batch_concurrency, + ) + .await + }) + }) { + Ok(v) => v, + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); + } + }; + match started { + Ok(v) => ApiResult::new_success(external_get_start_result_to_py(&v, py)), + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "get_start failed", + )), + } + } + + get_start_inner( + self, + keys, + prefix_best_effort, + atomic_group_lens, + concurrency, + py, + ) + .into_py_object(py) + } + + #[pyo3(signature = (handle))] + fn get_transfer(&self, handle: u64, py: Python) -> PyObject { + fn get_transfer_inner(client: &KvClient, handle: u64, py: Python) -> ApiResult { + let runtime = match client.runtime.as_ref() { + Some(v) => v, + None => { + return ApiResult::new_error(new_general_error( + py, + "Client runtime is missing", + )); + } + }; + let framework = match require_kv_framework_api(client, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + if !framework.is_external_mode() { + return ApiResult::new_error(new_invalid_argument_error( + py, + "get_transfer is supported only in external-client mode", + )); + } + let framework_for_transfer = framework.clone(); + let transfer_results = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + framework_for_transfer + .external_client_api_view() + .external_client_api() + .inner() + .get_transfer(handle) + .await + }) + }) { + Ok(v) => v, + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); + } + }; + let transfer_results = match transfer_results { + Ok(v) => v, + Err(err) => { + return ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "get_transfer failed", + )); + } + }; + let mut value_ptrs = Vec::with_capacity(transfer_results.len()); + let mut holders = Vec::with_capacity(transfer_results.len()); + for (idx, item) in transfer_results.into_iter().enumerate() { + match item { + Ok(Some(holder)) => { + value_ptrs.push(holder.bytes().as_ptr() as u64); + holders.push(StagedGetViewHolder::External { _holder: holder }); + } + Ok(None) => { + return ApiResult::new_error(new_key_not_found_error( + py, + &format!("get_transfer external transfer missed key index {}", idx), + None, + )); + } + Err(err) => { + return ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "get_transfer external transfer item failed", + )); + } + } + } + let view_plan = Arc::new(FluxonGetViewsPlan { + blob: build_plan_blob(&value_ptrs), + _holders: holders, + }); + let plan_ptr = plan_ptr_from_blob(view_plan.blob.as_ref()); + let mut registry_guard = client + .plan_registry + .write() + .expect("plan_registry poisoned"); + registry_guard.insert(plan_ptr, FluxonPlanRegistryEntry::Get(view_plan)); + drop(registry_guard); + ApiResult::new_success((plan_ptr as u64).into_py(py)) + } + + get_transfer_inner(self, handle, py).into_py_object(py) + } + + #[pyo3(signature = (handle))] + fn cancel_get_transfer(&self, handle: u64, py: Python) -> PyObject { + fn cancel_get_transfer_inner( + client: &KvClient, + handle: u64, + py: Python, + ) -> ApiResult { + let runtime = match client.runtime.as_ref() { + Some(v) => v, + None => { + return ApiResult::new_error(new_general_error( + py, + "Client runtime is missing", + )); + } + }; + let framework = match require_kv_framework_api(client, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + if !framework.is_external_mode() { + return ApiResult::new_error(new_invalid_argument_error( + py, + "cancel_get_transfer is supported only in external-client mode", + )); + } + let framework_for_cancel = framework.clone(); + let cancel_res = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + framework_for_cancel + .external_client_api_view() + .external_client_api() + .inner() + .cancel_get_transfer(handle) + .await + }) + }) { + Ok(v) => v, + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); + } + }; + match cancel_res { + Ok(()) => ApiResult::new_success(0i32.into_py(py)), + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "cancel_get_transfer failed", + )), + } + } + + cancel_get_transfer_inner(self, handle, py).into_py_object(py) + } + + /// Allocate a fluxon-kv lease id synchronously. + /// Always allocate a new lease id (no reuse by requested id). + /// Allocate with the provided TTL seconds (must be >= MIN_CLIENT_TTL_SECONDS). + #[pyo3(signature = (ttl_seconds))] + fn allocate_lease(&self, ttl_seconds: u64, py: Python) -> PyObject { + fn allocate_lease_inner( + client: &KvClient, + ttl_seconds: u64, + py: Python, + ) -> ApiResult { + // Enforce minimum TTL at the PyO3 boundary so obvious mistakes fail fast. + if ttl_seconds + < fluxon_kv::master_lease_manager::MasterLeaseManager::MIN_CLIENT_TTL_SECONDS + { + return ApiResult::new_error(new_invalid_argument_error( + py, + &format!( + "allocate_lease(ttl_seconds) requires ttl_seconds >= {} seconds", + fluxon_kv::master_lease_manager::MasterLeaseManager::MIN_CLIENT_TTL_SECONDS, + ), + )); + } + let framework = match require_kv_framework_api(client, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + let runtime = match client.runtime.as_ref() { + Some(v) => v, + None => { + return ApiResult::new_error(new_general_error( + py, + "Client runtime is missing", + )); + } + }; + // Blocking call on the client's runtime; simple and predictable for callers. + let r: Result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + framework + .kv_allocate_lease(ttl_seconds) + .await + .map_err(|e| e.to_string()) + }) + }) { + Ok(v) => v, + Err(e) => Err(format!("runtime bridge failed: {}", e)), + }; + match r { + Ok(id) => ApiResult::new_success(Python::with_gil(|py| id.into_py(py))), + Err(e) => ApiResult::new_error(Python::with_gil(|py| { + new_network_error(py, &format!("Allocate lease failed: {}", e), None) + })), + } + } + allocate_lease_inner(self, ttl_seconds, py).into_py_object(py) + } + + /// Keepalive a lease synchronously. Type must be specified to avoid ambiguity. + /// This uses the lease's existing TTL on the master. + #[pyo3(signature = (lease_id, lease_type))] + fn keepalive_lease( + &self, + lease_id: u64, + lease_type: &Bound<'_, PyAny>, + py: Python, + ) -> PyObject { + fn keepalive_lease_inner( + client: &KvClient, + lease_id: u64, + lease_type: &Bound<'_, PyAny>, + py: Python, + ) -> ApiResult { + // Accept simple enum-like strings: "kvclient" | "etcd" + let lease_type_str = match lease_type.extract::() { + Ok(s) => s.to_ascii_lowercase(), + Err(_) => { + return ApiResult::new_error(new_invalid_argument_error( + py, + "lease_type must be 'kvclient' or 'etcd'", + )); + } + }; + + if lease_type_str != "kvclient" { + return ApiResult::new_error(new_invalid_argument_error( + py, + "keepalive_lease(type=etcd) is not supported in fluxon_pyo3; use fluxon_mq.LeaseManagerHandle for etcd leases", + )); + } + let framework = match require_kv_framework_api(client, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + let runtime = match client.runtime.as_ref() { + Some(v) => v, + None => { + return ApiResult::new_error(new_general_error( + py, + "Client runtime is missing", + )); + } + }; + let r: Result<(), String> = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + framework + .kv_keepalive_lease(lease_id) + .await + .map_err(|e| e.to_string()) + }) + }) { + Ok(v) => v, + Err(e) => Err(format!("runtime bridge failed: {}", e)), + }; + match r { + Ok(_) => { + ApiResult::new_success(Python::with_gil(|py| new_none_success_instance(py))) + } + Err(e) => ApiResult::new_error(Python::with_gil(|py| { + new_network_error(py, &format!("Keepalive lease failed: {}", e), None) + })), + } + } + keepalive_lease_inner(self, lease_id, lease_type, py).into_py_object(py) + } + + /// Put a key-value pair (non-blocking) by encoding a flat dict from raw entries. + /// + /// `ptrs` is a list of `(type_id, dict_key_ptr, dict_key_len, val_u64, val_len, extra)`: + /// - `dict_key_ptr/dict_key_len`: UTF-8 bytes of the dict field key. + /// - For scalar types (bool/int64/float64), `val_u64` stores raw bits and `val_len` is fixed. /// - For bytes-like types (string/bytes), `val_u64` stores a pointer and `val_len` is the byte length. /// - `extra`: reserved for future use. /// @@ -2938,13 +4927,15 @@ impl KvClient { /// on the caller to keep the pointed-to memory alive until the async call completes. /// /// The backend encoding/copy runs on the Rust runtime without holding the Python GIL. - #[pyo3(signature = (key, ptrs, lease_id=None, reject_if_inflight_same_key=false, callback=None))] + #[pyo3(signature = (key, ptrs, lease_id=None, reject_if_inflight_same_key=false, reject_if_exist_same_key=false, write_through=true, callback=None))] fn put( &self, key: &str, ptrs: Vec<(u8, u64, u32, u64, u32, Option)>, lease_id: Option, reject_if_inflight_same_key: bool, + reject_if_exist_same_key: bool, + write_through: bool, callback: Option, py: Python, ) -> PyObject { @@ -2954,6 +4945,8 @@ impl KvClient { ptrs: Vec<(u8, usize, u32, u64, u32, Option)>, lease_id: Option, reject_if_inflight_same_key: bool, + reject_if_exist_same_key: bool, + write_through: bool, callback: Option, py: Python, ) -> ApiResult { @@ -2982,6 +4975,12 @@ impl KvClient { if reject_if_inflight_same_key { o.0.push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfInflightSameKey); } + if reject_if_exist_same_key { + o.0.push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfExistSameKey); + } + if write_through { + o.0.push(fluxon_kv::client_kv_api::PutOptionalArg::WriteThrough); + } o }; @@ -3041,6 +5040,8 @@ impl KvClient { ptrs_owned, lease_id, reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, callback, py, ) @@ -3048,13 +5049,15 @@ impl KvClient { } /// Put a key-value pair and wait for completion before returning. - #[pyo3(signature = (key, ptrs, lease_id=None, reject_if_inflight_same_key=false))] + #[pyo3(signature = (key, ptrs, lease_id=None, reject_if_inflight_same_key=false, reject_if_exist_same_key=false, write_through=true))] fn put_blocking( &self, key: &str, ptrs: Vec<(u8, u64, u32, u64, u32, Option)>, lease_id: Option, reject_if_inflight_same_key: bool, + reject_if_exist_same_key: bool, + write_through: bool, py: Python, ) -> PyObject { fn put_blocking_inner( @@ -3063,6 +5066,8 @@ impl KvClient { ptrs: Vec<(u8, usize, u32, u64, u32, Option)>, lease_id: Option, reject_if_inflight_same_key: bool, + reject_if_exist_same_key: bool, + write_through: bool, py: Python, ) -> ApiResult { if ptrs.len() > (u32::MAX as usize) { @@ -3094,6 +5099,16 @@ impl KvClient { .0 .push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfInflightSameKey); } + if reject_if_exist_same_key { + put_opts + .0 + .push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfExistSameKey); + } + if write_through { + put_opts + .0 + .push(fluxon_kv::client_kv_api::PutOptionalArg::WriteThrough); + } let result = match py.allow_threads(|| { runtime.run_async_from_sync(async { unsafe { framework.kv_put_ptrs(&key, ptrs, put_opts).await } @@ -3137,10 +5152,538 @@ impl KvClient { } put_blocking_inner( self, - key_owned, - ptrs_owned, + key_owned, + ptrs_owned, + lease_id, + reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, + py, + ) + .into_py_object(py) + } + + /// Put a batch of key-value pairs and wait for completion before returning. + /// + /// Each item uses the same flatdict encoding contract as `put_blocking()`. + #[pyo3(signature = (keys, ptrs_groups, lease_id=None, reject_if_inflight_same_key=false, reject_if_exist_same_key=false, write_through=true, concurrency=None))] + fn batch_put_blocking( + &self, + keys: Vec, + ptrs_groups: Vec)>>, + lease_id: Option, + reject_if_inflight_same_key: bool, + reject_if_exist_same_key: bool, + write_through: bool, + concurrency: Option, + py: Python, + ) -> PyObject { + fn batch_put_blocking_inner( + client: &KvClient, + keys: Vec, + ptrs_groups: Vec)>>, + lease_id: Option, + reject_if_inflight_same_key: bool, + reject_if_exist_same_key: bool, + write_through: bool, + concurrency: Option, + py: Python, + ) -> ApiResult { + if keys.len() != ptrs_groups.len() { + return ApiResult::new_error(new_invalid_argument_error( + py, + "batch_put_blocking requires keys and ptrs_groups to have the same length", + )); + } + if keys.is_empty() { + return ApiResult::new_success(Vec::::new().into_py(py)); + } + + let batch_concurrency = match concurrency.unwrap_or(DEFAULT_PYO3_BATCH_CONCURRENCY) { + 0 => { + return ApiResult::new_error(new_invalid_argument_error( + py, + "batch_concurrency must be > 0", + )); + } + v => v, + }; + + let framework = match require_kv_framework_api(client, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + let runtime = match client.runtime.as_ref() { + Some(v) => v, + None => { + return ApiResult::new_error(new_general_error( + py, + "Client runtime is missing", + )); + } + }; + let framework = borrow_stable_owner(&framework); + let keys_for_results = keys; + + let mut put_opts = fluxon_kv::client_kv_api::PutOptionalArgs::new(); + if let Some(id) = lease_id { + put_opts + .0 + .push(fluxon_kv::client_kv_api::PutOptionalArg::LeaseId(id)); + } + if reject_if_inflight_same_key { + put_opts + .0 + .push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfInflightSameKey); + } + if reject_if_exist_same_key { + put_opts + .0 + .push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfExistSameKey); + } + if write_through { + put_opts + .0 + .push(fluxon_kv::client_kv_api::PutOptionalArg::WriteThrough); + } + + if !framework.is_external_mode() { + let framework_for_backend = framework.clone(); + let keys_for_backend = keys_for_results.clone(); + let backend_result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + unsafe { + framework_for_backend + .client_kv_api_view() + .client_kv_api() + .inner() + .batch_put_flat_dict_ptrs( + keys_for_backend, + ptrs_groups, + put_opts, + batch_concurrency, + ) + .await + } + }) + }) { + Ok(v) => v, + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); + } + }; + + return Python::with_gil(|py| match backend_result { + Ok(per_item_results) => { + let out = PyList::empty_bound(py); + for (key, item_result) in keys_for_results + .into_iter() + .zip(per_item_results.into_iter()) + { + let item = match item_result { + Ok(()) => crate::error::new_result_success( + py, + new_none_success_instance(py), + ), + Err(err) => crate::error::new_result_error( + py, + crate::error::py_error_from_kv_error( + py, + &err, + &format!("Put failed for key {}", key), + ), + ), + }; + out.append(item).expect("append batch_put result"); + } + ApiResult::new_success(out.into_py(py)) + } + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "Batch put failed", + )), + }); + } + + let framework_for_backend = framework.clone(); + let keys_for_backend = keys_for_results.clone(); + let backend_result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + unsafe { + framework_for_backend + .external_client_api_view() + .external_client_api() + .inner() + .batch_put_flat_dict_ptrs( + keys_for_backend, + ptrs_groups, + put_opts, + batch_concurrency, + ) + .await + } + }) + }) { + Ok(v) => v, + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); + } + }; + + Python::with_gil(|py| match backend_result { + Ok(per_item_results) => { + let out = PyList::empty_bound(py); + for (key, item_result) in keys_for_results + .into_iter() + .zip(per_item_results.into_iter()) + { + let item = match item_result { + Ok(()) => { + crate::error::new_result_success(py, new_none_success_instance(py)) + } + Err(err) => { + let err_obj = crate::error::py_error_from_kv_error( + py, + &err, + &format!("Put failed for key {}", key), + ); + crate::error::new_result_error(py, err_obj) + } + }; + out.append(item).expect("append batch_put result"); + } + ApiResult::new_success(out.into_py(py)) + } + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "Batch put failed", + )), + }) + } + + let mut ptrs_groups_owned: Vec)>> = + Vec::with_capacity(ptrs_groups.len()); + for ptrs in ptrs_groups.into_iter() { + let mut ptrs_owned: Vec<(u8, usize, u32, u64, u32, Option)> = + Vec::with_capacity(ptrs.len()); + for (type_id, dict_key_ptr, dict_key_len, val_u64, val_len, extra) in ptrs.into_iter() { + let dict_key_ptr_usize: usize = match usize::try_from(dict_key_ptr) { + Ok(v) => v, + Err(_) => { + return ApiResult::::new_error(new_invalid_argument_error( + py, + "dict_key_ptr out of range", + )) + .into_py_object(py); + } + }; + ptrs_owned.push(( + type_id, + dict_key_ptr_usize, + dict_key_len, + val_u64, + val_len, + extra, + )); + } + if ptrs_owned.len() > (u32::MAX as usize) { + return ApiResult::::new_error(new_invalid_argument_error( + py, + "flat dict too large", + )) + .into_py_object(py); + } + ptrs_groups_owned.push(ptrs_owned); + } + + batch_put_blocking_inner( + self, + keys, + ptrs_groups_owned, + lease_id, + reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, + concurrency, + py, + ) + .into_py_object(py) + } + + /// Register a caller-owned host buffer range used by batch zero-copy paths. + #[pyo3(signature = (ptr, len))] + fn register_buffer(&self, ptr: u64, len: u64, py: Python) -> PyObject { + fn register_buffer_inner( + client: &KvClient, + ptr: u64, + len: u64, + py: Python, + ) -> ApiResult { + let ptr_usize = match usize::try_from(ptr) { + Ok(v) => v, + Err(_) => { + return ApiResult::new_error(new_invalid_argument_error( + py, + "register_buffer ptr out of range", + )); + } + }; + let len_usize = match usize::try_from(len) { + Ok(v) => v, + Err(_) => { + return ApiResult::new_error(new_invalid_argument_error( + py, + "register_buffer len out of range", + )); + } + }; + if ptr_usize == 0 && len_usize > 0 { + return ApiResult::new_error(new_invalid_argument_error( + py, + "register_buffer ptr must be non-zero when len > 0", + )); + } + let mut guard = client + .registered_buffers + .write() + .expect("registered_buffers poisoned"); + guard.register(ptr_usize, len_usize); + ApiResult::new_success(0i32.into_py(py)) + } + + register_buffer_inner(self, ptr, len, py).into_py_object(py) + } + + /// Native blocking batch put path for payload pointers. + #[pyo3(signature = (keys, payload_ptrs, payload_sizes, lease_id=None, reject_if_inflight_same_key=false, reject_if_exist_same_key=false, write_through=true))] + fn batch_put_from( + &self, + keys: Vec, + payload_ptrs: Vec, + payload_sizes: Vec, + lease_id: Option, + reject_if_inflight_same_key: bool, + reject_if_exist_same_key: bool, + write_through: bool, + py: Python, + ) -> PyObject { + fn batch_put_from_inner( + client: &KvClient, + keys: Vec, + payload_ptrs: Vec, + payload_sizes: Vec, + lease_id: Option, + reject_if_inflight_same_key: bool, + reject_if_exist_same_key: bool, + write_through: bool, + py: Python, + ) -> ApiResult { + if keys.len() != payload_ptrs.len() || keys.len() != payload_sizes.len() { + return ApiResult::new_error(new_invalid_argument_error( + py, + "batch_put_from requires keys, payload_ptrs, and payload_sizes to have the same length", + )); + } + if keys.is_empty() { + return ApiResult::new_success(Vec::::new().into_py(py)); + } + + let framework = match require_kv_framework_api(client, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + let runtime = match client.runtime.as_ref() { + Some(v) => v, + None => { + return ApiResult::new_error(new_general_error( + py, + "Client runtime is missing", + )); + } + }; + + let registered = client + .registered_buffers + .read() + .expect("registered_buffers poisoned"); + let mut payload_ptrs_usize = Vec::with_capacity(payload_ptrs.len()); + for (&ptr, &size_u32) in payload_ptrs.iter().zip(payload_sizes.iter()) { + let ptr_usize = match usize::try_from(ptr) { + Ok(v) => v, + Err(_) => { + return ApiResult::new_error(new_invalid_argument_error( + py, + "batch_put_from payload_ptr out of range", + )); + } + }; + let size = size_u32 as usize; + if ptr_usize == 0 && size > 0 { + return ApiResult::new_error(new_invalid_argument_error( + py, + "batch_put_from payload_ptr must be non-zero when payload_size > 0", + )); + } + if !registered.ranges.is_empty() && !registered.contains(ptr_usize, size) { + return ApiResult::new_error(new_invalid_argument_error( + py, + "batch_put_from payload range is not inside any registered buffer", + )); + } + payload_ptrs_usize.push(ptr_usize); + } + drop(registered); + + let framework = borrow_stable_owner(&framework); + let mut put_opts = fluxon_kv::client_kv_api::PutOptionalArgs::new(); + if let Some(id) = lease_id { + put_opts + .0 + .push(fluxon_kv::client_kv_api::PutOptionalArg::LeaseId(id)); + } + if reject_if_inflight_same_key { + put_opts + .0 + .push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfInflightSameKey); + } + if reject_if_exist_same_key { + put_opts + .0 + .push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfExistSameKey); + } + if write_through { + put_opts + .0 + .push(fluxon_kv::client_kv_api::PutOptionalArg::WriteThrough); + } + + let keys_for_backend = keys.clone(); + let ptrs_groups = keys_for_backend + .iter() + .zip(payload_ptrs_usize.iter()) + .zip(payload_sizes.iter()) + .map(|((_key, payload_ptr), payload_size)| { + vec![( + 5u8, + b"payload".as_ptr() as usize, + 7u32, + *payload_ptr as u64, + *payload_size, + None, + )] + }) + .collect::>(); + let batch_concurrency = DEFAULT_PYO3_BATCH_CONCURRENCY; + + if !framework.is_external_mode() { + let framework_for_backend = framework.clone(); + let backend_result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + unsafe { + framework_for_backend + .client_kv_api_view() + .client_kv_api() + .inner() + .batch_put_flat_dict_ptrs( + keys_for_backend, + ptrs_groups, + put_opts, + batch_concurrency, + ) + .await + } + }) + }) { + Ok(v) => v, + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); + } + }; + return match backend_result { + Ok(per_item_results) => ApiResult::new_success( + per_item_results + .into_iter() + .map(|item| match item { + Ok(()) => 0, + Err(err) => kv_error_to_ret_code(&err), + }) + .collect::>() + .into_py(py), + ), + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "Batch put failed", + )), + }; + } + + let framework_for_backend = framework.clone(); + let backend_result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + unsafe { + framework_for_backend + .external_client_api_view() + .external_client_api() + .inner() + .batch_put_flat_dict_ptrs( + keys_for_backend, + ptrs_groups, + put_opts, + batch_concurrency, + ) + .await + } + }) + }) { + Ok(v) => v, + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); + } + }; + + match backend_result { + Ok(per_item_results) => ApiResult::new_success( + per_item_results + .into_iter() + .map(|item| match item { + Ok(()) => 0, + Err(err) => kv_error_to_ret_code(&err), + }) + .collect::>() + .into_py(py), + ), + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "Batch put failed", + )), + } + } + + batch_put_from_inner( + self, + keys, + payload_ptrs, + payload_sizes, lease_id, reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, py, ) .into_py_object(py) @@ -3322,6 +5865,195 @@ impl KvClient { get_blocking_inner(self, key, py).into_py_object(py) } + /// Get a batch of keys and wait for completion before returning. + /// + /// Returns a Python list of per-item `Result` objects, aligned with + /// `get_blocking()` semantics. + #[pyo3(signature = (keys, concurrency=None))] + fn batch_get_blocking( + &self, + keys: Vec, + concurrency: Option, + py: Python, + ) -> PyObject { + fn batch_get_blocking_inner( + client: &KvClient, + keys: Vec, + concurrency: Option, + py: Python, + ) -> ApiResult { + if keys.is_empty() { + return ApiResult::new_success(Vec::::new().into_py(py)); + } + + let batch_concurrency = match concurrency.unwrap_or(DEFAULT_PYO3_BATCH_CONCURRENCY) { + 0 => { + return ApiResult::new_error(new_invalid_argument_error( + py, + "batch_concurrency must be > 0", + )); + } + v => v, + }; + + let framework = match require_kv_framework_api(client, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + let runtime = match client.runtime.as_ref() { + Some(v) => v, + None => { + return ApiResult::new_error(new_general_error( + py, + "Client runtime is missing", + )); + } + }; + let framework = borrow_stable_owner(&framework); + let keys_for_results = keys; + + if !framework.is_external_mode() { + let framework_for_backend = framework.clone(); + let keys_for_backend = keys_for_results.clone(); + let backend_result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + framework_for_backend + .client_kv_api_view() + .client_kv_api() + .inner() + .batch_get(keys_for_backend, batch_concurrency) + .await + }) + }) { + Ok(v) => v, + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); + } + }; + + return Python::with_gil(|py| match backend_result { + Ok(per_item_results) => { + let out = PyList::empty_bound(py); + for (key, item_result) in keys_for_results + .into_iter() + .zip(per_item_results.into_iter()) + { + let item = match item_result { + Ok(Some((rust_holder, _remote_info))) => { + let mem_holder = MemHolder::new(rust_holder); + match mem_holder.into_py_mem_holder(py) { + ApiResult::Success(py_holder) => { + crate::error::new_result_success(py, py_holder) + } + ApiResult::Error(err) => { + crate::error::new_result_error(py, err) + } + } + } + Ok(None) => crate::error::new_result_error( + py, + new_key_not_found_error( + py, + &format!("Key not found: {}", key), + Some(&key), + ), + ), + Err(err) => crate::error::new_result_error( + py, + crate::error::py_error_from_kv_error( + py, + &err, + &format!("Get failed for key {}", key), + ), + ), + }; + out.append(item).expect("append batch_get result"); + } + ApiResult::new_success(out.into_py(py)) + } + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "Batch get failed", + )), + }); + } + + let framework_for_backend = framework.clone(); + let keys_for_backend = keys_for_results.clone(); + let backend_result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + framework_for_backend + .external_client_api_view() + .external_client_api() + .inner() + .batch_get(keys_for_backend, batch_concurrency) + .await + }) + }) { + Ok(v) => v, + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); + } + }; + + Python::with_gil(|py| match backend_result { + Ok(per_item_results) => { + let out = PyList::empty_bound(py); + for (key, item_result) in keys_for_results + .into_iter() + .zip(per_item_results.into_iter()) + { + let item = match item_result { + Ok(Some(external_mem_holder)) => { + let pyo3_external = ExternalMemHolder::new(external_mem_holder); + match pyo3_external.into_py_mem_holder(py) { + ApiResult::Success(py_holder) => { + crate::error::new_result_success(py, py_holder) + } + ApiResult::Error(err) => { + crate::error::new_result_error(py, err) + } + } + } + Ok(None) => crate::error::new_result_error( + py, + new_key_not_found_error( + py, + &format!("Key not found: {}", key), + Some(&key), + ), + ), + Err(err) => crate::error::new_result_error( + py, + crate::error::py_error_from_kv_error( + py, + &err, + &format!("Get failed for key {}", key), + ), + ), + }; + out.append(item).expect("append batch_get result"); + } + ApiResult::new_success(out.into_py(py)) + } + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "Batch get failed", + )), + }) + } + + batch_get_blocking_inner(self, keys, concurrency, py).into_py_object(py) + } + /// Delete a key (synchronous from Python; only put/get use KvFuture) #[pyo3(signature = (key, callback=None))] fn delete(&self, key: String, callback: Option, py: Python) -> PyObject { @@ -3416,9 +6148,84 @@ impl KvClient { metrics_snapshot_inner(self, py).into_py_object(py) } + /// Async snapshot for Fluxon KV locality and IO counters. + fn observability_snapshot_async(&self, py: Python) -> PyObject { + fn observability_snapshot_async_inner( + client: &KvClient, + py: Python, + ) -> ApiResult { + let _framework = match require_kv_framework_api(client, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + let runtime_handle = match client.runtime.as_ref() { + Some(v) => v.handle().clone(), + None => { + return ApiResult::new_error(new_general_error( + py, + "Client runtime is missing", + )); + } + }; + let locality_counters = client.locality_counters.clone(); + let future = async move { + let metrics = locality_counters.snapshot(); + Python::with_gil(|py| { + let out = PyDict::new_bound(py); + out.set_item("l2_local_hit_pages", metrics.l2_local_hit_pages) + .expect("set l2_local_hit_pages"); + out.set_item("l2_local_hit_bytes", metrics.l2_local_hit_bytes) + .expect("set l2_local_hit_bytes"); + out.set_item("l2_remote_hit_pages", metrics.l2_remote_hit_pages) + .expect("set l2_remote_hit_pages"); + out.set_item("l2_remote_hit_bytes", metrics.l2_remote_hit_bytes) + .expect("set l2_remote_hit_bytes"); + let io = PyDict::new_bound(py); + for (key, item) in [ + ("put_local", metrics.put_local.clone()), + ("put_remote", metrics.put_remote.clone()), + ("get_local", metrics.get_local.clone()), + ("get_remote", metrics.get_remote.clone()), + ] { + let entry = PyDict::new_bound(py); + entry + .set_item("op_count", item.op_count) + .expect("set op_count"); + entry.set_item("bytes", item.bytes).expect("set bytes"); + entry + .set_item("transfer_us", item.transfer_us) + .expect("set transfer_us"); + entry + .set_item("bandwidth_gbps", item.bandwidth_gbps()) + .expect("set bandwidth_gbps"); + io.set_item(key, entry).expect("set io entry"); + } + out.set_item("io", io).expect("set io"); + ApiResult::new_success(out.into_py(py)) + }) + }; + match KvFuture::new(future, runtime_handle, py) { + Ok(py_future) => ApiResult::new_success(py_future.into_any()), + Err(e) => ApiResult::new_error(new_general_error( + py, + &format!("Failed to create future: {}", e), + )), + } + } + + observability_snapshot_async_inner(self, py).into_py_object(py) + } + /// Check if a key exists (synchronous; returns bool wrapped in Result) - fn is_exist(&self, key: String, py: Python) -> PyObject { - fn is_exist_inner(client: &KvClient, key: String, py: Python) -> ApiResult { + #[pyo3(signature = (key, allow_local_snapshot=false))] + fn is_exist(&self, key: String, allow_local_snapshot: bool, py: Python) -> PyObject { + fn is_exist_inner( + client: &KvClient, + key: String, + allow_local_snapshot: bool, + py: Python, + ) -> ApiResult { + let _ = allow_local_snapshot; let framework = match require_kv_framework_api(client, py) { Ok(v) => v, Err(e) => return ApiResult::new_error(e), @@ -3450,7 +6257,298 @@ impl KvClient { }), } } - is_exist_inner(self, key, py).into_py_object(py) + is_exist_inner(self, key, allow_local_snapshot, py).into_py_object(py) + } + + /// Native blocking batch get path writing payload bytes into caller-provided pointers. + #[pyo3(signature = (keys, payload_ptrs, payload_capacities))] + fn batch_get_into( + &self, + keys: Vec, + payload_ptrs: Vec, + payload_capacities: Vec, + py: Python, + ) -> PyObject { + fn batch_get_into_inner( + client: &KvClient, + keys: Vec, + payload_ptrs: Vec, + payload_capacities: Vec, + py: Python, + ) -> ApiResult { + if keys.len() != payload_ptrs.len() || keys.len() != payload_capacities.len() { + return ApiResult::new_error(new_invalid_argument_error( + py, + "batch_get_into requires keys, payload_ptrs, and payload_capacities to have the same length", + )); + } + if keys.is_empty() { + return ApiResult::new_success(Vec::::new().into_py(py)); + } + + let framework = match require_kv_framework_api(client, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + let runtime = match client.runtime.as_ref() { + Some(v) => v, + None => { + return ApiResult::new_error(new_general_error( + py, + "Client runtime is missing", + )); + } + }; + + let registered = client + .registered_buffers + .read() + .expect("registered_buffers poisoned"); + let mut payload_ptrs_usize = Vec::with_capacity(payload_ptrs.len()); + for (&ptr, &cap_u32) in payload_ptrs.iter().zip(payload_capacities.iter()) { + let ptr_usize = match usize::try_from(ptr) { + Ok(v) => v, + Err(_) => { + return ApiResult::new_error(new_invalid_argument_error( + py, + "batch_get_into payload_ptr out of range", + )); + } + }; + if ptr_usize == 0 && cap_u32 > 0 { + return ApiResult::new_error(new_invalid_argument_error( + py, + "batch_get_into payload_ptr must be non-zero when payload_capacity > 0", + )); + } + let cap = cap_u32 as usize; + if !registered.ranges.is_empty() && !registered.contains(ptr_usize, cap) { + return ApiResult::new_error(new_invalid_argument_error( + py, + "batch_get_into destination range is not inside any registered buffer", + )); + } + payload_ptrs_usize.push(ptr_usize); + } + drop(registered); + + let framework = borrow_stable_owner(&framework); + let batch_concurrency = DEFAULT_PYO3_BATCH_CONCURRENCY; + + if !framework.is_external_mode() { + let framework_for_backend = framework.clone(); + let keys_for_backend = keys.clone(); + let backend_result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + framework_for_backend + .client_kv_api_view() + .client_kv_api() + .inner() + .batch_get(keys_for_backend, batch_concurrency) + .await + }) + }) { + Ok(v) => v, + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); + } + }; + + return match backend_result { + Ok(per_item_results) => { + let mut out = Vec::with_capacity(per_item_results.len()); + for (((key, payload_ptr), payload_capacity), item_result) in keys + .into_iter() + .zip(payload_ptrs_usize.into_iter()) + .zip(payload_capacities.into_iter()) + .zip(per_item_results.into_iter()) + { + let code = match item_result { + Ok(Some((holder, _remote_info))) => { + let holder_result = KvGetResult::Owner(Some(holder)); + let payload = + match payload_slice_from_get_result(&key, &holder_result) { + Ok(payload) => payload, + Err(err) => { + out.push(kv_error_to_ret_code(&err)); + continue; + } + }; + if payload.len() > payload_capacity as usize { + -(4003i32) + } else { + if !payload.is_empty() { + unsafe { + std::ptr::copy_nonoverlapping( + payload.as_ptr(), + payload_ptr as *mut u8, + payload.len(), + ); + } + } + payload.len() as i32 + } + } + Ok(None) => kv_error_to_ret_code(&CoreKvError::Api( + CoreApiError::KeyNotFound { key }, + )), + Err(err) => kv_error_to_ret_code(&err), + }; + out.push(code); + } + ApiResult::new_success(out.into_py(py)) + } + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "Batch get failed", + )), + }; + } + + let framework_for_backend = framework.clone(); + let keys_for_backend = keys.clone(); + let backend_result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + framework_for_backend + .external_client_api_view() + .external_client_api() + .inner() + .batch_get(keys_for_backend, batch_concurrency) + .await + }) + }) { + Ok(v) => v, + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); + } + }; + + match backend_result { + Ok(per_item_results) => { + let mut out = Vec::with_capacity(per_item_results.len()); + for (((key, payload_ptr), payload_capacity), item_result) in keys + .into_iter() + .zip(payload_ptrs_usize.into_iter()) + .zip(payload_capacities.into_iter()) + .zip(per_item_results.into_iter()) + { + let code = + match item_result { + Ok(Some(holder)) => { + let holder_result = KvGetResult::External(Some(holder)); + let payload = + match payload_slice_from_get_result(&key, &holder_result) { + Ok(payload) => payload, + Err(err) => { + out.push(kv_error_to_ret_code(&err)); + continue; + } + }; + if payload.len() > payload_capacity as usize { + -(4003i32) + } else { + if !payload.is_empty() { + unsafe { + std::ptr::copy_nonoverlapping( + payload.as_ptr(), + payload_ptr as *mut u8, + payload.len(), + ); + } + } + payload.len() as i32 + } + } + Ok(None) => kv_error_to_ret_code(&CoreKvError::Api( + CoreApiError::KeyNotFound { key }, + )), + Err(err) => kv_error_to_ret_code(&err), + }; + out.push(code); + } + ApiResult::new_success(out.into_py(py)) + } + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "Batch get failed", + )), + } + } + + batch_get_into_inner(self, keys, payload_ptrs, payload_capacities, py).into_py_object(py) + } + + /// Native blocking batch existence check. + #[pyo3(signature = (keys, allow_local_snapshot=false))] + fn batch_is_exist( + &self, + keys: Vec, + allow_local_snapshot: bool, + py: Python, + ) -> PyObject { + fn batch_is_exist_inner( + client: &KvClient, + keys: Vec, + allow_local_snapshot: bool, + py: Python, + ) -> ApiResult { + if keys.is_empty() { + return ApiResult::new_success(Vec::::new().into_py(py)); + } + let framework = match require_kv_framework_api(client, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + let runtime = match client.runtime.as_ref() { + Some(v) => v, + None => { + return ApiResult::new_error(new_general_error( + py, + "Client runtime is missing", + )); + } + }; + let framework = borrow_stable_owner(&framework); + let result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + framework + .kv_batch_is_exist(keys, allow_local_snapshot) + .await + }) + }) { + Ok(v) => v, + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); + } + }; + match result { + Ok(exists_list) => { + let ints = exists_list + .into_iter() + .map(|exists| if exists { 1i32 } else { 0i32 }) + .collect::>(); + ApiResult::new_success(ints.into_py(py)) + } + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "Batch existence check failed", + )), + } + } + + batch_is_exist_inner(self, keys, allow_local_snapshot, py).into_py_object(py) } /// Count number of keys whose name starts with the given prefix. @@ -4164,6 +7262,7 @@ fn fluxon_pyo3(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_function(wrap_pyfunction!(run_master_blocking, m)?)?; + m.add_function(wrap_pyfunction!(decode_flat_dict_payload, m)?)?; m.add_function(wrap_pyfunction!(monitor_render_cli, m)?)?; m.add_function(wrap_pyfunction!(monitor_render_web, m)?)?; m.add_function(wrap_pyfunction!(fluxon_ops_controller_blocking, m)?)?; @@ -4309,17 +7408,14 @@ mod tests { discovery.entries[0].provider_path, libs_dir.join("libmlx5-rdmav34.so") ); - assert!( - discovery.outcomes.iter().any(|outcome| { - outcome.contains("config_ok:") && outcome.contains("driver=mlx5") - }) - ); - assert!( - discovery - .outcomes - .iter() - .any(|outcome| outcome.contains("config_parse_fail:")) - ); + assert!(discovery + .outcomes + .iter() + .any(|outcome| { outcome.contains("config_ok:") && outcome.contains("driver=mlx5") })); + assert!(discovery + .outcomes + .iter() + .any(|outcome| outcome.contains("config_parse_fail:"))); } #[test] diff --git a/fluxon_rs/fluxon_util/src/dev_config.rs b/fluxon_rs/fluxon_util/src/dev_config.rs index c860910..d3f5953 100644 --- a/fluxon_rs/fluxon_util/src/dev_config.rs +++ b/fluxon_rs/fluxon_util/src/dev_config.rs @@ -1,4 +1,4 @@ -use anyhow::{anyhow, Context, Result}; +use anyhow::{Context, Result, anyhow}; use serde_yaml::Value; use std::fs; use std::path::{Path, PathBuf}; diff --git a/fluxon_rs/fluxon_util/src/lib.rs b/fluxon_rs/fluxon_util/src/lib.rs index a85aed0..cde6dc7 100644 --- a/fluxon_rs/fluxon_util/src/lib.rs +++ b/fluxon_rs/fluxon_util/src/lib.rs @@ -37,10 +37,9 @@ pub mod limitrate; pub mod pyo3; // Re-export for stable public API: existing call sites can keep using `fluxon_util::init_log`. pub use log::{ - current_daily_sharded_log_path, current_log_file_path, daily_sharded_log_path, - display_runtime_log_path, init_log, init_log_test, init_log_with_extra_layer, - latest_existing_daily_sharded_log_path, resolve_readable_log_path, - DEFAULT_DAILY_LOG_RETENTION_DAYS, + DEFAULT_DAILY_LOG_RETENTION_DAYS, current_daily_sharded_log_path, current_log_file_path, + daily_sharded_log_path, display_runtime_log_path, init_log, init_log_test, + init_log_with_extra_layer, latest_existing_daily_sharded_log_path, resolve_readable_log_path, }; #[cfg(test)] mod test_util_test; @@ -251,7 +250,12 @@ mod tests { ); assert_logged_text( &active_log_path, - &["debug message", "info message", "warning message", "error message"], + &[ + "debug message", + "info message", + "warning message", + "error message", + ], ); } } diff --git a/fluxon_rs/fluxon_util/src/log.rs b/fluxon_rs/fluxon_util/src/log.rs index fc6066f..4db4ae4 100644 --- a/fluxon_rs/fluxon_util/src/log.rs +++ b/fluxon_rs/fluxon_util/src/log.rs @@ -61,9 +61,7 @@ fn read_test_log_shard_window_config() -> anyhow::Result 0"); @@ -85,7 +83,9 @@ fn read_test_log_shard_window_config() -> anyhow::Result) -> anyhow::Result { +fn resolve_shard_date_from_datetime( + now: chrono::DateTime, +) -> anyhow::Result { let Some(config) = read_test_log_shard_window_config()? else { return Ok(now.date_naive()); }; @@ -99,8 +99,8 @@ fn resolve_shard_date_from_datetime(now: chrono::DateTime) -> anyho ); } let bucket_index = delta_seconds / config.window_seconds; - let base_date = chrono::NaiveDate::from_ymd_opt(2026, 1, 1) - .expect("valid hard-coded synthetic base date"); + let base_date = + chrono::NaiveDate::from_ymd_opt(2026, 1, 1).expect("valid hard-coded synthetic base date"); Ok(base_date + chrono::Days::new(bucket_index as u64)) } @@ -108,10 +108,7 @@ fn current_shard_date() -> anyhow::Result { resolve_shard_date_from_datetime(chrono::Utc::now()) } -fn cleanup_old_daily_sharded_logs( - base_path: &Path, - retention_days: usize, -) -> anyhow::Result<()> { +fn cleanup_old_daily_sharded_logs(base_path: &Path, retention_days: usize) -> anyhow::Result<()> { let parent = match base_path.parent() { Some(parent) => parent, None => return Ok(()), @@ -124,7 +121,8 @@ fn cleanup_old_daily_sharded_logs( return Ok(()); }; fs::create_dir_all(parent)?; - let keep_since = current_shard_date()? - chrono::Days::new(retention_days.saturating_sub(1) as u64); + let keep_since = + current_shard_date()? - chrono::Days::new(retention_days.saturating_sub(1) as u64); let prefix = format!("{stem}."); for entry in std::fs::read_dir(parent)? { let entry = entry?; @@ -180,10 +178,7 @@ impl DailyShardedFileWriter { current_daily_sharded_log_path(&self.base_path) } - fn rotate_if_needed( - &self, - state: &mut DailyShardedFileWriterState, - ) -> io::Result<()> { + fn rotate_if_needed(&self, state: &mut DailyShardedFileWriterState) -> io::Result<()> { let next_path = self .current_path() .map_err(|err| io::Error::new(io::ErrorKind::Other, err.to_string()))?; @@ -314,20 +309,19 @@ pub fn daily_sharded_log_path( base_path: &Path, date: chrono::NaiveDate, ) -> anyhow::Result { - let file_name = base_path.file_name().and_then(|v| v.to_str()).ok_or_else(|| { - anyhow::anyhow!( - "log path must end with a valid utf-8 filename: {}", - base_path.display() - ) - })?; + let file_name = base_path + .file_name() + .and_then(|v| v.to_str()) + .ok_or_else(|| { + anyhow::anyhow!( + "log path must end with a valid utf-8 filename: {}", + base_path.display() + ) + })?; let stem = file_name .strip_suffix(".log") .ok_or_else(|| anyhow::anyhow!("log path must end with .log: {}", base_path.display()))?; - Ok(base_path.with_file_name(format!( - "{}.{}.log", - stem, - date.format("%Y-%m-%d") - ))) + Ok(base_path.with_file_name(format!("{}.{}.log", stem, date.format("%Y-%m-%d")))) } pub fn current_daily_sharded_log_path(base_path: &Path) -> anyhow::Result { diff --git a/fluxon_rs/fluxon_util/tests/log_mgmt.rs b/fluxon_rs/fluxon_util/tests/log_mgmt.rs index 431c5fc..f459337 100644 --- a/fluxon_rs/fluxon_util/tests/log_mgmt.rs +++ b/fluxon_rs/fluxon_util/tests/log_mgmt.rs @@ -59,7 +59,10 @@ fn kv_log_shards_roll_and_cleanup_with_test_window() { .expect("unix epoch") .as_secs() as i64; let _window_guard = EnvVarGuard::set(TEST_LOG_SHARD_WINDOW_SECONDS_ENV, "10"); - let _anchor_guard = EnvVarGuard::set(TEST_LOG_SHARD_ANCHOR_UNIX_SECONDS_ENV, (now - 2).to_string()); + let _anchor_guard = EnvVarGuard::set( + TEST_LOG_SHARD_ANCHOR_UNIX_SECONDS_ENV, + (now - 2).to_string(), + ); fluxon_util::init_log(log_path, instance_key); tracing::info!(target: "fluxon_util", "[kv-log-mgmt][phase=before] ts={}", now); @@ -115,7 +118,8 @@ fn resolve_readable_log_path_ignores_plain_base_log_when_daily_shards_exist() { let shard_path = temp_dir.path().join("startup.2026-06-21.log"); fs::write(&shard_path, "shard\n").expect("write shard log"); - let resolved = fluxon_util::resolve_readable_log_path(&base_path).expect("resolve readable log path"); + let resolved = + fluxon_util::resolve_readable_log_path(&base_path).expect("resolve readable log path"); assert_eq!(resolved, shard_path); } @@ -128,7 +132,7 @@ fn latest_existing_daily_sharded_log_path_skips_invalid_candidates() { fs::write(&invalid_shard_path, "invalid\n").expect("write invalid shard"); fs::write(&valid_shard_path, "valid\n").expect("write valid shard"); - let resolved = - fluxon_util::latest_existing_daily_sharded_log_path(&base_path).expect("resolve latest shard"); + let resolved = fluxon_util::latest_existing_daily_sharded_log_path(&base_path) + .expect("resolve latest shard"); assert_eq!(resolved, valid_shard_path); } From 6235d414faa936713e1b82d78cfc4124eaf3fb97 Mon Sep 17 00:00:00 2001 From: zTz01 <1773266173@qq.com> Date: Thu, 9 Jul 2026 19:07:56 +0800 Subject: [PATCH 02/10] async put_done --- ...06\346\210\220\350\256\276\350\256\241.md" | 215 ++- .../src/client_kv_api/external_api.rs | 1268 +++++++++-------- fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs | 159 ++- .../fluxon_kv/src/client_kv_api/msg_pack.rs | 8 +- fluxon_rs/fluxon_kv/src/client_kv_api/put.rs | 780 +++++----- .../fluxon_kv/src/client_seg_pool/mod.rs | 6 +- fluxon_rs/fluxon_kv/src/config.rs | 281 +++- .../external_client_test.rs | 4 +- .../fluxon_kv/src/external_client_api/mod.rs | 40 +- fluxon_rs/fluxon_kv/src/kv_test.rs | 23 +- fluxon_rs/fluxon_kv/src/kvcore_test_lib.rs | 3 +- fluxon_rs/fluxon_kv/src/lib.rs | 17 +- .../fluxon_kv/src/master_kv_router/delete.rs | 4 +- .../fluxon_kv/src/master_kv_router/get.rs | 10 +- .../fluxon_kv/src/master_kv_router/mod.rs | 61 +- .../src/master_kv_router/msg_pack.rs | 14 +- .../src/master_kv_router/placement.rs | 717 +++++++++- .../fluxon_kv/src/master_kv_router/put.rs | 652 ++++++--- .../lease_manager_test.rs | 70 +- .../fluxon_kv/src/memholder/memholder_test.rs | 3 +- fluxon_rs/fluxon_pyo3/src/error.rs | 2 +- fluxon_rs/fluxon_pyo3/src/lib.rs | 496 ++----- 22 files changed, 3034 insertions(+), 1799 deletions(-) diff --git "a/fluxon_doc_cn/design/sglang_fluxon_kv\351\233\206\346\210\220\350\256\276\350\256\241.md" "b/fluxon_doc_cn/design/sglang_fluxon_kv\351\233\206\346\210\220\350\256\276\350\256\241.md" index 8a0dc6d..3b0c1c6 100644 --- "a/fluxon_doc_cn/design/sglang_fluxon_kv\351\233\206\346\210\220\350\256\276\350\256\241.md" +++ "b/fluxon_doc_cn/design/sglang_fluxon_kv\351\233\206\346\210\220\350\256\276\350\256\241.md" @@ -1,17 +1,71 @@ # SGLang Fluxon KV 集成设计 -## 设计目标 +## 背景与目标 本文说明开源仓库中 SGLang HiCache 接入 Fluxon KV 的 hostless 实现设计,聚焦接口契约、状态归属和生命周期边界。本文不是通用 `FlatDict` KV API 的完整说明。 +稳定结论:本集成的目标是把 SGLang HiCache + Mooncake 形态下分裂的 L2/L3 KV Cache 收敛到 Fluxon 统一管理的本机/远端 KV 层。Fluxon 需要同时具备两类能力:一类是 `key -> value` 的分布式缓存、路由、版本和生命周期能力;另一类是 HiCache L2 所依赖的 hostless 数据面能力,也就是让 SGLang native kernel 直接在 GPU KV cache 和 Fluxon 管理的 host value memory 之间搬运数据。 + +关键 insights 先集中列在这里,后文围绕这些结论展开接口、状态和时序设计: + +- **L2/L3 分离是工程解耦选择,但会带来资源冗余和 L2 全局不可见** + - 因果链:HiCache L2 留在推理框架内,Mooncake L3 作为外部 backend,能降低接入复杂度;代价是同一类 KV page 被两套系统分别索引、驻留、驱逐和释放。同一批 page 可能同时驻留在本机 L2 和外部 L3,且其它 worker 或其它节点不能通过统一 route 判断本机 L2 page 是否可复用。 + - 本设计落点:把逻辑 L2/L3 收敛到 Fluxon local side / remote side,用一套 owner、holder、route、commit/release 管理同一批 page。page key 在 Fluxon master/owner 中形成统一路由;只有 commit future 成功后,跨 worker 和跨节点复用才把该 page 视为可见。 +- **同机 worker 缺少共享内存快路径** + - 因果链:多个 SGLang worker 容易各自维护后端 segment、本机缓存副本和独立 pin/release 状态;同机交接也可能绕行后端协议。 + - 本设计落点:同机 worker attach 到同一个 Fluxon owner shared segment,通过 holder 引用管理本机可见 value 的生命周期。 +- **统一 L2/L3 需要分布式 KV 能力** + - 因果链:Mooncake 这类分布式 KV backend 的目标仍然成立:KV Cache 需要利用远端 CPU 内存,尤其是无推理负载机器上的闲置内存,作为 shared backing。只用本进程数组或本机缓存,无法统一索引、放置和复用这些远端闲置内存。 + - 本设计落点:Fluxon 保留 `key -> value` route、inflight 判重、commit future 和 local/remote 放置能力,把远端闲置 CPU 内存纳入 remote side,同时把本机 L2 纳入同一套 owner/holder 生命周期。 +- **保留 L2 低延迟需要 kernel 直连内存** + - 因果链:普通 `put/get(key, bytes)` KV 接口需要在 CPU 侧 materialize payload、查地址、组织拷贝或拆装 bytes;长上下文下如果再按 page 和 layer 展开,会形成 `page_count * layer_count` 级别的 CPU 控制面循环。 + - 本设计落点:Fluxon 只构造 `plan_ptr(value_ptrs)`,SGLang native kernel 直接在 GPU KV cache 和 Fluxon host value memory 之间搬运 bytes。 +- **KV Cache 适合 write-back 最终一致性,最终目标是极致化这条路径** + - 因果链:page value 按不可变对象使用,缓存副本可丢失;写回失败只会降低命中率,不改变推理正确性。因此优化重点应放在缩短 write-back 和 restore 的热路径,而不是把每次缓存写回做成强同步持久写。 + - 本设计落点:native write 完成后异步推进 route commit,`KvFuture` 成功前不作为跨 worker / 跨节点 shared backing;写入侧减少同步等待、CPU 循环和中间 bytes 包装,读取侧先规划 prefix,再只 materialize 可恢复前缀。 +- **需要适配 SGLang KVCache 特化接口** + - 因果链:SGLang KVCache restore 不是普通逐 key `get`,而是面向一批有序 page keys 的 prefix restore。它需要一次性回答“这一批最多恢复到哪里”,并且不能切开一个 radix node 对应的 atomic group。batch 化还能减少逐 key 调用、查表、锁和跨边界调度开销。 + - 本设计落点:Fluxon hostless get 以 batch 为单位计算 `raw_prefix_hit_len`、`transferable_len` 和 `prefix_hit_groups`。`get_start` 合并存在性 / prefix 判断和可恢复前缀的数据拉取启动,返回 handle 和 prefix;`get_transfer` 再消费 handle,把可恢复前缀转换成 readable `plan_ptr(value_ptrs)`。 + +### 核心实现思路 + +核心实现按上面的 insight 逐条落到接口和状态边界: + +- **对应 L2/L3 分离带来资源冗余和 L2 全局不可见** + - 实现思路:把 L2/L3 从两个后端系统收敛成 Fluxon 的 local side / remote side。local side 承接本机 shared segment、reserve slots 和 holder;remote side 承接跨 owner / 跨机器 KV 数据面。 + - 主要落点:Fluxon master/owner route、`MemHolder`、commit/release 生命周期。 +- **对应同机 worker 缺少共享内存快路径** + - 实现思路:一台机器运行一个 Fluxon owner,同机 SGLang worker 以 external/client attach 到同一个 owner shared segment。worker 只注册本进程 CUDA context 可见的 mapping,底层内存归属和释放由 owner 管理。 + - 主要落点:`wait_local_segments_ready()`、owner shared segment、CUDA host registration。 +- **对应统一 L2/L3 需要分布式 KV 能力** + - 实现思路:继续保留类似 Mooncake 的分布式 KV 目标,用 page key 做全局命名,用 route 和 version 定位本机 owner 或远端 owner,把无推理负载机器上的闲置 CPU 内存作为可放置、可复用的 remote side backing。inflight 判重和 commit future 约束写入发布,避免远端共享副本提前可见。 + - 主要落点:Fluxon master route、local/remote owner 放置、`local_fast_put_start` reservation、`local_fast_put_commit` 发布。 +- **对应保留 L2 低延迟需要 kernel 直连内存** + - 实现思路:在保留分布式 `key -> value` KV 语义的前提下,把普通 `put/get` 的数据面拆成两条 hostless 两阶段路径。Fluxon 不接管 KV page 内部 layout,只提供 key 路由、holder 生命周期和 `plan_ptr(value_ptrs)`。 + - `plan_ptr` 协议:Fluxon 和 SGLang kernel 之间只共享一段短生命周期 plan blob。blob 里保存本次 batch 的 `value_ptrs[]`;Fluxon 负责这些地址的分配、可见性和 holder 生命周期,SGLang kernel 负责按自己的 KV layout 解释并读写这些地址。 + - Put:`put_start -> native write -> put_commit` 构成写入闭环。`put_start` 本质上为本次 batch 分配 Fluxon 管理的 value memory,并返回 `plan_ptr(value_ptrs)`;SGLang native write kernel 直接往这些地址写入 GPU KV bytes;`put_commit` 在 kernel 写完后通知 Fluxon,把这些 slots 发布为可路由的 KV value。 + - Get / restore:`get_start -> get_transfer -> native restore -> release_views` 构成读取闭环。`get_start` 先计算连续安全前缀;`get_transfer` 把可恢复前缀 materialize 成 readable `plan_ptr(value_ptrs)` 并持有 holder;SGLang native restore kernel 直接从这些地址恢复 GPU KV cache,完成后 `release_views` 释放 plan 引用。 + - 主要落点:plan blob ABI、`value_ptrs[]`、`local_fast_put_start/local_fast_put_commit`、`get_start/get_transfer`、SGLang `write_*_to_fluxon_values` / `restore_*_from_fluxon_values`。 +- **对应 KV Cache 适合 write-back 最终一致性** + - 实现思路:KV Cache 的不可变、可丢失语义天然对应 Fluxon 的 master / owner / external 三层架构。master 管全局 route 和最终可见性,owner 管本机共享内存和 holder 生命周期,external 是 SGLang worker 的热路径接入层。 + - Put:native write 完成后先更新 external / owner 本地可见索引并返回 `KvFuture`,后台再推进 master route commit。`KvFuture` 成功前只表示本机 write-back 进入提交流程;失败时清理本地在途状态,退化为后续 cache miss。 + - Get / restore:优先查询 external / owner 本地热路径;本地 miss 时再进入远端 prefetch 和 restore。读取只 materialize 连续安全前缀,失败时 rollback 或按 miss 继续。 + - 主要落点:master route、owner shared segment、external local visible index、`KvFuture`、`get_start/get_transfer/release_views`。 +- **对应适配 SGLang KVCache 特化接口** + - 实现思路:把 restore 查询建模成 SGLang KVCache 专用的 batch prefix planning,而不是逐 key 独立 get。 + - Reject inflight / exist:KV page 按不可变缓存对象写回,重复 page key 不应产生第二份并发写入。`local_fast_put_start` 固定使用 `reject_if_inflight_same_key` 和 `reject_if_exist_same_key`,在分配 writable memory 前拒绝在途或已存在的同 key value,避免重复写回和未提交数据被误发布。 + - Prefetch 对应 `get_start`:`get_start(keys, prefix_best_effort, atomic_group_lens)` 按 key 顺序完成存在性 / prefix 判断,并在 owner/external 侧启动 `keys[..transferable_len]` 的 prefetch transfer,把“能恢复多少”和“开始拉取可恢复数据”合并在 start 阶段。 + - Batch 和 group 对齐:`get_start` 按 atomic group 边界把 `raw_prefix_hit_len` 收敛成 `transferable_len`;`get_transfer` 只消费这个 handle 和 `keys[..transferable_len]` 的 prefetch 结果,并构造 batch 级 readable `plan_ptr(value_ptrs)`,保证 kernel restore 看到的是连续、完整、可回滚的 readable batch plan。 + - 主要落点:`reject_if_inflight_same_key`、`reject_if_exist_same_key`、`GetStartResult`、`atomic_group_lens`、`raw_prefix_hit_len`、`transferable_len`、`prefix_hit_groups`、`get_start/get_transfer`。 + +因此,本设计要统一的是 L2/L3 的对象归属、可见性和生命周期,同时保留 L2 路径的低延迟数据面。单独替换成普通远端 KV 会丢掉 HiCache L2 的 kernel 直连能力;单独保留本地数组或进程内缓存,又无法让 L2 进入全局命中、驱逐和跨节点复用链路。 + 当前调用链主要分为三条主线: - 写入侧:`local_fast_put_start -> SGLang native write -> local_fast_put_commit`。 - 读取侧:`get_start -> get_transfer -> SGLang native restore -> release_views`。 - 放弃读取侧 restore 时:`cancel_get_transfer` 释放 `get_start` 持有的资源。 -Fluxon 仍然按 key 保存 opaque value bytes。SGLang 负责 page key、page layout、MHA/MLA/Mamba value 内部格式、GPU KV cache index 和 native kernel 调度;Fluxon 负责 key-version 路由、put 准入与 reservation、owner-local reserve、host value 地址、holder 生命周期和跨 owner 数据面。 - 这个集成把 SGLang 逻辑上的 L2/L3 缓存落到 Fluxon 统一管理的本机/远端 KV 层中。这样可以用同一套 owner、holder、commit/release 语义管理 KV page,减少传统 L2 host cache 与 L3 backend 分属不同系统时产生的同机重复缓存和生命周期割裂。 常见部署下,一台机器启动一个 Fluxon owner;同机多个 GPU 对应的多个 SGLang worker 进程通过 external/client attach 到同一个 owner shared segment。相比一个 SGLang 进程一个后端 segment、进程间不共享后端 segment 的形态,Fluxon 把同机 host/shared memory、owner local reserve slots 和 holder 生命周期放到同一个 owner 生命周期模型里。这样多个 SGLang worker 可以通过同一个 owner segment 获得本机快速可见性和受控的本地可写内存供给,减少各进程为了各自安全边界重复持有 KV、固定预留 segment 或独立维护 pin/release 状态带来的浪费。 @@ -169,15 +223,73 @@ blob[11] = value_ptr_9 hostless backup 的核心约束是:Fluxon 负责 GPU KV cache 之下的本机/远端 KV 层的地址分配、route 提交和生命周期管理,但真正的 KV bytes 由 SGLang native kernel 从 GPU KV cache 写入。因此 Fluxon 不能在收到 key 后立刻发布 KV route;它必须先完成 key reservation、put id 分配和 owner-local reserve slot claim,把稳定可写的 `value_ptrs[]` 通过 `plan_ptr` 返回给 SGLang。SGLang native kernel 写完这些地址后,`local_fast_put_commit` 才能把这些 slots 提交为 resident values,并发布 Fluxon KV route。 -这条写路径拆成两个 Fluxon API 阶段: +这条 backup 路径按 write-back 最终一致性设计:native write 完成后先进入本地可见和后台 commit 流程,跨 worker / 跨节点可见性以 `KvFuture` 成功为准。提交失败不会破坏推理语义,只会让对应 page 失去 shared backing;上层清理 `storage_*` 状态后按 cache miss 处理。 + +### 弹性本地侧预分配 + +弹性本地侧预分配对应 owner 本地写入预留池。它是在 owner shared segment 中为 SGLang hostless put 预先划分的 writable slots。`local_fast_put_start` 从这些 slots 中为本次 put 分配地址,并把地址写入 `plan_ptr(value_ptrs)` 返回给 SGLang native kernel。此时 slot 只处于 reserved/prepared 状态,还没有绑定为 Fluxon KV 的正式 `key -> value` route。 + +这个 pool 是共享 owner segment 上的弹性本地可写内存供给层。它让多个 SGLang worker 都能快速取得受 owner 生命周期管理的 `value_ptrs[]`,同时避免为每个 worker 固定切出长期独占的后端 segment。reserve slot 不足时可以按需求补充 grant,空闲后再按 cooldown 回收。 + +对象含义: + +| 对象 | 含义 | +| --- | --- | +| grant | owner 侧一次申请的大块本地内存,当前固定为 `512 MiB`。 | +| slot | grant 内按 `slot_size` 切分的小块;一个 slot 承载一个 Fluxon value。 | +| slot lease | `local_fast_put_start` 为本次 batch 临时 claim 到的一组 slots;失败或 abort 时必须释放。 | +| value pointer | slot 的起始地址,会写入 plan blob 的 `value_ptrs[]`,供 SGLang kernel 直接写入。 | +| resident value | `local_fast_put_commit` 后由 slot 构造出的本地可读 value。 | +| route | master/owner 确认后的 key 到 value 位置映射;route 成功后该 value 才是全局可见的 KV replica。 | + +slot 生命周期: + +```text +Free + -> Prepared // local_fast_put_start claim slot + -> PendingLocalVisible // local_fast_put_commit 开始,本地 resident value 已记录为 pending visible + -> Committed // put_done 成功,route 引用该 slot + -> Free // route 和 holder 引用都释放后回收 +``` + +如果 native write 失败,调用方必须执行 `put_abort(plan_ptr)`,Prepared slots 会回到 Free。`local_fast_put_commit` 成功返回后,slot 是否能释放由 route 引用和 holder 引用共同决定;只要 master/owner route 或 `MemHolder` 仍引用该 slot,底层 grant 就不能释放。 + +当前容量策略: + +| 项 | 当前实现 | +| --- | --- | +| grant 物理粒度 | `OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES = 512 * 1024 * 1024` | +| 最小 slot size | `4 KiB` | +| slot size 计算 | `max(value_len, 4 KiB).next_power_of_two()` | +| slot 上限 | `slot_size <= 512 MiB` | +| refill 触发 | 当前 slot class free slots 不足时登记 pending demand 并唤醒 rebalance actor。 | +| 默认等待 | soft wait `10 ms`,hard timeout `1 s`。 | +| shrink 单位 | 整个 grant;不做 live grant compaction。 | + +底层物理释放收束在 grant 级别。单个 committed slot 只是 grant 内逻辑索引,不直接拥有释放整块 mmap/registered memory 的权力。 + +### Fluxon put_start / put_commit 接口设计 + +Fluxon 的 backup 解法是把普通 KV `put(key, bytes)` 拆成 `put_start -> native write -> put_commit`。这个拆分的核心是接口解耦:Fluxon 先给本次写入分配受 owner 生命周期管理的 value memory,并把地址交给 SGLang;SGLang native/CUDA kernel 负责真正把 GPU KV cache bytes 写入这些地址;kernel 写完后,SGLang 再通知 Fluxon 发布这批 value。这样普通 KV 接口里的 payload materialization、CPU 侧 bytes 拆装和逐 page/layer 拷贝组织都不会进入 backup 热路径。 -1. `local_fast_put_start(keys, value_len)`:只做写入准入、key reservation、put id 分配和可写 value 地址准备,返回 `plan_ptr(value_ptrs)`;此时 value bytes 还没有写完,不能作为可读 KV route 暴露。 -2. `local_fast_put_commit(plan_ptr)`:在 SGLang native kernel 完成写入后消费 put plan,提交 slot / transfer / route,并返回 `KvFuture`;只有 future 成功后,SGLang 才能把 node 标记为 `storage_backed`。 +`put_start` 不是一次可见写入,它的核心结果是内存分配和指针返回。Fluxon 为本次 batch claim owner-local reserve slots,生成 `plan_ptr(value_ptrs)`;`value_ptrs[]` 指向 Fluxon owner segment 中已经准备好的 writable value memory,SGLang kernel 可以直接写这些地址。判重、reservation 和 put id 是保护这次内存分配不被重复写入或提前发布的控制面约束;这些 value 在 `put_commit` 前不会作为可读 route 暴露。 -写入阶段的拆分主要是为了同时满足两个约束: +`put_commit` 是 kernel 写完后的通知和发布点。SGLang 在 CUDA write 完成后调用它,Fluxon 消费 put plan,把对应 slots 转成 resident values,并异步推进 route commit。`KvFuture` 成功前,数据只表示本次 write-back 已进入 Fluxon commit 流程;`KvFuture` 成功后,page 才能成为跨 worker / 跨节点可复用的 shared backing。这样 `put_start -> native write -> put_commit` 就构成了 hostless put 的完整闭环。 + +这套接口拆分直接使用上面的弹性本地侧预分配池:`put_start` 从预分配 reserve slots 中 claim 短生命周期 slot lease,热路径拿到的是已准备好的地址。 + +| 解法层 | 做什么 | 解决的问题 | +| --- | --- | --- | +| `local_fast_put_start(keys, value_len)` | 从 owner-local reserve slots claim 本次 batch 的 slot lease,分配 writable value memory,并返回 `plan_ptr(value_ptrs)`;key reservation 和 put id 保护这次分配 | 在 native write 前只暴露可写地址,不发布可读 route,避免其它 get 读到尚未写完的 value | +| SGLang native write | SGLang native kernel 根据 `plan_ptr(value_ptrs)` 把 GPU KV page 写入 Fluxon 管理的 host value memory | 避免普通 KV `put(bytes)` 路径在 CPU 侧拆装 payload 和逐 page/layer 组织拷贝 | +| `local_fast_put_commit(plan_ptr)` | 消费 put plan,把已写完的 slots 转为 resident values,推进 transfer / route commit,并返回 `KvFuture` | 把本地写完和全局发布分开;只有 future 成功后,SGLang 才能把 node 标记为 `storage_backed` | +| 弹性本地侧预分配 | owner shared segment 中按 slot size 管理 reserve slots;free slots 不足时按 pending demand 补充 grant,空闲后按 cooldown 回收 | 热路径直接 claim 已准备好的可写地址,避免每个 worker 固定独占 segment,也避免每次 backup 临时分配或注册 host memory | + +写入阶段的拆分主要是为了同时满足三个约束: - 数据面效率:SGLang 不需要先把 GPU KV page 包装成通用 KV payload 再交给后端,而是直接用 kernel 写入 Fluxon 返回的 value 地址。 - 可见性安全:`put_start` 阶段只预留地址,不发布 route;避免其它 get 读到尚未写完或尚未 commit 的 value。 +- 容量弹性:本地侧预分配池提供短生命周期 slot lease,而不是为每个 SGLang worker 固定切出长期独占内存;容量不足时由 owner 侧 refill,空闲后按 grant 粒度回收。 ```mermaid sequenceDiagram @@ -215,19 +327,20 @@ hostless backup 默认不依赖 put 前 exists 扫描。重复 key 或在途 key commit 请求会带上 `len`、`src_offset` 和 target 信息。Fluxon 用这些字段判断本次 value 是否落在当前进程可访问的 owner segment 或 owner-local reserve slot 中;如果需要本地可见索引,`put_done` 会返回 owner 分配的 `local_cache_holder_id`。`MemoryInfo` 和 holder 生命周期在下文说明。 -## Restore 时序 +## Prefetch 与 Restore 时序 -hostless restore 的核心约束是:SGLang 只能恢复有序 page keys 的连续前缀,并且不能切开一个 radix node 对应的 atomic group。Fluxon 需要先在本机/远端 KV 层里判断这批 keys 的可恢复边界,再把真正可恢复的部分转换成 SGLang kernel 可读取的 `plan_ptr(value_ptrs)`。因此 restore 被拆成 `get_start` 和 `get_transfer` 两个阶段。 +hostless restore 的核心约束是:SGLang 只能恢复有序 page keys 的连续前缀,并且不能切开一个 radix node 对应的 atomic group。Fluxon 需要先在本机/远端 KV 层里判断这批 keys 的可恢复边界,再把真正可恢复的部分提前 materialize 到当前进程可读的 holder / memory view 中,最后转换成 SGLang kernel 可读取的 `plan_ptr(value_ptrs)`。 -`get_start(keys, prefix_best_effort, atomic_group_lens)` 只做恢复规划:按 key 顺序做 local visible check / owner get start,计算 page 级连续命中前缀 `raw_prefix_hit_len`,再按 `atomic_group_lens` 向下收敛成 `transferable_len`。这个阶段回答“本次最多能恢复多少”,但不要求 SGLang 立刻分配 GPU KV pages,也不暴露 readable plan。 +因此读取侧分成 prefetch 和 restore 两段: -`get_transfer(handle)` 在 SGLang 决定恢复后执行:它消费 `get_start` 返回的 handle,等待或完成必要 transfer,只 materialize `keys[..transferable_len]`,并返回持有 holder 引用的 readable `plan_ptr`。随后 SGLang native kernel 使用 `restore_*_from_fluxon_values(...)`,把 Fluxon value memory 拷回 GPU KV cache。 +- Prefetch:`get_start(keys, prefix_best_effort, atomic_group_lens)` 按 key 顺序做 local visible check / owner get start,计算 page 级连续命中前缀 `raw_prefix_hit_len`,再按 `atomic_group_lens` 向下收敛成 `transferable_len`。prefix 发布后,owner/external 侧会启动后台 prefetch transfer,只处理 `keys[..transferable_len]`,并把 holder / transfer result 保存在 shared op 中。 +- Restore:SGLang 拿到 `transferable_len` 后再决定是否分配 GPU KV pages 并继续恢复。`get_transfer(handle)` 消费 `get_start` 返回的 handle,等待或取得 prefetch 结果,生成持有 holder 引用的 readable `plan_ptr`。随后 SGLang native kernel 使用 `restore_*_from_fluxon_values(...)`,把 Fluxon value memory 拷回 GPU KV cache。 -读取阶段拆成 planning 和 materialization 两步,主要是为了保证: +读取阶段拆成 prefetch 和 restore 两步,主要是为了保证: - prefix 安全:中间 page miss 时,只恢复连续命中的完整前缀,不构造带洞的 GPU KV 状态。 - atomic group 安全:`transferable_len` 不会切开 radix node group,避免恢复半个 node。 -- 资源效率:SGLang 在知道可恢复边界后再分配 GPU KV pages,避免先分配再发现 miss。 +- 资源效率:SGLang 在知道可恢复边界后再分配 GPU KV pages,同时 Fluxon 可以提前 prefetch 可恢复前缀,重叠远端 materialization 和 SGLang 侧 GPU page 分配。 - 生命周期安全:`get_transfer` 返回的 plan 持有 holder 引用,直到 `release_views(plan_ptr)` 后才释放,保证 kernel restore 期间 value 地址稳定。 ```mermaid @@ -243,17 +356,25 @@ sequenceDiagram B->>F: get_start(storage_keys, prefix_best_effort, atomic_group_lens) F->>E: batch_get_start(keys) E->>O: ExternalBatchGetStartReq - O-->>E: handle + raw_prefix_hit_len - E-->>F: backend handle + raw_prefix_hit_len - F->>F: build GetStartResult(raw_prefix_hit_len, transferable_len, ...) - F-->>B: GetStartHandle + GetStartResult - B-->>U: transferable_len / prefix_hit_groups / first_miss_index + O->>O: local visible check / owner get start + O->>O: compute raw_prefix_hit_len and transferable_len + par return prefix + O-->>E: handle + raw_prefix_hit_len + E-->>F: backend handle + raw_prefix_hit_len + F->>F: build GetStartResult(raw_prefix_hit_len, transferable_len, ...) + F-->>B: GetStartHandle + GetStartResult + B-->>U: transferable_len / prefix_hit_groups / first_miss_index + U->>U: allocate GPU KV pages for transferable prefix + and background prefetch + O->>O: prefetch transfer keys[..transferable_len] + O->>O: keep holders / transfer results in shared op + end alt transferable_len > 0 and caller chooses restore U->>B: get_transfer(handle) B->>F: get_transfer(handle) F->>E: batch_get_transfer(handle, transferable keys) E->>O: ExternalBatchGetTransferReq - O-->>E: holders / transfer results + O-->>E: prefetched holders / transfer results E-->>F: plan_ptr(value_ptrs, holders kept alive) F-->>B: plan_ptr B-->>U: plan_ptr @@ -264,6 +385,8 @@ sequenceDiagram U->>B: cancel_get_transfer(handle) B->>F: cancel_get_transfer(handle) F->>E: cancel_batch_get_start(handle) + E->>O: ExternalBatchGetCancelReq + O->>O: release get-start handle / prefetched holders end ``` @@ -280,7 +403,7 @@ sequenceDiagram 生命周期规则: -- `get_start` 成功后,调用方必须二选一:`get_transfer(handle)` 或 `cancel_get_transfer(handle)`。 +- `get_start` 成功后,调用方必须二选一:`get_transfer(handle)` 或 `cancel_get_transfer(handle)`;放弃 restore 时必须取消 handle,释放可能已经启动的 prefetch 资源。 - `get_transfer(handle)` 成功后,handle 已被消费;后续由 returned `plan_ptr` 和 `release_views(plan_ptr)` 管理。 - `release_views(plan_ptr)` 必须在 native restore 完成后执行,即使 native restore 失败也要释放。 - `get_start` 只命中部分前缀时,SGLang 只能恢复 `transferable_len` 覆盖的完整 atomic groups,不能构造半个 atomic group 的 GPU KV 状态。 @@ -300,58 +423,6 @@ Fluxon client/external 侧会维护当前进程可直接访问的 value 索引 `precommit_local_visible_info` 只覆盖 commit 进行中的短窗口。put commit 成功并确认 holder 后,会移除 precommit entry 并记录 committed entry;如果 commit 失败,precommit entry 必须被清理,不能作为后续 storage-backed 恢复来源。 -## Owner 本地写入预留池 - -Owner 本地写入预留池是 owner segment 中为 SGLang hostless put 预先划分的 writable slots。`local_fast_put_start` 从这些 slots 中为本次 put 分配地址,并把地址写入 `plan_ptr(value_ptrs)` 返回给 SGLang native kernel。此时 slot 只处于 reserved/prepared 状态,还没有绑定为 Fluxon KV 的正式 `key -> value` route。 - -这个 pool 是共享 owner segment 上的弹性本地可写内存供给层。它让多个 SGLang worker 都能快速取得受 owner 生命周期管理的 `value_ptrs[]`,同时避免为每个 worker 固定切出长期独占的后端 segment。reserve slot 不足时可以按需求补充 grant,空闲后再按 cooldown 回收。 - -SGLang native kernel 写完 `value_ptrs[]` 后,`local_fast_put_commit` 才把这些 slots 提交为 resident values,并完成 Fluxon KV route commit。commit 前如果 native write 失败,`put_abort(plan_ptr)` 会释放这些 reserved slots。 - -这条路径把写入拆成两个阶段: - -1. `local_fast_put_start` 完成 key reservation、put id 分配和本地 slot claim,返回 `plan_ptr(value_ptrs)`。 -2. SGLang native kernel 写完 `value_ptrs[]` 后,`local_fast_put_commit` 再把这些 slot 转为 resident values,并完成 Fluxon KV 的 put 提交。 - -这里的 `local_fast_*` 是 Python/PyO3 public hostless plan API。真正的 value bytes 由 SGLang native kernel 写入 `value_ptrs[]` 指向的地址;Fluxon 在 commit 阶段只消费 put plan、处理必要 transfer 或 direct done,并完成 route commit。 - -对象含义: - -| 对象 | 含义 | -| --- | --- | -| grant | owner 侧一次申请的大块本地内存,当前固定为 `512 MiB`。 | -| slot | grant 内按 `slot_size` 切分的小块;一个 slot 承载一个 Fluxon value。 | -| slot lease | `local_fast_put_start` 为本次 batch 临时 claim 到的一组 slots;失败或 abort 时必须释放。 | -| value pointer | slot 的起始地址,会写入 plan blob 的 `value_ptrs[]`,供 SGLang kernel 直接写入。 | -| resident value | `local_fast_put_commit` 后由 slot 构造出的本地可读 value。 | -| route | master/owner 确认后的 key 到 value 位置映射;route 成功后该 value 才是全局可见的 KV replica。 | - -slot 生命周期: - -```text -Free - -> Prepared // local_fast_put_start claim slot - -> PendingLocalVisible // local_fast_put_commit 开始,本地 resident value 已记录为 pending visible - -> Committed // put_done 成功,route 引用该 slot - -> Free // route 和 holder 引用都释放后回收 -``` - -如果 native write 失败,调用方必须执行 `put_abort(plan_ptr)`,Prepared slots 会回到 Free。`local_fast_put_commit` 成功返回后,slot 是否能释放由 route 引用和 holder 引用共同决定;只要 master/owner route 或 `MemHolder` 仍引用该 slot,底层 grant 就不能释放。 - -当前容量策略: - -| 项 | 当前实现 | -| --- | --- | -| grant 物理粒度 | `OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES = 512 * 1024 * 1024` | -| 最小 slot size | `4 KiB` | -| slot size 计算 | `max(value_len, 4 KiB).next_power_of_two()` | -| slot 上限 | `slot_size <= 512 MiB` | -| refill 触发 | 当前 slot class free slots 不足时登记 pending demand 并唤醒 rebalance actor。 | -| 默认等待 | soft wait `10 ms`,hard timeout `1 s`。 | -| shrink 单位 | 整个 grant;不做 live grant compaction。 | - -底层物理释放收束在 grant 级别。单个 committed slot 只是 grant 内逻辑索引,不直接拥有释放整块 mmap/registered memory 的权力。 - ## SGLang Node Storage 状态 SGLang 侧的 node metadata 不等价于 Fluxon master route 状态。当前四个字段建议按下面语义解释: diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs index 3cfd44d..a10e354 100755 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs @@ -1,3 +1,4 @@ +use crate::client_kv_api::ClientKvApi; use crate::client_kv_api::msg_pack::{ ExternalBatchGetCancelReq, ExternalBatchGetCancelResp, ExternalBatchGetItemResp, ExternalBatchGetReq, ExternalBatchGetResp, ExternalBatchGetStartReq, ExternalBatchGetStartResp, @@ -11,33 +12,31 @@ use crate::client_kv_api::msg_pack::{ ExternalPutRevokeReq, ExternalPutRevokeResp, ExternalPutStartReq, ExternalPutStartResp, ExternalPutTransferEndReq, ExternalPutTransferEndResp, TestPutPhaseTrace, }; -use crate::client_kv_api::ClientKvApi; use crate::client_kv_api::{ self, ExternalGetStartDedupKey, ExternalGetStartEntry, ExternalGetStartOwnerItem, ExternalGetStartPrefixResult, ExternalGetStartSharedItemResult, ExternalGetStartSharedOp, ExternalGetStartSharedPhase, ExternalGetStartTransferOutput, ExternalHoldingGetInfo, - ExternalPendingPutCtx, + ExternalPendingPutCtx, ReplicaTaskTarget, }; -use crate::client_seg_pool::{parse_side_transfer_worker_lane_idx, ResolveSideTransferLaneReq}; +use crate::client_seg_pool::{ResolveSideTransferLaneReq, parse_side_transfer_worker_lane_idx}; use crate::cluster_manager::NodeIDString; use crate::cluster_manager::{ META_KEY_SHARED_STORAGE_NODE_ID, META_KEY_SHARED_STORAGE_NODE_START_TIME, }; use crate::master_kv_router::msg_pack::{ - BatchPutDoneItemReq, BatchPutRevokeItemReq, BatchPutStartItemReq, + BatchPutDoneItemReq, BatchPutRevokeItemReq, BatchPutStartItemReq, PutDoneCommittedSlot, }; use crate::memholder::MemholderManagerTrait; use crate::memholder::NodeHolderKey; use crate::memholder::{ExternalMemHolderInfo, UserMemHolder, UserMemHolderExposeKind}; use crate::p2p::msg_pack::MsgPack; -use crate::rpcresp_kvresult_convert::msg_and_error::{codes_api, ApiError, KvError, KvResult, OK}; use crate::rpcresp_kvresult_convert::FromError; use crate::rpcresp_kvresult_convert::ToResult; +use crate::rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, KvResult, OK, codes_api}; use async_trait::async_trait; use dashmap::mapref::entry::Entry; -use futures::stream::{self, StreamExt}; -use std::sync::atomic::Ordering; use std::sync::Arc; +use std::sync::atomic::Ordering; use std::time::Duration; use std::time::Instant; use tracing; @@ -87,6 +86,146 @@ fn local_committed_cache_publish( }) } +fn external_local_first_error_item(err: &KvError) -> ExternalBatchPutStartItemResp { + ExternalBatchPutStartItemResp { + put_id: None, + ..ExternalBatchPutStartItemResp::from_error(err) + } +} + +fn external_local_first_release_keys(inner: &client_kv_api::ClientKvApiInner, keys: &[String]) { + for key in keys { + inner.release_external_local_first_put_key(key); + } +} + +async fn commit_external_local_first_pending( + inner: &client_kv_api::ClientKvApiInner, + key: &str, + put_id: crate::master_kv_router::put::PutIDForAKey, + ctx: &ExternalPendingPutCtx, + req_src_offset: u64, + req_len: u64, + op: &'static str, +) -> KvResult { + if ctx.peer_id.is_some() { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "{op} local-first pending ctx must not carry peer_id: key={} put_id=({},{})", + key, put_id.0, put_id.1 + ), + })); + } + if ctx.src_offset != req_src_offset || ctx.len != req_len { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "{op} local-first request mismatches pending ctx: key={} put_id=({},{}) req_src_offset={} ctx_src_offset={} req_len={} ctx_len={}", + key, put_id.0, put_id.1, req_src_offset, ctx.src_offset, req_len, ctx.len + ), + })); + } + let slot_ref = ctx.local_reserve_slot.as_ref().ok_or_else(|| { + KvError::Api(ApiError::InvalidArgument { + detail: format!( + "{op} pending ctx is not local-first: key={} put_id=({},{})", + key, put_id.0, put_id.1 + ), + }) + })?; + let slot_size = ctx.local_reserve_slot_size.ok_or_else(|| { + KvError::Api(ApiError::InvalidArgument { + detail: format!( + "{op} local-first pending ctx missing slot_size: key={} put_id=({},{})", + key, put_id.0, put_id.1 + ), + }) + })?; + let len = u32::try_from(req_len).map_err(|_| { + KvError::Api(ApiError::Unknown { + detail: format!( + "{op} local-first len does not fit u32: key={} len={}", + key, req_len + ), + }) + })?; + let memory_info = inner + .build_local_reserve_resident_memory_info( + key, + slot_ref.ptr, + len, + slot_size, + slot_ref.grant_id, + slot_ref.slot_index, + ) + .await; + inner.install_precommit_local_visible_memory_info(key, memory_info.clone()); + inner.promote_precommit_local_reserve_resident_slot_if_same(key, put_id, memory_info)?; + Ok(PutDoneCommittedSlot { + grant_id: slot_ref.grant_id, + slot_index: slot_ref.slot_index, + slot_size, + addr: slot_ref.ptr, + base_addr: slot_ref.base_addr, + len: req_len, + }) +} + +fn spawn_external_local_first_publish( + inner: &client_kv_api::ClientKvApiInner, + key: String, + put_id: crate::master_kv_router::put::PutIDForAKey, + lease_id: Option, + committed_slot: PutDoneCommittedSlot, +) { + let view = inner.view.clone_view(); + let spawn_view = view.clone(); + spawn_view.spawn("external_local_first_route_publish", async move { + let inner = view.client_kv_api().inner(); + match inner + .batch_put_done(vec![BatchPutDoneItemReq { + key: key.clone(), + put_id, + lease_id, + committed_slot: Some(committed_slot), + publish_local_cache: false, + }]) + .await + { + Ok(resp) => { + if let Some(item) = resp.items.into_iter().next() { + if let Err(err) = + crate::rpcresp_kvresult_convert::try_from_code(item.error_code, item.error_json) + { + tracing::warn!( + "external local-first route publish failed: key={} put_id=({},{}) err={}", + key, + put_id.0, + put_id.1, + err + ); + } + } else { + tracing::warn!( + "external local-first route publish returned empty response: key={} put_id=({},{})", + key, + put_id.0, + put_id.1 + ); + } + } + Err(err) => { + tracing::warn!( + "external local-first route publish rpc failed: key={} put_id=({},{}) err={}", + key, + put_id.0, + put_id.1, + err + ); + } + } + }); +} + pub(crate) fn normalize_external_get_start_group_lens( keys_len: usize, atomic_group_lens: Option>, @@ -769,7 +908,6 @@ impl ClientKvApi { .is_some_and(|peer| peer != owner_id.as_str()), put_id: Some(put_id), lease_id: req.lease_id, - write_through: req.write_through, started_time: req.started_time, test_observe_put_phases: req.test_observe_put_phases, }, @@ -1222,7 +1360,7 @@ impl HandlerForExternalClient for ClientKvApi { req.len as u32, req.reject_if_inflight_same_key, req.reject_if_exist_same_key, - req.write_through, + req.make_replica_task, req.preferred_sub_cluster.as_deref(), source_node_id, ) @@ -1256,6 +1394,16 @@ impl HandlerForExternalClient for ClientKvApi { src_offset }; let remote_offset = put_start_resp.target_addr - put_start_resp.target_base_addr; + let replica_target = + put_start_resp + .replica_target + .as_ref() + .map(|target| ReplicaTaskTarget { + node_id: target.node_id.clone(), + target_offset: target.target_addr - target.target_base_addr, + target_base_addr: target.target_base_addr, + len: target.len, + }); inner.external_pending_puts.insert( ( req.key.clone(), @@ -1276,7 +1424,11 @@ impl HandlerForExternalClient for ClientKvApi { remote_offset }, len: req.len, + make_replica_task: req.make_replica_task && replica_target.is_some(), preferred_sub_cluster: req.preferred_sub_cluster.clone(), + replica_target, + local_reserve_slot: None, + local_reserve_slot_size: None, }, ); if !is_local_target { @@ -1337,94 +1489,93 @@ impl HandlerForExternalClient for ClientKvApi { self.validate_requester_owner_status_updated(req.started_time)?; - let start_resp = inner - .batch_put_start( - req.items - .iter() - .map(|item| BatchPutStartItemReq { - key: item.key.clone(), - len: item.len, - reject_if_inflight_same_key: item.reject_if_inflight_same_key, - reject_if_exist_same_key: item.reject_if_exist_same_key, - write_through: item.write_through, - preferred_sub_cluster: item.preferred_sub_cluster.clone(), - }) - .collect(), - ) - .await?; - if start_resp.items.len() != req.items.len() { - return Err(KvError::Api(ApiError::Unknown { - detail: format!( - "external_batch_put_start response length mismatch: expected={} got={}", - req.items.len(), - start_resp.items.len() - ), + let Some(first_item) = req.items.first() else { + return Ok(ExternalBatchPutStartResp { + items: Vec::new(), + error_code: OK, + error_json: String::new(), + }); + }; + let value_len = first_item.len; + if req.items.iter().any(|item| item.len != value_len) { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: "external_batch_put_start local-first requires uniform item len" + .to_string(), })); } - let self_node_id = inner.view.cluster_manager().get_self_info().id.clone(); - let mut items = Vec::with_capacity(req.items.len()); - for (req_item, start_item) in req.items.into_iter().zip(start_resp.items.into_iter()) { - if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( - start_item.error_code, - start_item.error_json.clone(), + let mut reserved_keys = Vec::with_capacity(req.items.len()); + for item in &req.items { + if let Err(err) = inner.reserve_external_local_first_put_key( + &item.key, + item.reject_if_inflight_same_key, + item.reject_if_exist_same_key, ) { - items.push(ExternalBatchPutStartItemResp { - put_id: None, - ..ExternalBatchPutStartItemResp::from_error(&err) + external_local_first_release_keys(inner, &reserved_keys); + let items = req + .items + .iter() + .map(|_| external_local_first_error_item(&err)) + .collect(); + return Ok(ExternalBatchPutStartResp { + items, + error_code: OK, + error_json: String::new(), }); - continue; } + reserved_keys.push(item.key.clone()); + } - let src_offset = start_item.src_addr - start_item.src_base_addr; - let is_local_target = start_item.node_id == self_node_id; - let target_offset = if is_local_target { - start_item.target_addr - start_item.target_base_addr - } else { - src_offset - }; - let remote_offset = start_item.target_addr - start_item.target_base_addr; + let slot_lease = match inner + .owner_claim_local_reserve_slot_lease(value_len, req.items.len()) + .await + { + Ok(slot_lease) => slot_lease, + Err(err) => { + external_local_first_release_keys(inner, &reserved_keys); + return Err(err); + } + }; + let self_node_id = inner.view.cluster_manager().get_self_info().id.clone(); + let mut items = Vec::with_capacity(req.items.len()); + for (req_item, slot_ref) in req.items.into_iter().zip(slot_lease.slots.into_iter()) { + let put_id = inner.next_external_local_first_put_id(); + let src_offset = slot_ref.ptr.saturating_sub(slot_ref.base_addr); inner.external_pending_puts.insert( - ( - req_item.key.clone(), - start_item.put_id.0, - start_item.put_id.1, - ), + (req_item.key.clone(), put_id.0, put_id.1), ExternalPendingPutCtx { - peer_id: if is_local_target { - None - } else { - Some(start_item.node_id.clone()) - }, + peer_id: None, src_offset, - target_base_addr: start_item.target_base_addr, - target_offset: if is_local_target { - target_offset - } else { - remote_offset - }, + target_base_addr: slot_ref.base_addr, + target_offset: src_offset, len: req_item.len, + make_replica_task: req_item.make_replica_task, preferred_sub_cluster: req_item.preferred_sub_cluster.clone(), + replica_target: None, + local_reserve_slot: Some(slot_ref.clone()), + local_reserve_slot_size: Some(slot_lease.slot_size), }, ); + tracing::debug!( + "external_batch_put_start local-first: key={} put_id=({},{}) node_id={} base={:#x} offset={:#x} len={}", + req_item.key, + put_id.0, + put_id.1, + self_node_id, + slot_ref.base_addr, + src_offset, + req_item.len + ); items.push(ExternalBatchPutStartItemResp { error_code: OK, src_offset, - target_offset, - transfer_target_offset: if is_local_target { - None - } else { - Some(remote_offset) - }, - peer_id: if is_local_target { - None - } else { - Some(start_item.node_id) - }, - src_base_addr: start_item.src_base_addr, - target_base_addr: start_item.target_base_addr, + target_offset: src_offset, + transfer_target_offset: None, + peer_id: None, + src_base_addr: slot_ref.base_addr, + target_base_addr: slot_ref.base_addr, error_json: String::new(), - put_id: Some(start_item.put_id), + put_id: Some(put_id), }); } @@ -1462,23 +1613,27 @@ impl HandlerForExternalClient for ClientKvApi { .external_pending_puts .get(&(req.key.clone(), put_id.0, put_id.1)) .map(|ctx| ctx.clone()); - let preferred_sub_cluster = pending_ctx + let replica_target = pending_ctx + .as_ref() + .and_then(|ctx| ctx.replica_target.clone()); + let admitted_replica_task = pending_ctx .as_ref() - .and_then(|ctx| ctx.preferred_sub_cluster.clone()); + .map(|ctx| ctx.make_replica_task) + .unwrap_or(false); let self_node_id = inner.view.cluster_manager().get_self_info().id.clone(); let req_remote_target = req .peer_id .as_deref() .is_some_and(|peer| peer != self_node_id.as_str()); - let has_remote_append = pending_ctx + let has_remote_target = pending_ctx .as_ref() .and_then(|ctx| ctx.peer_id.as_ref()) .is_some(); - if pending_ctx.is_some() && req_remote_target != has_remote_append { + if pending_ctx.is_some() && req_remote_target != has_remote_target { let err = KvError::Api(ApiError::InvalidArgument { detail: format!( "external_put_transfer_end peer_id mismatches pending ctx: key={} put_id=({},{}) req_remote_target={} ctx_remote_target={}", - req.key, put_id.0, put_id.1, req_remote_target, has_remote_append + req.key, put_id.0, put_id.1, req_remote_target, has_remote_target ), }); if let Err(revoke_err) = inner.put_revoke(&req.key, put_id).await { @@ -1495,120 +1650,8 @@ impl HandlerForExternalClient for ClientKvApi { .invalidate(&(req.key.clone(), put_id.0, put_id.1)); return Ok(ExternalPutTransferEndResp::from_error(&err)); } - - // Delegate transfer to owner put_transfer (offset-based) then end - // For remote target, ignore caller's target_offset (staging) and use stashed remote ctx. - let (peer_id_for_transfer, target_off_for_transfer, target_base_for_transfer) = - if let Some(peer) = req.peer_id.clone() { - if peer == self_node_id.as_ref() { - (None, req.target_offset, None) - } else { - match pending_ctx.as_ref() { - Some(ctx) if ctx.peer_id.is_some() => ( - ctx.peer_id.clone(), - ctx.target_offset, - Some(ctx.target_base_addr), - ), - None => match req.target_base_addr { - Some(target_base_addr) => { - (Some(peer.into()), req.target_offset, Some(target_base_addr)) - } - None => { - let err = KvError::Unreachable( - crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::RpcDecodeError { - rpc_input_json: format!( - "missing pending remote put ctx and caller target_base_addr; key={}, put_id=({},{}), peer_id={}", - req.key, put_id.0, put_id.1, peer - ), - }, - ); - return Ok(ExternalPutTransferEndResp::from_error(&err)); - } - }, - Some(_) => match req.target_base_addr { - Some(target_base_addr) => { - (Some(peer.into()), req.target_offset, Some(target_base_addr)) - } - None => { - let err = KvError::Unreachable( - crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::RpcDecodeError { - rpc_input_json: format!( - "pending local ctx conflicted with remote external_put_transfer_end; key={}, put_id=({},{}), peer_id={}", - req.key, put_id.0, put_id.1, peer - ), - }, - ); - return Ok(ExternalPutTransferEndResp::from_error(&err)); - } - }, - } - } - } else { - (None, req.target_offset, None) - }; - let transfer_peer_id_for_trace = peer_id_for_transfer.as_ref().map(|peer| peer.to_string()); - - tracing::debug!( - "external_put_transfer_end resolved: key={}, put_id=({},{}) src_off={:#x}, tgt_off={:#x}, len={}, peer_id={:?}, target_base={:?}", - req.key, - put_id.0, - put_id.1, - req.src_offset, - target_off_for_transfer, - req.len, - peer_id_for_transfer, - target_base_for_transfer - ); - - let transfer_started_at = Instant::now(); - let mut put_locality_recorded = false; - if req.write_through { - let transfer_result = inner - .put_transfer( - &req.key, - put_id, - req.src_offset, - target_off_for_transfer, - req.len, - peer_id_for_transfer, - target_base_for_transfer, - ) - .await; - match transfer_result { - Ok(breakdown) => { - let breakdown_transfer_us = breakdown.submit_blocking_us - + breakdown.create_xfer_req_us - + breakdown.post_xfer_req_us - + breakdown.poll_wait_us; - inner.record_put_locality( - breakdown.remote_transfer, - req.len, - breakdown_transfer_us, - ); - put_locality_recorded = true; - } - Err(e) => { - tracing::error!("Failed to transfer data: {}", e); - // On transfer failure, revoke the put to release resources - if let Err(revoke_err) = inner.put_revoke(&req.key, put_id).await { - tracing::warn!( - "put_revoke also failed after transfer error: {}", - revoke_err - ); - } - // Cleanup pending ctx on failure - inner - .external_pending_puts - .invalidate(&(req.key.clone(), put_id.0, put_id.1)); - return Ok(crate::rpcresp_kvresult_convert::FromError::from_error(&e)); - } - } - } - - let put_transfer_total_us = duration_to_i64_us(transfer_started_at.elapsed()); - if req.write_through && !put_locality_recorded { - inner.record_put_locality(false, req.len, 0); - } + let put_transfer_total_us = 0; + let transfer_peer_id_for_trace = None; if inner.skip_put_end_commit_enabled() { inner @@ -1640,35 +1683,31 @@ impl HandlerForExternalClient for ClientKvApi { } let end_started_at = Instant::now(); - let publish_local_cache = !req.write_through || !req_remote_target; - let local_cache_publish = if publish_local_cache { - match local_committed_cache_publish( - "external_put_transfer_end", - &req.key, - put_id, - pending_ctx.as_ref(), - req.src_offset, - req.len, - ) { - Ok(publish) => Some(publish), - Err(err) => { - if let Err(revoke_err) = inner.put_revoke(&req.key, put_id).await { - tracing::warn!( - "external_put_transfer_end put_revoke failed after local cache publish precheck error: key={} put_id=({},{}) err={}", - req.key, - put_id.0, - put_id.1, - revoke_err - ); - } - inner - .external_pending_puts - .invalidate(&(req.key.clone(), put_id.0, put_id.1)); - return Ok(crate::rpcresp_kvresult_convert::FromError::from_error(&err)); + let publish_local_cache = true; + let local_cache_publish = match local_committed_cache_publish( + "external_put_transfer_end", + &req.key, + put_id, + pending_ctx.as_ref(), + req.src_offset, + req.len, + ) { + Ok(publish) => publish, + Err(err) => { + if let Err(revoke_err) = inner.put_revoke(&req.key, put_id).await { + tracing::warn!( + "external_put_transfer_end put_revoke failed after local cache publish precheck error: key={} put_id=({},{}) err={}", + req.key, + put_id.0, + put_id.1, + revoke_err + ); } + inner + .external_pending_puts + .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + return Ok(crate::rpcresp_kvresult_convert::FromError::from_error(&err)); } - } else { - None }; let put_end = match inner .put_end_with_local_cache_publish(&req.key, put_id, req.lease_id, publish_local_cache) @@ -1686,46 +1725,43 @@ impl HandlerForExternalClient for ClientKvApi { let put_end_stats = put_end.stats; let put_end_total_us = duration_to_i64_us(end_started_at.elapsed()); - if publish_local_cache { - let Some(holder_id) = put_end.local_cache_holder_id else { - let err = KvError::Api(ApiError::Unknown { - detail: format!( - "external_put_transfer_end missing local cache holder after local commit: key={} put_id=({},{})", - req.key, put_id.0, put_id.1 - ), - }); - inner - .external_pending_puts - .invalidate(&(req.key.clone(), put_id.0, put_id.1)); - return Ok(crate::rpcresp_kvresult_convert::FromError::from_error(&err)); - }; - let publish = local_cache_publish - .as_ref() - .expect("publish_local_cache precheck must provide local cache publish info"); + let Some(holder_id) = put_end.local_cache_holder_id else { + let err = KvError::Api(ApiError::Unknown { + detail: format!( + "external_put_transfer_end missing local cache holder after local commit: key={} put_id=({},{})", + req.key, put_id.0, put_id.1 + ), + }); inner - .install_local_committed_memory_info( - &req.key, - put_id, - publish.src_offset, - publish.len, - holder_id, - ) - .await?; - } + .external_pending_puts + .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + return Ok(crate::rpcresp_kvresult_convert::FromError::from_error(&err)); + }; + inner + .install_local_committed_memory_info( + &req.key, + put_id, + local_cache_publish.src_offset, + local_cache_publish.len, + holder_id, + ) + .await?; inner .external_pending_puts .invalidate(&(req.key.clone(), put_id.0, put_id.1)); - if !req.write_through && (has_remote_append || req_remote_target) { + if admitted_replica_task && replica_target.is_some() { if let Err(err) = inner - .enqueue_write_back_remote_append( + .make_replica_task( &req.key, put_id, - preferred_sub_cluster.as_deref(), + replica_target + .clone() + .expect("make_replica_task requires pre-reserved replica target"), ) .await { tracing::warn!( - "write-back external_put_transfer_end enqueue failed after local commit: key={} put_id=({},{}) err={}", + "external_put_transfer_end make replica task failed after local commit: key={} put_id=({},{}) err={}", req.key, put_id.0, put_id.1, @@ -1784,18 +1820,15 @@ impl HandlerForExternalClient for ClientKvApi { lease_id: Option, len: u64, put_locality: Option<(bool, i64)>, - remember_local_snapshot: bool, - publish_local_cache: bool, - local_cache_publish: Option, - enqueue_write_back_append: bool, - preferred_sub_cluster: Option, + local_cache_publish: LocalCommittedCachePublish, + make_replica_task: bool, + replica_target: Option, } let mut results: Vec> = (0..req.items.len()).map(|_| None).collect(); let mut done_pending = Vec::new(); let mut revoke_pending = Vec::new(); - let mut transfer_futures = Vec::new(); for (idx, item) in req.items.into_iter().enumerate() { let Some(put_id) = item.put_id else { @@ -1815,17 +1848,77 @@ impl HandlerForExternalClient for ClientKvApi { .external_pending_puts .get(&(item.key.clone(), put_id.0, put_id.1)) .map(|ctx| ctx.clone()); - let preferred_sub_cluster = pending_ctx - .as_ref() - .and_then(|ctx| ctx.preferred_sub_cluster.clone()); + if let Some(ctx) = pending_ctx.as_ref() { + if ctx.local_reserve_slot.is_some() { + if item.peer_id.is_some() { + let err = KvError::Api(ApiError::InvalidArgument { + detail: format!( + "external_batch_put_transfer_end local-first item must be local target: key={} put_id=({},{})", + item.key, put_id.0, put_id.1 + ), + }); + results[idx] = Some(ExternalBatchPutTransferEndItemResp::from_error(&err)); + inner.external_pending_puts.invalidate(&( + item.key.clone(), + put_id.0, + put_id.1, + )); + inner.release_external_local_first_put_key(&item.key); + continue; + } + match commit_external_local_first_pending( + inner, + &item.key, + put_id, + ctx, + item.src_offset, + item.len, + "external_batch_put_transfer_end", + ) + .await + { + Ok(committed_slot) => { + inner.record_put_locality(false, item.len, 0); + inner.external_pending_puts.invalidate(&( + item.key.clone(), + put_id.0, + put_id.1, + )); + inner.release_external_local_first_put_key(&item.key); + spawn_external_local_first_publish( + inner, + item.key.clone(), + put_id, + item.lease_id, + committed_slot, + ); + results[idx] = Some(ExternalBatchPutTransferEndItemResp { + error_code: OK, + error_json: String::new(), + }); + } + Err(err) => { + inner.external_pending_puts.invalidate(&( + item.key.clone(), + put_id.0, + put_id.1, + )); + inner.release_external_local_first_put_key(&item.key); + results[idx] = + Some(ExternalBatchPutTransferEndItemResp::from_error(&err)); + } + } + continue; + } + } let has_remote_append = pending_ctx .as_ref() .and_then(|ctx| ctx.peer_id.as_ref()) .is_some(); - if item.peer_id.is_some() != has_remote_append { + if item.peer_id.is_some() || has_remote_append { let err = KvError::Api(ApiError::InvalidArgument { detail: format!( - "external_batch_put_transfer_end peer_id mismatches pending ctx: key={} put_id=({},{}) req_remote_target={} ctx_remote_target={}", + "external_batch_put_transfer_end remote primary target is no longer supported: key={} put_id=({},{}) req_remote_target={} ctx_remote_target={}", item.key, put_id.0, put_id.1, @@ -1843,193 +1936,49 @@ impl HandlerForExternalClient for ClientKvApi { .invalidate(&(item.key.clone(), put_id.0, put_id.1)); continue; } - let remember_local_snapshot = !item.write_through || item.peer_id.is_none(); - let publish_local_cache = remember_local_snapshot; - let enqueue_write_back_append = !item.write_through && item.peer_id.is_some(); - let local_cache_publish = if publish_local_cache { - match local_committed_cache_publish( - "external_batch_put_transfer_end", - &item.key, - put_id, - pending_ctx.as_ref(), - item.src_offset, - item.len, - ) { - Ok(publish) => Some(publish), - Err(err) => { - results[idx] = Some(ExternalBatchPutTransferEndItemResp::from_error(&err)); - revoke_pending.push(BatchPutRevokeItemReq { - key: item.key.clone(), - put_id, - }); - inner.external_pending_puts.invalidate(&( - item.key.clone(), - put_id.0, - put_id.1, - )); - continue; - } - } - } else { - None - }; - - let transfer_args = if let Some(peer) = item.peer_id.clone() { - match pending_ctx.as_ref() { - Some(ctx) if ctx.peer_id.is_some() => { - Ok((ctx.peer_id.clone(), ctx.target_offset, Some(ctx.target_base_addr))) - } - None => match item.target_base_addr { - Some(target_base_addr) => { - Ok((Some(peer.into()), item.target_offset, Some(target_base_addr))) - } - None => Err(KvError::Unreachable( - crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::RpcDecodeError { - rpc_input_json: format!( - "missing pending remote put ctx and caller target_base_addr in external_batch_put_transfer_end; key={}, put_id=({},{}), peer_id={}", - item.key, put_id.0, put_id.1, peer - ), - }, - )), - }, - Some(_) => match item.target_base_addr { - Some(target_base_addr) => { - Ok((Some(peer.into()), item.target_offset, Some(target_base_addr))) - } - None => Err(KvError::Unreachable( - crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::RpcDecodeError { - rpc_input_json: format!( - "pending local ctx conflicted with remote external_batch_put_transfer_end; key={}, put_id=({},{}), peer_id={}", - item.key, put_id.0, put_id.1, peer - ), - }, - )), - }, - } - } else { - Ok((None, item.target_offset, None)) - }; - let (peer_id_for_transfer, target_off_for_transfer, target_base_for_transfer) = - match transfer_args { - Ok(v) => v, - Err(err) => { - results[idx] = Some(ExternalBatchPutTransferEndItemResp::from_error(&err)); - continue; - } - }; - - if !item.write_through { - done_pending.push(DonePending { - idx, - key: item.key, - put_id, - lease_id: item.lease_id, - len: item.len, - put_locality: Some((false, 0)), - remember_local_snapshot, - publish_local_cache, - local_cache_publish, - enqueue_write_back_append, - preferred_sub_cluster, - }); - continue; - } - - transfer_futures.push(async move { - let transfer_started_at = Instant::now(); - let transfer_result = inner - .put_transfer( - &item.key, - put_id, - item.src_offset, - target_off_for_transfer, - item.len, - peer_id_for_transfer, - target_base_for_transfer, - ) - .await; - ( - idx, - item.key, - item.len, - put_id, - item.lease_id, - remember_local_snapshot, - publish_local_cache, - local_cache_publish, - preferred_sub_cluster, - duration_to_i64_us(transfer_started_at.elapsed()), - transfer_result, - ) - }); - } - - let transfer_concurrency = req.transfer_concurrency.max(1); - let mut transfer_stream = - stream::iter(transfer_futures).buffer_unordered(transfer_concurrency); - while let Some(joined) = transfer_stream.next().await { - match joined { - ( - idx, - key, - len, - put_id, - lease_id, - remember_local_snapshot, - publish_local_cache, - local_cache_publish, - preferred_sub_cluster, - wall_transfer_us, - Ok(breakdown), - ) => { - let breakdown_transfer_us = breakdown.submit_blocking_us - + breakdown.create_xfer_req_us - + breakdown.post_xfer_req_us - + breakdown.poll_wait_us; - let transfer_us = breakdown_transfer_us.max(wall_transfer_us); - done_pending.push(DonePending { - idx, - key, - put_id, - lease_id, - len, - put_locality: Some((breakdown.remote_transfer, transfer_us)), - remember_local_snapshot, - publish_local_cache, - local_cache_publish, - enqueue_write_back_append: false, - preferred_sub_cluster, - }); - } - ( - idx, - key, - _len, - put_id, - _lease_id, - _remember_local_snapshot, - _publish_local_cache, - _local_cache_publish, - _preferred_sub_cluster, - _wall_transfer_us, - Err(err), - ) => { + let local_cache_publish = match local_committed_cache_publish( + "external_batch_put_transfer_end", + &item.key, + put_id, + pending_ctx.as_ref(), + item.src_offset, + item.len, + ) { + Ok(publish) => publish, + Err(err) => { results[idx] = Some(ExternalBatchPutTransferEndItemResp::from_error(&err)); revoke_pending.push(BatchPutRevokeItemReq { - key: key.clone(), + key: item.key.clone(), put_id, }); inner .external_pending_puts - .invalidate(&(key, put_id.0, put_id.1)); + .invalidate(&(item.key.clone(), put_id.0, put_id.1)); + continue; } - } + }; + done_pending.push(DonePending { + idx, + key: item.key, + put_id, + lease_id: item.lease_id, + len: item.len, + put_locality: Some((false, 0)), + local_cache_publish, + make_replica_task: pending_ctx + .as_ref() + .map(|ctx| ctx.make_replica_task) + .unwrap_or(false), + replica_target: pending_ctx + .as_ref() + .and_then(|ctx| ctx.replica_target.clone()), + }); } if !revoke_pending.is_empty() { if let Err(err) = inner.batch_put_revoke(revoke_pending).await { tracing::warn!( - "external_batch_put_transfer_end batch_put_revoke failed after transfer errors: {}", + "external_batch_put_transfer_end batch_put_revoke failed after precheck errors: {}", err ); } @@ -2074,7 +2023,7 @@ impl HandlerForExternalClient for ClientKvApi { put_id: pending.put_id, lease_id: pending.lease_id, committed_slot: None, - publish_local_cache: pending.publish_local_cache, + publish_local_cache: true, }) .collect(), ) @@ -2105,42 +2054,34 @@ impl HandlerForExternalClient for ClientKvApi { if let Some((remote, transfer_us)) = pending.put_locality { inner.record_put_locality(remote, pending.len, transfer_us); } - if pending.publish_local_cache { - let Some(holder_id) = done_item.local_cache_holder_id else { - return Err(KvError::Api(ApiError::Unknown { - detail: format!( - "external_batch_put_transfer_end missing local cache holder after local commit: key={} put_id=({},{})", - pending.key, pending.put_id.0, pending.put_id.1 - ), - })); - }; - let publish = pending - .local_cache_publish - .as_ref() - .expect("publish_local_cache precheck must provide local cache publish info"); - inner - .install_local_committed_memory_info( - &pending.key, - pending.put_id, - publish.src_offset, - publish.len, - holder_id, - ) - .await?; - } else if pending.remember_local_snapshot { - inner.remember_local_snapshot(&pending.key, pending.put_id); - } - if pending.enqueue_write_back_append { + let Some(holder_id) = done_item.local_cache_holder_id else { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external_batch_put_transfer_end missing local cache holder after local commit: key={} put_id=({},{})", + pending.key, pending.put_id.0, pending.put_id.1 + ), + })); + }; + inner + .install_local_committed_memory_info( + &pending.key, + pending.put_id, + pending.local_cache_publish.src_offset, + pending.local_cache_publish.len, + holder_id, + ) + .await?; + if pending.make_replica_task { + let target = pending + .replica_target + .clone() + .expect("make_replica_task requires pre-reserved replica target"); if let Err(err) = inner - .enqueue_write_back_remote_append( - &pending.key, - pending.put_id, - pending.preferred_sub_cluster.as_deref(), - ) + .make_replica_task(&pending.key, pending.put_id, target) .await { tracing::warn!( - "external_batch_put_transfer_end write-back enqueue failed after local commit: key={} put_id=({},{}) err={}", + "external_batch_put_transfer_end make replica task failed after local commit: key={} put_id=({},{}) err={}", pending.key, pending.put_id.0, pending.put_id.1, @@ -2190,18 +2131,53 @@ impl HandlerForExternalClient for ClientKvApi { .external_pending_puts .get(&(req.key.clone(), put_id.0, put_id.1)) .map(|ctx| ctx.clone()); - if let Some(ctx) = pending_ctx.as_ref() { - let has_remote_append = ctx.peer_id.is_some(); - if req.remote_target != has_remote_append { - let err = KvError::Api(ApiError::InvalidArgument { - detail: format!( - "external_put_commit remote_target mismatches pending ctx: key={} put_id=({},{}) req_remote_target={} ctx_remote_target={}", - req.key, put_id.0, put_id.1, req.remote_target, has_remote_append - ), - }); + let has_remote_append = pending_ctx + .as_ref() + .and_then(|ctx| ctx.peer_id.as_ref()) + .is_some(); + if req.remote_target || has_remote_append { + let err = KvError::Api(ApiError::InvalidArgument { + detail: format!( + "external_put_commit remote primary target is no longer supported: key={} put_id=({},{}) req_remote_target={} ctx_remote_target={}", + req.key, put_id.0, put_id.1, req.remote_target, has_remote_append + ), + }); + if let Err(revoke_err) = inner.put_revoke(&req.key, put_id).await { + tracing::warn!( + "external_put_commit put_revoke failed after remote primary target: key={} put_id=({},{}) err={}", + req.key, + put_id.0, + put_id.1, + revoke_err + ); + } + inner + .external_pending_puts + .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + return Ok(ExternalPutCommitResp::from_error(&err)); + } + let replica_target = pending_ctx + .as_ref() + .and_then(|ctx| ctx.replica_target.clone()); + let admitted_replica_task = pending_ctx + .as_ref() + .map(|ctx| ctx.make_replica_task) + .unwrap_or(false); + + let end_started_at = Instant::now(); + let local_cache_publish = match local_committed_cache_publish( + "external_put_commit", + &req.key, + put_id, + pending_ctx.as_ref(), + req.src_offset, + req.len, + ) { + Ok(publish) => publish, + Err(err) => { if let Err(revoke_err) = inner.put_revoke(&req.key, put_id).await { tracing::warn!( - "external_put_commit put_revoke failed after remote_target mismatch: key={} put_id=({},{}) err={}", + "external_put_commit put_revoke failed after local cache publish precheck error: key={} put_id=({},{}) err={}", req.key, put_id.0, put_id.1, @@ -2213,46 +2189,9 @@ impl HandlerForExternalClient for ClientKvApi { .invalidate(&(req.key.clone(), put_id.0, put_id.1)); return Ok(ExternalPutCommitResp::from_error(&err)); } - } - let remember_local_snapshot = !req.write_through || !req.remote_target; - let enqueue_write_back_append = !req.write_through && req.remote_target; - let preferred_sub_cluster = pending_ctx - .as_ref() - .and_then(|ctx| ctx.preferred_sub_cluster.clone()); - - let end_started_at = Instant::now(); - let publish_local_cache = remember_local_snapshot; - let local_cache_publish = if publish_local_cache { - match local_committed_cache_publish( - "external_put_commit", - &req.key, - put_id, - pending_ctx.as_ref(), - req.src_offset, - req.len, - ) { - Ok(publish) => Some(publish), - Err(err) => { - if let Err(revoke_err) = inner.put_revoke(&req.key, put_id).await { - tracing::warn!( - "external_put_commit put_revoke failed after local cache publish precheck error: key={} put_id=({},{}) err={}", - req.key, - put_id.0, - put_id.1, - revoke_err - ); - } - inner - .external_pending_puts - .invalidate(&(req.key.clone(), put_id.0, put_id.1)); - return Ok(ExternalPutCommitResp::from_error(&err)); - } - } - } else { - None }; let put_end = match inner - .put_end_with_local_cache_publish(&req.key, put_id, req.lease_id, publish_local_cache) + .put_end_with_local_cache_publish(&req.key, put_id, req.lease_id, true) .await { Ok(end) => end, @@ -2265,46 +2204,43 @@ impl HandlerForExternalClient for ClientKvApi { }; let put_end_stats = put_end.stats; let put_end_total_us = duration_to_i64_us(end_started_at.elapsed()); - if publish_local_cache { - let Some(holder_id) = put_end.local_cache_holder_id else { - let err = KvError::Api(ApiError::Unknown { - detail: format!( - "external_put_commit missing local cache holder after local commit: key={} put_id=({},{})", - req.key, put_id.0, put_id.1 - ), - }); - inner - .external_pending_puts - .invalidate(&(req.key.clone(), put_id.0, put_id.1)); - return Ok(ExternalPutCommitResp::from_error(&err)); - }; - let publish = local_cache_publish - .as_ref() - .expect("publish_local_cache precheck must provide local cache publish info"); + let Some(holder_id) = put_end.local_cache_holder_id else { + let err = KvError::Api(ApiError::Unknown { + detail: format!( + "external_put_commit missing local cache holder after local commit: key={} put_id=({},{})", + req.key, put_id.0, put_id.1 + ), + }); inner - .install_local_committed_memory_info( - &req.key, - put_id, - publish.src_offset, - publish.len, - holder_id, - ) - .await?; - } + .external_pending_puts + .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + return Ok(ExternalPutCommitResp::from_error(&err)); + }; + inner + .install_local_committed_memory_info( + &req.key, + put_id, + local_cache_publish.src_offset, + local_cache_publish.len, + holder_id, + ) + .await?; inner .external_pending_puts .invalidate(&(req.key.clone(), put_id.0, put_id.1)); - if enqueue_write_back_append { + if admitted_replica_task && replica_target.is_some() { if let Err(err) = inner - .enqueue_write_back_remote_append( + .make_replica_task( &req.key, put_id, - preferred_sub_cluster.as_deref(), + replica_target + .clone() + .expect("make_replica_task requires pre-reserved replica target"), ) .await { tracing::warn!( - "write-back external_put_commit enqueue failed after local commit: key={} put_id=({},{}) err={}", + "external_put_commit make replica task failed after local commit: key={} put_id=({},{}) err={}", req.key, put_id.0, put_id.1, @@ -2354,11 +2290,9 @@ impl HandlerForExternalClient for ClientKvApi { key: String, put_id: crate::master_kv_router::put::PutIDForAKey, lease_id: Option, - remember_local_snapshot: bool, - publish_local_cache: bool, - local_cache_publish: Option, - enqueue_write_back_append: bool, - preferred_sub_cluster: Option, + local_cache_publish: LocalCommittedCachePublish, + make_replica_task: bool, + replica_target: Option, } let mut results: Vec> = @@ -2384,14 +2318,98 @@ impl HandlerForExternalClient for ClientKvApi { .get(&(item.key.clone(), put_id.0, put_id.1)) .map(|ctx| ctx.clone()); if let Some(ctx) = pending_ctx.as_ref() { - let has_remote_append = ctx.peer_id.is_some(); - if item.remote_target != has_remote_append { - let err = KvError::Api(ApiError::InvalidArgument { - detail: format!( - "external_batch_put_commit remote_target mismatches pending ctx: key={} put_id=({},{}) req_remote_target={} ctx_remote_target={}", - item.key, put_id.0, put_id.1, item.remote_target, has_remote_append - ), - }); + if ctx.local_reserve_slot.is_some() { + if item.remote_target { + let err = KvError::Api(ApiError::InvalidArgument { + detail: format!( + "external_batch_put_commit local-first item must be local target: key={} put_id=({},{})", + item.key, put_id.0, put_id.1 + ), + }); + results[idx] = Some(ExternalBatchPutCommitItemResp::from_error(&err)); + inner.external_pending_puts.invalidate(&( + item.key.clone(), + put_id.0, + put_id.1, + )); + inner.release_external_local_first_put_key(&item.key); + continue; + } + match commit_external_local_first_pending( + inner, + &item.key, + put_id, + ctx, + item.src_offset, + item.len, + "external_batch_put_commit", + ) + .await + { + Ok(committed_slot) => { + inner.record_put_locality(false, item.len, 0); + inner.external_pending_puts.invalidate(&( + item.key.clone(), + put_id.0, + put_id.1, + )); + inner.release_external_local_first_put_key(&item.key); + spawn_external_local_first_publish( + inner, + item.key.clone(), + put_id, + item.lease_id, + committed_slot, + ); + results[idx] = Some(ExternalBatchPutCommitItemResp { + error_code: OK, + error_json: String::new(), + }); + } + Err(err) => { + inner.external_pending_puts.invalidate(&( + item.key.clone(), + put_id.0, + put_id.1, + )); + inner.release_external_local_first_put_key(&item.key); + results[idx] = Some(ExternalBatchPutCommitItemResp::from_error(&err)); + } + } + continue; + } + } + let has_remote_append = pending_ctx + .as_ref() + .and_then(|ctx| ctx.peer_id.as_ref()) + .is_some(); + if item.remote_target || has_remote_append { + let err = KvError::Api(ApiError::InvalidArgument { + detail: format!( + "external_batch_put_commit remote primary target is no longer supported: key={} put_id=({},{}) req_remote_target={} ctx_remote_target={}", + item.key, put_id.0, put_id.1, item.remote_target, has_remote_append + ), + }); + results[idx] = Some(ExternalBatchPutCommitItemResp::from_error(&err)); + revoke_pending.push(BatchPutRevokeItemReq { + key: item.key.clone(), + put_id, + }); + inner + .external_pending_puts + .invalidate(&(item.key.clone(), put_id.0, put_id.1)); + continue; + }; + let local_cache_publish = match local_committed_cache_publish( + "external_batch_put_commit", + &item.key, + put_id, + pending_ctx.as_ref(), + item.src_offset, + item.len, + ) { + Ok(publish) => publish, + Err(err) => { results[idx] = Some(ExternalBatchPutCommitItemResp::from_error(&err)); revoke_pending.push(BatchPutRevokeItemReq { key: item.key.clone(), @@ -2402,49 +2420,20 @@ impl HandlerForExternalClient for ClientKvApi { .invalidate(&(item.key.clone(), put_id.0, put_id.1)); continue; } - } - let remember_local_snapshot = !item.write_through || !item.remote_target; - let publish_local_cache = remember_local_snapshot; - let local_cache_publish = if publish_local_cache { - match local_committed_cache_publish( - "external_batch_put_commit", - &item.key, - put_id, - pending_ctx.as_ref(), - item.src_offset, - item.len, - ) { - Ok(publish) => Some(publish), - Err(err) => { - results[idx] = Some(ExternalBatchPutCommitItemResp::from_error(&err)); - revoke_pending.push(BatchPutRevokeItemReq { - key: item.key.clone(), - put_id, - }); - inner.external_pending_puts.invalidate(&( - item.key.clone(), - put_id.0, - put_id.1, - )); - continue; - } - } - } else { - None }; - let preferred_sub_cluster = pending_ctx - .as_ref() - .and_then(|ctx| ctx.preferred_sub_cluster.clone()); done_pending.push(DonePending { idx, key: item.key.clone(), put_id, lease_id: item.lease_id, - remember_local_snapshot, - publish_local_cache, local_cache_publish, - enqueue_write_back_append: !item.write_through && item.remote_target, - preferred_sub_cluster, + make_replica_task: pending_ctx + .as_ref() + .map(|ctx| ctx.make_replica_task) + .unwrap_or(false), + replica_target: pending_ctx + .as_ref() + .and_then(|ctx| ctx.replica_target.clone()), }); } @@ -2493,7 +2482,7 @@ impl HandlerForExternalClient for ClientKvApi { put_id: pending.put_id, lease_id: pending.lease_id, committed_slot: None, - publish_local_cache: pending.publish_local_cache, + publish_local_cache: true, }) .collect(), ) @@ -2521,42 +2510,34 @@ impl HandlerForExternalClient for ClientKvApi { results[pending.idx] = Some(ExternalBatchPutCommitItemResp::from_error(&err)); continue; } - if pending.publish_local_cache { - let Some(holder_id) = done_item.local_cache_holder_id else { - return Err(KvError::Api(ApiError::Unknown { - detail: format!( - "external_batch_put_commit missing local cache holder after local commit: key={} put_id=({},{})", - pending.key, pending.put_id.0, pending.put_id.1 - ), - })); - }; - let publish = pending - .local_cache_publish - .as_ref() - .expect("publish_local_cache precheck must provide local cache publish info"); - inner - .install_local_committed_memory_info( - &pending.key, - pending.put_id, - publish.src_offset, - publish.len, - holder_id, - ) - .await?; - } else if pending.remember_local_snapshot { - inner.remember_local_snapshot(&pending.key, pending.put_id); - } - if pending.enqueue_write_back_append { + let Some(holder_id) = done_item.local_cache_holder_id else { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external_batch_put_commit missing local cache holder after local commit: key={} put_id=({},{})", + pending.key, pending.put_id.0, pending.put_id.1 + ), + })); + }; + inner + .install_local_committed_memory_info( + &pending.key, + pending.put_id, + pending.local_cache_publish.src_offset, + pending.local_cache_publish.len, + holder_id, + ) + .await?; + if pending.make_replica_task { + let target = pending + .replica_target + .clone() + .expect("make_replica_task requires pre-reserved replica target"); if let Err(err) = inner - .enqueue_write_back_remote_append( - &pending.key, - pending.put_id, - pending.preferred_sub_cluster.as_deref(), - ) + .make_replica_task(&pending.key, pending.put_id, target) .await { tracing::warn!( - "external_batch_put_commit write-back enqueue failed after local commit: key={} put_id=({},{}) err={}", + "external_batch_put_commit make replica task failed after local commit: key={} put_id=({},{}) err={}", pending.key, pending.put_id.0, pending.put_id.1, @@ -2602,9 +2583,32 @@ impl HandlerForExternalClient for ClientKvApi { ); return Ok(ExternalPutRevokeResp::from_error(&err)); }; + let pending_ctx = inner + .external_pending_puts + .get(&(req.key.clone(), put_id.0, put_id.1)) + .map(|ctx| ctx.clone()); inner .external_pending_puts .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + if let Some(ctx) = pending_ctx { + if let (Some(slot_ref), Some(slot_size)) = + (ctx.local_reserve_slot, ctx.local_reserve_slot_size) + { + inner.release_external_local_first_put_key(&req.key); + let lease = client_kv_api::OwnerLocalReserveSlotLease { + value_len: ctx.len, + slot_size, + slots: vec![slot_ref], + }; + return match inner.owner_release_local_reserve_slot_lease(lease).await { + Ok(_) => Ok(ExternalPutRevokeResp { + error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, + error_json: String::new(), + }), + Err(e) => Ok(ExternalPutRevokeResp::from_error(&e)), + }; + } + } match inner.put_revoke(&req.key, put_id).await { Ok(_) => Ok(ExternalPutRevokeResp { error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs index 7f723f0..544d5e6 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs @@ -31,8 +31,8 @@ use crate::{ client_seg_pool::{ClientSegPool, ClientSegPoolAccessTrait, ResolveSideTransferLaneReq}, client_transfer_engine::{ClientTransferEngine, ClientTransferEngineAccessTrait}, cluster_manager::{ - app_logic_ext::{ClusterManagerAppLogicExt, ClusterManagerExtError}, ClusterEvent, ClusterManager, ClusterManagerAccessTrait, + app_logic_ext::{ClusterManagerAppLogicExt, ClusterManagerExtError}, }, master_kv_router::msg_pack::{ DeleteAckReq, DeleteReq, GetDoneReq, GetMetaReq, GetRevokeReq, GetStartReq, @@ -50,19 +50,23 @@ use crate::{ use async_trait::async_trait; use crossbeam::queue::SegQueue; use dashmap::DashMap; -use fluxon_framework::{define_module, LogicalModule}; +use fluxon_framework::{LogicalModule, define_module}; use fluxon_framework_compiled::upgrade_view_guard::UpgradeViewGuard; use fluxon_util::map_lock::AMapLock; use limit_thirdparty::tokio; use parking_lot::{Mutex, RwLock}; use std::collections::HashMap; use std::collections::HashSet; -use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Weak; +use std::sync::atomic::{AtomicU32, AtomicU64, Ordering}; use std::sync::{Arc, OnceLock}; -use std::time::{Duration, Instant}; +use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; use tracing::warn; +const REPLICA_TASK_QUEUE_CAPACITY: usize = 128; +const OWNER_LOCAL_PUBLISH_QUEUE_CAPACITY: usize = 4096; +const OWNER_LOCAL_PUBLISH_MAX_INFLIGHT: usize = 64; + /// Information about a memholder held by external client #[derive(Clone)] pub struct ExternalHoldingGetInfo { @@ -79,7 +83,7 @@ pub struct OwnerRuntimeObserveSnapshot { } pub use get::RemoteGetInfo; -pub use put::OwnerReservedPutItem; +pub use put::{OwnerLocalPublishItem, OwnerLocalPublishJob, OwnerReservedPutItem}; pub mod external_api; mod local_reserve_rebalance; pub use external_api::HandlerForExternalClient; @@ -181,8 +185,8 @@ pub enum PutOptionalArg { RejectIfInflightSameKey, /// Ask the master to fail-fast when the key already has a committed live replica. RejectIfExistSameKey, - /// Keep the legacy synchronous remote-placement semantics. - WriteThrough, + /// Disable asynchronous remote replica task after local commit in write-back mode. + SkipMakeReplicaTask, /// Prefer placing the target allocation on a kvclient within this sub_cluster. PreferredSubCluster(String), /// Hidden test-only side-channel for collecting per-put phase timings. @@ -203,7 +207,7 @@ impl PutOptionalArgs { PutOptionalArg::LeaseId(id) => Some(*id), PutOptionalArg::RejectIfInflightSameKey | PutOptionalArg::RejectIfExistSameKey - | PutOptionalArg::WriteThrough + | PutOptionalArg::SkipMakeReplicaTask | PutOptionalArg::PreferredSubCluster(_) | PutOptionalArg::TestObservePutPhases(_) => None, }) @@ -221,10 +225,11 @@ impl PutOptionalArgs { .any(|arg| matches!(arg, PutOptionalArg::RejectIfExistSameKey)) } - pub fn write_through(&self) -> bool { - self.0 + pub fn make_replica_task(&self) -> bool { + !self + .0 .iter() - .any(|arg| matches!(arg, PutOptionalArg::WriteThrough)) + .any(|arg| matches!(arg, PutOptionalArg::SkipMakeReplicaTask)) } /// Get the last provided preferred_sub_cluster if any. @@ -234,7 +239,7 @@ impl PutOptionalArgs { PutOptionalArg::LeaseId(_) | PutOptionalArg::RejectIfInflightSameKey | PutOptionalArg::RejectIfExistSameKey - | PutOptionalArg::WriteThrough + | PutOptionalArg::SkipMakeReplicaTask | PutOptionalArg::TestObservePutPhases(_) => None, }) } @@ -245,7 +250,7 @@ impl PutOptionalArgs { PutOptionalArg::LeaseId(_) | PutOptionalArg::RejectIfInflightSameKey | PutOptionalArg::RejectIfExistSameKey - | PutOptionalArg::WriteThrough + | PutOptionalArg::SkipMakeReplicaTask | PutOptionalArg::PreferredSubCluster(_) => None, }) } @@ -1140,6 +1145,14 @@ impl ClientKvApiViewHolder { } } +fn now_unix_ms() -> u64 { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_millis() + .min(u64::MAX as u128) as u64 +} + impl std::ops::Deref for ClientKvApiViewHolder { type Target = ClientKvApiView; @@ -1168,6 +1181,10 @@ pub struct ClientKvApiInner { owner_local_reserve_pool: Mutex, /// Wake the background reserve actor after demand/free-slot changes. owner_local_reserve_rebalance_notify: Arc, + /// Owner-local write-back put ids for external local-first path. + external_local_first_put_id_counter: AtomicU32, + /// Owner-local inflight write guard for external local-first path. + external_local_first_inflight_key_counts: DashMap, /// Shared delete actor input for owner -> external weak-index invalidation. pub external_invalidate_delete: EnsureMemholderMgmtDeleteHandle, @@ -1229,8 +1246,10 @@ pub struct ClientKvApiInner { /// 注意:put_id (time_ms,version) 在不同 key 上并不全局唯一,因此必须携带 key 作为索引的一部分,避免碰撞。 /// 使用 moka::sync::SegmentedCache 并设置 30 分钟 TTL,避免异常路径未清理导致的泄漏;不设置容量上限,纯 TTL 控制。 external_pending_puts: moka::sync::SegmentedCache<(String, u64, u32), ExternalPendingPutCtx>, - write_back_append_tx: tokio::sync::ampsc::Sender, - write_back_append_rx: Mutex>>, + owner_local_publish_tx: tokio::sync::ampsc::Sender, + owner_local_publish_rx: Mutex>>, + replica_task_tx: tokio::sync::ampsc::Sender, + replica_task_rx: Mutex>>, } impl ClientKvApiInner { @@ -1265,6 +1284,73 @@ impl ClientKvApiInner { self.test_spec_config.skip_put_end_commit } + pub(crate) fn next_external_local_first_put_id( + &self, + ) -> crate::master_kv_router::put::PutIDForAKey { + ( + now_unix_ms(), + self.external_local_first_put_id_counter + .fetch_add(1, Ordering::Relaxed), + ) + } + + pub fn next_owner_local_first_put_id(&self) -> crate::master_kv_router::put::PutIDForAKey { + self.next_external_local_first_put_id() + } + + pub async fn enqueue_owner_local_publish(&self, job: OwnerLocalPublishJob) -> KvResult<()> { + let key_count = job.items.len(); + let first_key = job + .items + .first() + .map(|item| item.key.as_str()) + .unwrap_or("") + .to_string(); + self.owner_local_publish_tx.try_send(job).map_err(|err| { + KvError::Api(ApiError::Unknown { + detail: format!( + "owner local publish queue is full or closed: first_key={} key_count={} err={}", + first_key, key_count, err + ), + }) + }) + } + + pub(crate) fn reserve_external_local_first_put_key( + &self, + key: &str, + reject_if_inflight_same_key: bool, + reject_if_exist_same_key: bool, + ) -> KvResult<()> { + if reject_if_exist_same_key && self.has_local_snapshot(key) { + return Err(KvError::Api(ApiError::KeyAlreadyExists { + key: key.to_string(), + })); + } + let mut entry = self + .external_local_first_inflight_key_counts + .entry(key.to_string()) + .or_insert(0); + if reject_if_inflight_same_key && *entry > 0 { + return Err(KvError::Api(ApiError::KeyBeingWritten { + key: key.to_string(), + })); + } + *entry += 1; + Ok(()) + } + + pub(crate) fn release_external_local_first_put_key(&self, key: &str) { + if let Some(mut entry) = self.external_local_first_inflight_key_counts.get_mut(key) { + if *entry <= 1 { + drop(entry); + self.external_local_first_inflight_key_counts.remove(key); + } else { + *entry -= 1; + } + } + } + pub(crate) fn remember_local_snapshot( &self, key: &str, @@ -1461,14 +1547,27 @@ pub struct ExternalPendingPutCtx { pub target_base_addr: u64, pub target_offset: u64, pub len: u64, + pub make_replica_task: bool, pub preferred_sub_cluster: Option, + pub replica_target: Option, + pub local_reserve_slot: Option, + pub local_reserve_slot_size: Option, +} + +#[derive(Debug, Clone)] +pub(crate) struct ReplicaTaskTarget { + pub node_id: String, + pub target_offset: u64, + pub target_base_addr: u64, + pub len: u64, } #[derive(Clone)] -pub(crate) struct WriteBackAppendJob { +pub(crate) struct ReplicaTaskJob { pub key: String, pub put_id: crate::master_kv_router::put::PutIDForAKey, pub holder: Arc, + pub target: Option, pub preferred_sub_cluster: Option, } @@ -2473,7 +2572,10 @@ impl ClientKvApi { pub async fn construct(arg: ClientKvApiNewArg) -> Result { tracing::info!("Constructing ClientKvApi in Client mode (PreView)"); - let (write_back_append_tx, write_back_append_rx) = tokio::sync::ampsc::channel(1024); + let (replica_task_tx, replica_task_rx) = + tokio::sync::ampsc::channel(REPLICA_TASK_QUEUE_CAPACITY); + let (owner_local_publish_tx, owner_local_publish_rx) = + tokio::sync::ampsc::channel(OWNER_LOCAL_PUBLISH_QUEUE_CAPACITY); let inner = ClientKvApiInner { view: ClientKvApiViewHolder::new(), @@ -2488,6 +2590,8 @@ impl ClientKvApi { owner_local_reserve_rebalance_notify: Arc::new( limit_thirdparty::tokio::sync::Notify::new(), ), + external_local_first_put_id_counter: AtomicU32::new(0), + external_local_first_inflight_key_counts: DashMap::new(), external_invalidate_delete: EnsureMemholderMgmtDeleteHandle::new( OwnerExternalMemMgr::DELETE_SUBMIT_QUEUE_CAPACITY, ), @@ -2534,8 +2638,10 @@ impl ClientKvApi { rpc_caller_external_put_revoke: RPCCaller::new(), rpc_caller_resolve_side_transfer_lane: RPCCaller::new(), default_lease_id: parking_lot::RwLock::new(None), - write_back_append_tx, - write_back_append_rx: Mutex::new(Some(write_back_append_rx)), + owner_local_publish_tx, + owner_local_publish_rx: Mutex::new(Some(owner_local_publish_rx)), + replica_task_tx, + replica_task_rx: Mutex::new(Some(replica_task_rx)), }; Ok(Self(inner)) } @@ -2925,10 +3031,19 @@ impl ClientKvApi { .expect("delete_ack_batch rx already taken, that's impossible"); delete::spawn_owner_delete_ack_batch(inner.view.clone_view(), delete_ack_batch_rx); - if let Some(write_back_append_rx) = inner.write_back_append_rx.lock().take() { - put::spawn_write_back_append_actor(inner.view.clone_view(), write_back_append_rx); + if let Some(replica_task_rx) = inner.replica_task_rx.lock().take() { + put::spawn_replica_task_actor(inner.view.clone_view(), replica_task_rx); + } else { + tracing::warn!("replica_task_rx already taken for ClientKvApi"); + } + if let Some(owner_local_publish_rx) = inner.owner_local_publish_rx.lock().take() { + put::spawn_owner_local_publish_dispatcher( + inner.view.clone_view(), + owner_local_publish_rx, + OWNER_LOCAL_PUBLISH_MAX_INFLIGHT, + ); } else { - tracing::warn!("write_back_append_rx already taken for ClientKvApi"); + tracing::warn!("owner_local_publish_rx already taken for ClientKvApi"); } // Spawn cluster listener to clean up get_holding when external_client leaves diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs index c53c634..c9c2475 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs @@ -218,7 +218,7 @@ pub struct ExternalBatchPutStartItemReq { pub len: u64, pub reject_if_inflight_same_key: bool, pub reject_if_exist_same_key: bool, - pub write_through: bool, + pub make_replica_task: bool, pub preferred_sub_cluster: Option, } @@ -271,7 +271,6 @@ pub struct ExternalBatchPutTransferEndItemReq { pub peer_id: Option, pub target_base_addr: Option, pub put_id: Option, - pub write_through: bool, pub lease_id: Option, } @@ -317,7 +316,6 @@ pub struct ExternalBatchPutCommitItemReq { pub remote_target: bool, pub put_id: Option, pub lease_id: Option, - pub write_through: bool, } #[derive(Default, Debug, Clone, Encode, Decode)] @@ -480,7 +478,7 @@ pub struct ExternalPutStartReq { pub len: u64, pub reject_if_inflight_same_key: bool, pub reject_if_exist_same_key: bool, - pub write_through: bool, + pub make_replica_task: bool, /// Prefer placing the target allocation on any kvclient within this sub_cluster. pub preferred_sub_cluster: Option, /// Owner node_start_time observed by external when request starts @@ -526,7 +524,6 @@ pub struct ExternalPutTransferEndReq { pub peer_id: Option, pub target_base_addr: Option, pub put_id: Option, - pub write_through: bool, /// Optional lease to attach this key to when committing pub lease_id: Option, /// Owner node_start_time observed by external when request starts @@ -563,7 +560,6 @@ pub struct ExternalPutCommitReq { pub remote_target: bool, pub put_id: Option, pub lease_id: Option, - pub write_through: bool, /// Owner node_start_time observed by the caller when request starts pub started_time: i64, pub test_observe_put_phases: bool, diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs index 225decf..fd309b3 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs @@ -1,17 +1,16 @@ use super::{ - local_reserve_rebalance::{owner_local_reserve_timeout_config, wait_owner_local_reserve_ready}, ClientKvApiInner, OwnerLocalReserveClassState, OwnerLocalReserveGrantState, - OwnerLocalReservePoolState, OwnerLocalReserveSlotLease, WriteBackAppendJob, + OwnerLocalReservePoolState, OwnerLocalReserveSlotLease, ReplicaTaskJob, ReplicaTaskTarget, + local_reserve_rebalance::{owner_local_reserve_timeout_config, wait_owner_local_reserve_ready}, }; -use crate::cluster_manager::app_logic_ext::ClusterManagerAppLogicExt; +use crate::OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES; use crate::cluster_manager::NodeIDString; +use crate::cluster_manager::app_logic_ext::ClusterManagerAppLogicExt; use crate::master_kv_router::put::PutIDForAKey; -use crate::OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES; // no StageScope; timestamps-based metrics only use crate::memholder::kvclient_encode::{calc_flat_dict_encoded_len, write_flat_dict_ptrs_to_ptr}; use crate::observe_kvope::{ obe_put_start_error_rpc, obe_put_start_error_status, obe_put_start_success, - obe_put_transfer_error, }; use crate::{ client_kv_api::ClientKvApiView, @@ -21,17 +20,18 @@ use crate::{ BatchPutRevokeReq, BatchPutRevokeResp, BatchPutStartItemReq, BatchPutStartReq, BatchPutStartResp, BatchReleasePutKeyReservationsReq, BatchReleasePutKeyReservationsResp, PutAppendDoneReq, PutAppendDoneResp, PutAppendRevokeReq, PutAppendStartReq, - PutAppendStartResp, PutDoneReq, PutRevokeReq, PutStartReq, PutStartResp, - ReleaseLocalGrantReq, ReserveLocalGrantReq, ReserveLocalGrantResp, + PutAppendStartResp, PutDoneCommittedSlot, PutDoneReq, PutRevokeReq, PutStartReq, + PutStartResp, ReleaseLocalGrantReq, ReserveLocalGrantReq, ReserveLocalGrantResp, }, + memholder::{UserMemHolder, UserMemHolderExposeKind}, p2p::msg_pack::MsgPack, p2p::p2p_module::RpcTransportPolicy, rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, KvResult}, }; use chrono::Utc; use fluxon_commu::TransferBreakdown; -use futures::stream::{self, StreamExt}; use limit_thirdparty::tokio; +use std::sync::Arc; use std::time::Instant; use tracing::info; @@ -135,12 +135,28 @@ pub struct OwnerReservedPutItem { pub value_len: u64, pub lease_id: Option, pub peer_node_id: Option, - pub write_through: bool, pub remember_local_snapshot: bool, - pub enqueue_write_back_append: bool, + pub make_replica_task: bool, + pub replica_target: Option, +} + +#[derive(Debug, Clone)] +pub struct OwnerLocalPublishItem { + pub key: String, + pub put_id: PutIDForAKey, + pub value_len: u64, + pub lease_id: Option, + pub committed_slot: PutDoneCommittedSlot, + pub make_replica_task: bool, pub preferred_sub_cluster: Option, } +#[derive(Debug, Clone)] +pub struct OwnerLocalPublishJob { + pub items: Vec, + pub key_reservation_ids: Vec, +} + #[derive(Debug, Clone, Copy, Default)] pub struct PutEndStats { pub master_put_end_rpc_us: i64, @@ -517,6 +533,16 @@ impl ClientKvApiInner { } else { Some(start_item.node_id.clone()) }; + let replica_target = + start_item + .replica_target + .as_ref() + .map(|target| ReplicaTaskTarget { + node_id: target.node_id.clone(), + target_offset: target.target_addr - target.target_base_addr, + target_base_addr: target.target_base_addr, + len: target.len, + }); revoke_items.push(BatchPutRevokeItemReq { key: start_req.key.clone(), put_id: start_item.put_id, @@ -531,10 +557,9 @@ impl ClientKvApiInner { value_len: start_req.len, lease_id, peer_node_id: peer_node_id.clone(), - write_through: start_req.write_through, - remember_local_snapshot: !start_req.write_through || peer_node_id.is_none(), - enqueue_write_back_append: !start_req.write_through && peer_node_id.is_some(), - preferred_sub_cluster: start_req.preferred_sub_cluster, + remember_local_snapshot: true, + make_replica_task: start_req.make_replica_task && replica_target.is_some(), + replica_target, }); } @@ -556,7 +581,7 @@ impl ClientKvApiInner { pub async fn owner_batch_put_commit_reserved( &self, items: Vec, - transfer_concurrency: usize, + _transfer_concurrency: usize, ) -> KvResult>> { if items.is_empty() { return Ok(Vec::new()); @@ -568,87 +593,13 @@ impl ClientKvApiInner { item: OwnerReservedPutItem, } - let transfer_concurrency = transfer_concurrency.max(1); let metrics = self.metrics_handle(); let mut results: Vec>> = (0..items.len()).map(|_| None).collect(); let mut done_pending = Vec::with_capacity(items.len()); - let mut revoke_pending = Vec::new(); - let mut transfer_futures = Vec::new(); for (idx, item) in items.into_iter().enumerate() { - if !item.write_through { - metrics.record_put_io_locality(false, item.value_len, 0); - done_pending.push(DonePending { idx, item }); - continue; - } - if item.peer_node_id.is_none() && item.src_addr == item.target_addr { - metrics.record_put_io_locality(false, item.value_len, 0); - done_pending.push(DonePending { idx, item }); - continue; - } - - let src_offset = item.src_addr - item.src_base_addr; - let target_offset = if item.peer_node_id.is_some() { - item.target_addr - item.target_base_addr - } else { - item.target_addr - item.src_base_addr - }; - transfer_futures.push(async move { - let transfer_started_at = Instant::now(); - let transfer_result = self - .put_transfer( - &item.key, - item.put_id, - src_offset, - target_offset, - item.value_len, - item.peer_node_id.clone(), - item.peer_node_id.as_ref().map(|_| item.target_base_addr), - ) - .await; - ( - idx, - item, - duration_to_i64_us(transfer_started_at.elapsed()), - transfer_result, - ) - }); - } - - let mut transfer_stream = - stream::iter(transfer_futures).buffer_unordered(transfer_concurrency); - while let Some(joined) = transfer_stream.next().await { - match joined { - (idx, item, wall_transfer_us, Ok(breakdown)) => { - let breakdown_transfer_us = breakdown.submit_blocking_us - + breakdown.create_xfer_req_us - + breakdown.post_xfer_req_us - + breakdown.poll_wait_us; - let transfer_us = breakdown_transfer_us.max(wall_transfer_us); - metrics.record_put_io_locality( - breakdown.remote_transfer, - item.value_len, - transfer_us, - ); - done_pending.push(DonePending { idx, item }); - } - (idx, item, _wall_transfer_us, Err(err)) => { - results[idx] = Some(Err(err)); - revoke_pending.push(BatchPutRevokeItemReq { - key: item.key, - put_id: item.put_id, - }); - } - } - } - - if !revoke_pending.is_empty() { - if let Err(err) = self.batch_put_revoke(revoke_pending).await { - tracing::warn!( - "owner_batch_put_commit_reserved batch_put_revoke failed after transfer errors: {}", - err - ); - } + metrics.record_put_io_locality(false, item.value_len, 0); + done_pending.push(DonePending { idx, item }); } if self.skip_put_end_commit_enabled() { @@ -700,17 +651,18 @@ impl ClientKvApiInner { if pending.item.remember_local_snapshot { self.remember_local_snapshot(&pending.item.key, pending.item.put_id); } - if pending.item.enqueue_write_back_append { + if pending.item.make_replica_task { + let target = pending + .item + .replica_target + .clone() + .expect("make_replica_task requires pre-reserved replica target"); if let Err(err) = self - .enqueue_write_back_remote_append( - &pending.item.key, - pending.item.put_id, - pending.item.preferred_sub_cluster.as_deref(), - ) + .make_replica_task(&pending.item.key, pending.item.put_id, target) .await { tracing::warn!( - "owner_batch_put_commit_reserved write-back remote append enqueue failed after local commit: key={} put_id=({},{}) err={}", + "owner_batch_put_commit_reserved make replica task failed after local commit: key={} put_id=({},{}) err={}", pending.item.key, pending.item.put_id.0, pending.item.put_id.1, @@ -757,7 +709,7 @@ impl ClientKvApiInner { keys: Vec, ptrs_groups: Vec)>>, opts: crate::client_kv_api::PutOptionalArgs, - transfer_concurrency: usize, + _transfer_concurrency: usize, ) -> KvResult>> { if !self.view.register_shutdown_poller().is_running() { return Err(KvError::Api(ApiError::SystemShutdown { @@ -777,11 +729,10 @@ impl ClientKvApiInner { if keys.is_empty() { return Ok(Vec::new()); } - let transfer_concurrency = transfer_concurrency.max(1); let lease_id = opts.lease_id(); let reject_if_inflight_same_key = opts.reject_if_inflight_same_key(); let reject_if_exist_same_key = opts.reject_if_exist_same_key(); - let write_through = opts.write_through(); + let make_replica_task = opts.make_replica_task(); let preferred_sub_cluster = opts.preferred_sub_cluster().map(|s| s.to_string()); let mut start_items = Vec::with_capacity(keys.len()); @@ -794,7 +745,7 @@ impl ClientKvApiInner { len: payload_len, reject_if_inflight_same_key, reject_if_exist_same_key, - write_through, + make_replica_task, preferred_sub_cluster: preferred_sub_cluster.clone(), }); } @@ -817,14 +768,12 @@ impl ClientKvApiInner { put_id: PutIDForAKey, lease_id: Option, remember_local_snapshot: bool, - enqueue_write_back_append: bool, + make_replica_task: bool, + replica_target: Option, } - let self_node_id = self.view.cluster_manager().get_self_info().id.clone(); let mut results: Vec>> = (0..keys.len()).map(|_| None).collect(); let mut done_pending = Vec::new(); - let mut revoke_pending = Vec::new(); - let mut transfer_futures = Vec::new(); let short_circuit_payload = self.short_circuit_put_payload_path_enabled(); let skip_put_end_commit = self.skip_put_end_commit_enabled(); @@ -844,12 +793,17 @@ impl ClientKvApiInner { } let put_id = start_item.put_id; - let peer_id = if start_item.node_id == self_node_id { - None - } else { - Some(start_item.node_id.clone()) - }; - let remember_local_snapshot = !write_through || peer_id.is_none(); + let remember_local_snapshot = true; + let replica_target = + start_item + .replica_target + .as_ref() + .map(|target| ReplicaTaskTarget { + node_id: target.node_id.clone(), + target_offset: target.target_addr - target.target_base_addr, + target_base_addr: target.target_base_addr, + len: target.len, + }); if !short_circuit_payload { unsafe { @@ -857,78 +811,17 @@ impl ClientKvApiInner { } } - if !write_through { - done_pending.push(DonePending { - idx, - key, - put_id, - lease_id, - remember_local_snapshot, - enqueue_write_back_append: !short_circuit_payload && peer_id.is_some(), - }); - continue; - } - - if short_circuit_payload - || (peer_id.is_none() && start_item.src_addr == start_item.target_addr) - { - done_pending.push(DonePending { - idx, - key, - put_id, - lease_id, - remember_local_snapshot, - enqueue_write_back_append: false, - }); - continue; - } - - let target_base_addr_opt = peer_id.as_ref().map(|_| start_item.target_base_addr); - let src_offset = start_item.src_addr - start_item.src_base_addr; - let target_offset = start_item.target_addr - start_item.target_base_addr; - transfer_futures.push(async move { - let transfer_result = self - .put_transfer( - &key, - put_id, - src_offset, - target_offset, - payload_len, - peer_id, - target_base_addr_opt, - ) - .await; - (idx, key, put_id, remember_local_snapshot, transfer_result) + done_pending.push(DonePending { + idx, + key, + put_id, + lease_id, + remember_local_snapshot, + make_replica_task: make_replica_task && replica_target.is_some(), + replica_target, }); } - let mut transfer_stream = - stream::iter(transfer_futures).buffer_unordered(transfer_concurrency); - while let Some(joined) = transfer_stream.next().await { - match joined { - (idx, key, put_id, remember_local_snapshot, Ok(_breakdown)) => { - done_pending.push(DonePending { - idx, - key, - put_id, - lease_id, - remember_local_snapshot, - enqueue_write_back_append: false, - }); - } - (idx, key, put_id, _remember_local_snapshot, Err(err)) => { - results[idx] = Some(Err(err)); - revoke_pending.push(BatchPutRevokeItemReq { key, put_id }); - } - } - } - - if !revoke_pending.is_empty() { - if let Err(err) = self.batch_put_revoke(revoke_pending).await { - tracing::warn!("batch_put_revoke failed after transfer errors: {}", err); - } - } - if skip_put_end_commit { for pending in done_pending { results[pending.idx] = Some(Ok(())); @@ -976,17 +869,17 @@ impl ClientKvApiInner { if pending.remember_local_snapshot { self.remember_local_snapshot(&pending.key, pending.put_id); } - if pending.enqueue_write_back_append { + if pending.make_replica_task { + let target = pending + .replica_target + .clone() + .expect("make_replica_task requires pre-reserved replica target"); if let Err(err) = self - .enqueue_write_back_remote_append( - &pending.key, - pending.put_id, - preferred_sub_cluster.as_deref(), - ) + .make_replica_task(&pending.key, pending.put_id, target) .await { tracing::warn!( - "batch write-back remote append enqueue failed after local commit: key={} put_id=({},{}) err={}", + "batch make replica task failed after local commit: key={} put_id=({},{}) err={}", pending.key, pending.put_id.0, pending.put_id.1, @@ -1009,36 +902,90 @@ impl ClientKvApiInner { .collect()) } - pub async fn enqueue_write_back_remote_append( + pub async fn make_replica_task( &self, key: &str, put_id: PutIDForAKey, - preferred_sub_cluster: Option<&str>, + target: ReplicaTaskTarget, ) -> KvResult<()> { - let Some((holder, _)) = self.get(key).await? else { - return Err(KvError::Api(ApiError::Unknown { - detail: format!( - "write-back local commit did not produce a readable current replica: key={} put_id=({},{})", - key, put_id.0, put_id.1 - ), - })); + let Some(memory_info) = self.local_visible_mem_holder(key) else { + tracing::warn!( + "replica task source holder is unavailable after local commit; dropping replica task: key={} put_id=({},{})", + key, + put_id.0, + put_id.1 + ); + return Ok(()); }; - self.write_back_append_tx - .send(WriteBackAppendJob { - key: key.to_string(), - put_id, - holder, - preferred_sub_cluster: preferred_sub_cluster.map(|s| s.to_string()), - }) - .await - .map_err(|err| { - KvError::Api(ApiError::Unknown { - detail: format!( - "write-back append actor queue send failed: key={} put_id=({},{}) err={}", - key, put_id.0, put_id.1, err - ), - }) - }) + + let holder = Arc::new(UserMemHolder::new( + memory_info, + self.get_or_init_all_memholder_refcount(), + UserMemHolderExposeKind::SegPtr, + )); + + match self.replica_task_tx.try_send(ReplicaTaskJob { + key: key.to_string(), + put_id, + holder, + target: Some(target), + preferred_sub_cluster: None, + }) { + Ok(()) => Ok(()), + Err(err) => { + tracing::warn!( + "replica task actor enqueue failed; dropping replica task: key={} put_id=({},{}) err={}", + key, + put_id.0, + put_id.1, + err + ); + Ok(()) + } + } + } + + pub async fn make_replica_append_task( + &self, + key: &str, + put_id: PutIDForAKey, + preferred_sub_cluster: Option, + ) -> KvResult<()> { + let Some(memory_info) = self.local_visible_mem_holder(key) else { + tracing::warn!( + "replica append task source holder is unavailable after local publish; dropping replica task: key={} put_id=({},{})", + key, + put_id.0, + put_id.1 + ); + return Ok(()); + }; + + let holder = Arc::new(UserMemHolder::new( + memory_info, + self.get_or_init_all_memholder_refcount(), + UserMemHolderExposeKind::SegPtr, + )); + + match self.replica_task_tx.try_send(ReplicaTaskJob { + key: key.to_string(), + put_id, + holder, + target: None, + preferred_sub_cluster, + }) { + Ok(()) => Ok(()), + Err(err) => { + tracing::warn!( + "replica append task actor enqueue failed; dropping replica task: key={} put_id=({},{}) err={}", + key, + put_id.0, + put_id.1, + err + ); + Ok(()) + } + } } async fn put_common( @@ -1048,7 +995,7 @@ impl ClientKvApiInner { len_for_start: u32, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, - write_through: bool, + make_replica_task: bool, preferred_sub_cluster: Option<&str>, lease_id: Option, _test_payload_len_u32: u32, @@ -1072,7 +1019,7 @@ impl ClientKvApiInner { len_for_start, reject_if_inflight_same_key, reject_if_exist_same_key, - write_through, + make_replica_task, preferred_sub_cluster, ) .await @@ -1101,6 +1048,15 @@ impl ClientKvApiInner { }; let abs_src = resp.src_addr; let abs_target = resp.target_addr; + let replica_target = resp + .replica_target + .as_ref() + .map(|target| ReplicaTaskTarget { + node_id: target.node_id.clone(), + target_offset: target.target_addr - target.target_base_addr, + target_base_addr: target.target_base_addr, + len: target.len, + }); #[cfg(test)] { @@ -1144,8 +1100,26 @@ impl ClientKvApiInner { skipped_breakdown.remote_transfer, ); self.put_end(key, put_id, lease_id).await?; - if !write_through || peer_id.is_none() { - self.remember_local_snapshot(key, put_id); + self.remember_local_snapshot(key, put_id); + if make_replica_task && replica_target.is_some() { + if let Err(err) = self + .make_replica_task( + key, + put_id, + replica_target + .clone() + .expect("make_replica_task requires pre-reserved replica target"), + ) + .await + { + tracing::warn!( + "make replica task failed after short-circuit local commit: key={} put_id=({},{}) err={}", + key, + put_id.0, + put_id.1, + err + ); + } } if let Some(tag) = info_complete_tag { info!("{tag} complete key={} bytes={}", key, payload_len); @@ -1170,87 +1144,20 @@ impl ClientKvApiInner { .await .unwrap() .allocated_addr; - if !write_through { - self.put_end(key, put_id, lease_id).await?; - self.remember_local_snapshot(key, put_id); - if peer_id.is_some() { - if let Err(err) = self - .enqueue_write_back_remote_append(key, put_id, preferred_sub_cluster) - .await - { - tracing::warn!( - "write-back remote append enqueue failed after local commit: key={} put_id=({},{}) err={}", - key, - put_id.0, - put_id.1, - err - ); - } - } - if let Some(tag) = info_complete_tag { - info!( - "{tag} local_commit_complete key={} bytes={}", - key, payload_len - ); - } - return Ok(()); - } - let src_offset = abs_src - base_addr; - let (target_offset, target_base_addr_opt) = match &peer_id { - Some(_) => ( - abs_target - resp.target_base_addr, - Some(resp.target_base_addr), - ), - None => (abs_target - base_addr, None), - }; if dbg_addr_summary { tracing::debug!( - "put path addr summary: key={}, put_id=({},{}) local_base={:#x}, abs_src={:#x}, src_off={:#x}, master_target_base={:#x}, abs_target={:#x}, tgt_off={:#x}, peer_id={:?}", + "put path addr summary: key={}, put_id=({},{}) local_base={:#x}, abs_src={:#x}, master_target_base={:#x}, abs_target={:#x}, peer_id={:?}", key, put_id.0, put_id.1, base_addr, abs_src, - src_offset, - target_base_addr_opt.unwrap_or(base_addr), + resp.target_base_addr, abs_target, - target_offset, peer_id ); } - let transfer_breakdown = match self - .put_transfer( - key, - put_id, - src_offset, - target_offset, - payload_len, - peer_id.clone(), - target_base_addr_opt, - ) - .await - { - Ok(breakdown) => breakdown, - Err(e) => { - self.put_revoke(key, put_id).await?; - obe_put_transfer_error(&metrics, &client_id, &node_role, key, payload_len); - return Err(e); - } - }; - metrics.pending_put_set_transfer_breakdown( - put_id, - transfer_breakdown.submit_blocking_us, - transfer_breakdown.create_xfer_req_us, - transfer_breakdown.post_xfer_req_us, - transfer_breakdown.poll_wait_us, - transfer_breakdown.poll_iters, - transfer_breakdown.used_fast_path, - false, - transfer_breakdown.local_noop, - transfer_breakdown.remote_transfer, - ); - if self.skip_put_end_commit_enabled() { let _ = metrics.pending_put_remove(&put_id); tracing::warn!( @@ -1270,8 +1177,26 @@ impl ClientKvApiInner { } self.put_end(key, put_id, lease_id).await?; - if peer_id.is_none() { - self.remember_local_snapshot(key, put_id); + self.remember_local_snapshot(key, put_id); + if make_replica_task && replica_target.is_some() { + if let Err(err) = self + .make_replica_task( + key, + put_id, + replica_target + .clone() + .expect("make_replica_task requires pre-reserved replica target"), + ) + .await + { + tracing::warn!( + "make replica task failed after local commit: key={} put_id=({},{}) err={}", + key, + put_id.0, + put_id.1, + err + ); + } } if let Some(tag) = info_complete_tag { info!("{tag} complete key={} bytes={}", key, payload_len); @@ -1292,7 +1217,7 @@ impl ClientKvApiInner { let lease_id = opts.lease_id(); let reject_if_inflight_same_key = opts.reject_if_inflight_same_key(); let reject_if_exist_same_key = opts.reject_if_exist_same_key(); - let write_through = opts.write_through(); + let make_replica_task = opts.make_replica_task(); let preferred_sub_cluster = opts.preferred_sub_cluster().map(|s| s.to_string()); let payload_len = calc_flat_dict_encoded_len(&ptrs)?; @@ -1302,7 +1227,7 @@ impl ClientKvApiInner { payload_len as u32, reject_if_inflight_same_key, reject_if_exist_same_key, - write_through, + make_replica_task, preferred_sub_cluster.as_deref(), lease_id, payload_len as u32, @@ -1329,7 +1254,7 @@ impl ClientKvApiInner { let lease_id = opts.lease_id(); let reject_if_inflight_same_key = opts.reject_if_inflight_same_key(); let reject_if_exist_same_key = opts.reject_if_exist_same_key(); - let write_through = opts.write_through(); + let make_replica_task = opts.make_replica_task(); let preferred_sub_cluster = opts.preferred_sub_cluster().map(|s| s.to_string()); let payload_len = value.len() as u64; self.put_common( @@ -1338,7 +1263,7 @@ impl ClientKvApiInner { value.len() as u32, reject_if_inflight_same_key, reject_if_exist_same_key, - write_through, + make_replica_task, preferred_sub_cluster.as_deref(), lease_id, value.len() as u32, @@ -1459,7 +1384,7 @@ impl ClientKvApiInner { len: u32, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, - write_through: bool, + make_replica_task: bool, preferred_sub_cluster: Option<&str>, source_node_id: Option, ) -> KvResult<(PutStartResp, i64)> { @@ -1469,7 +1394,7 @@ impl ClientKvApiInner { len: len as u64, reject_if_inflight_same_key, reject_if_exist_same_key, - write_through, + make_replica_task, preferred_sub_cluster: preferred_sub_cluster.map(|s| s.to_string()), source_node_id, }, @@ -1520,7 +1445,7 @@ impl ClientKvApiInner { len: u32, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, - write_through: bool, + make_replica_task: bool, preferred_sub_cluster: Option<&str>, ) -> KvResult<(PutStartResp, i64)> { self.put_start_with_source_node( @@ -1528,7 +1453,7 @@ impl ClientKvApiInner { len, reject_if_inflight_same_key, reject_if_exist_same_key, - write_through, + make_replica_task, preferred_sub_cluster, None, ) @@ -2143,17 +2068,17 @@ impl ClientKvApiInner { } } -pub fn spawn_write_back_append_actor( +pub fn spawn_replica_task_actor( view: ClientKvApiView, - mut rx: tokio::sync::ampsc::Receiver, + mut rx: tokio::sync::ampsc::Receiver, ) { let view_task = view.clone(); - let _ = view.spawn("write_back_append_actor", async move { + let _ = view.spawn("replica_task_actor", async move { let mut shutdown_waiter = view_task.register_shutdown_waiter(); loop { let job = tokio::select! { _ = shutdown_waiter.wait() => { - tracing::info!("write_back_append_actor stopping due to shutdown signal"); + tracing::info!("replica_task_actor stopping due to shutdown signal"); break; } job = rx.recv() => { @@ -2166,71 +2091,102 @@ pub fn spawn_write_back_append_actor( let inner = view_task.client_kv_api().inner(); let src_offset = job.holder.memory_info().offset; let len = job.holder.get_length() as u64; - let append_start = match inner - .put_append_start( - &job.key, - job.put_id, - job.holder.get_length(), - job.preferred_sub_cluster.as_deref(), - ) - .await - { - Ok(resp) => resp, - Err(err) => { - tracing::warn!( - "write-back append start failed: key={} put_id=({},{}) err={}", + let target = if let Some(target) = job.target.clone() { + target + } else { + let len_u32 = match u32::try_from(len) { + Ok(len_u32) => len_u32, + Err(_) => { + tracing::warn!( + "replica append task length does not fit u32: key={} put_id=({},{}) len={}", + job.key, + job.put_id.0, + job.put_id.1, + len + ); + continue; + } + }; + let append_start = match inner + .put_append_start( + &job.key, + job.put_id, + len_u32, + job.preferred_sub_cluster.as_deref(), + ) + .await + { + Ok(resp) => resp, + Err(err) => { + tracing::warn!( + "replica append task start failed: key={} put_id=({},{}) err={}", + job.key, + job.put_id.0, + job.put_id.1, + err + ); + continue; + } + }; + if !append_start.scheduled { + tracing::debug!( + "replica append task not scheduled: key={} put_id=({},{})", job.key, job.put_id.0, - job.put_id.1, - err + job.put_id.1 ); continue; } + ReplicaTaskTarget { + node_id: append_start.node_id, + target_offset: append_start.target_addr - append_start.target_base_addr, + target_base_addr: append_start.target_base_addr, + len: append_start.len, + } }; - if !append_start.scheduled { - tracing::debug!( - "write-back append skipped because current version no longer needs remote replica: key={} put_id=({},{})", + if len != target.len { + tracing::warn!( + "replica task length mismatch: key={} put_id=({},{}) src_len={} target_len={}", job.key, job.put_id.0, - job.put_id.1 + job.put_id.1, + len, + target.len + ); + spawn_replica_task_revoke( + view_task.clone(), + job.key, + job.put_id, + "length mismatch", ); continue; } - let target_offset = append_start.target_addr - append_start.target_base_addr; if let Err(err) = inner .put_transfer( &job.key, job.put_id, src_offset, - target_offset, + target.target_offset, len, - Some(append_start.node_id.clone()), - Some(append_start.target_base_addr), + Some(target.node_id.clone()), + Some(target.target_base_addr), ) .await { tracing::warn!( - "write-back append transfer failed: key={} put_id=({},{}) err={}", + "replica task transfer failed: key={} put_id=({},{}) err={}", job.key, job.put_id.0, job.put_id.1, err ); - if let Err(revoke_err) = inner.put_append_revoke(&job.key, job.put_id).await { - tracing::warn!( - "write-back append revoke failed after transfer error: key={} put_id=({},{}) err={}", - job.key, - job.put_id.0, - job.put_id.1, - revoke_err - ); - } + spawn_replica_task_revoke(view_task.clone(), job.key, job.put_id, "transfer error"); continue; } match inner.put_append_done(&job.key, job.put_id).await { Ok(resp) => { tracing::debug!( - "write-back append done: key={} put_id=({},{}) appended={}", + "replica task append done: key={} put_id=({},{}) appended={}", job.key, job.put_id.0, job.put_id.1, @@ -2239,7 +2195,7 @@ pub fn spawn_write_back_append_actor( } Err(err) => { tracing::warn!( - "write-back append done failed: key={} put_id=({},{}) err={}", + "replica task append done failed: key={} put_id=({},{}) err={}", job.key, job.put_id.0, job.put_id.1, @@ -2250,3 +2206,157 @@ pub fn spawn_write_back_append_actor( } }); } + +pub fn spawn_owner_local_publish_dispatcher( + view: ClientKvApiView, + mut rx: tokio::sync::ampsc::Receiver, + max_inflight: usize, +) { + let view_task = view.clone(); + let _ = view.spawn("owner_local_publish_dispatcher", async move { + let max_inflight = max_inflight.max(1); + let semaphore = Arc::new(::tokio::sync::Semaphore::new(max_inflight)); + let mut shutdown_waiter = view_task.register_shutdown_waiter(); + loop { + let job = tokio::select! { + _ = shutdown_waiter.wait() => { + tracing::info!("owner_local_publish_dispatcher stopping due to shutdown signal"); + break; + } + job = rx.recv() => { + match job { + Some(job) => job, + None => break, + } + } + }; + let permit = match semaphore.clone().acquire_owned().await { + Ok(permit) => permit, + Err(err) => { + tracing::warn!( + "owner_local_publish_dispatcher semaphore closed; dropping job key_count={} err={}", + job.items.len(), + err + ); + break; + } + }; + let spawn_view = view_task.clone(); + let worker_view = view_task.clone(); + spawn_view.spawn("owner_local_publish_worker", async move { + let _permit = permit; + publish_owner_local_job(worker_view, job).await; + }); + } + }); +} + +async fn publish_owner_local_job(view: ClientKvApiView, job: OwnerLocalPublishJob) { + let inner = view.client_kv_api().inner(); + if job.items.is_empty() { + release_owner_local_publish_reservations(inner, job.key_reservation_ids).await; + return; + } + + let done_req_items = job + .items + .iter() + .map(|item| BatchPutDoneItemReq { + key: item.key.clone(), + put_id: item.put_id, + lease_id: item.lease_id, + committed_slot: Some(item.committed_slot.clone()), + publish_local_cache: false, + }) + .collect::>(); + + match inner.batch_put_done(done_req_items).await { + Ok(done_resp) if done_resp.items.len() == job.items.len() => { + for (item, done_item) in job.items.iter().zip(done_resp.items.into_iter()) { + if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( + done_item.error_code, + done_item.error_json.clone(), + ) { + tracing::warn!( + "owner local publish failed: key={} put_id=({},{}) err={}", + item.key, + item.put_id.0, + item.put_id.1, + err + ); + continue; + } + if item.make_replica_task { + if let Err(err) = inner + .make_replica_append_task( + &item.key, + item.put_id, + item.preferred_sub_cluster.clone(), + ) + .await + { + tracing::warn!( + "owner local publish enqueue replica append failed: key={} put_id=({},{}) err={}", + item.key, + item.put_id.0, + item.put_id.1, + err + ); + } + } + } + } + Ok(done_resp) => { + tracing::warn!( + "owner local publish response length mismatch: expected={} got={}", + job.items.len(), + done_resp.items.len() + ); + } + Err(err) => { + tracing::warn!( + "owner local publish batch_put_done rpc failed: key_count={} err={}", + job.items.len(), + err + ); + } + } + + release_owner_local_publish_reservations(inner, job.key_reservation_ids).await; +} + +async fn release_owner_local_publish_reservations( + inner: &ClientKvApiInner, + key_reservation_ids: Vec, +) { + if let Err(err) = inner + .batch_release_put_key_reservations(key_reservation_ids) + .await + { + tracing::warn!( + "owner local publish key reservation cleanup failed: {}", + err + ); + } +} + +fn spawn_replica_task_revoke( + view: ClientKvApiView, + key: String, + put_id: PutIDForAKey, + reason: &'static str, +) { + let _ = view.clone().spawn("replica_task_revoke", async move { + let inner = view.client_kv_api().inner(); + if let Err(revoke_err) = inner.put_append_revoke(&key, put_id).await { + tracing::warn!( + "replica task append revoke failed after {}: key={} put_id=({},{}) err={}", + reason, + key, + put_id.0, + put_id.1, + revoke_err + ); + } + }); +} diff --git a/fluxon_rs/fluxon_kv/src/client_seg_pool/mod.rs b/fluxon_rs/fluxon_kv/src/client_seg_pool/mod.rs index 429f6b8..8c7cc78 100644 --- a/fluxon_rs/fluxon_kv/src/client_seg_pool/mod.rs +++ b/fluxon_rs/fluxon_kv/src/client_seg_pool/mod.rs @@ -1,3 +1,4 @@ +use crate::ClientKvApiAccessTrait; use crate::client_kv_api::ClientKvApi; use crate::client_transfer_engine::{ClientTransferEngine, ClientTransferEngineAccessTrait}; use crate::cluster_manager::ClusterManagerAccessTrait; @@ -5,9 +6,8 @@ use crate::config::ContributeToClusterPoolSize; use crate::master_seg_manager::msg_pack::SegmentDeviceMemInfo; use crate::p2p::p2p_module::P2pModule; use crate::p2p::p2p_module::P2pModuleAccessTrait; -use crate::rpcresp_kvresult_convert::msg_and_error::OK; use crate::rpcresp_kvresult_convert::FromError; -use crate::ClientKvApiAccessTrait; +use crate::rpcresp_kvresult_convert::msg_and_error::OK; use crate::{ cluster_manager::{ClusterManager, ClusterMember}, master_seg_manager::msg_pack::{ @@ -19,7 +19,7 @@ use crate::{ use async_trait::async_trait; use bitcode::{Decode, Encode}; use fluxon_commu::{CpuAllocatedMem, ShareGroupOwnerRef}; -use fluxon_framework::{define_module, LogicalModule}; +use fluxon_framework::{LogicalModule, define_module}; use fluxon_util::new_map; use limit_thirdparty::tokio; use limit_thirdparty::tokio::sync::ARwLockReadGuardOwned; diff --git a/fluxon_rs/fluxon_kv/src/config.rs b/fluxon_rs/fluxon_kv/src/config.rs index 4c7615f..bf676ee 100644 --- a/fluxon_rs/fluxon_kv/src/config.rs +++ b/fluxon_rs/fluxon_kv/src/config.rs @@ -483,6 +483,193 @@ pub const DEFAULT_OTLP_LOG_FLUSH_INTERVAL_MS: u64 = 2000; pub const DEFAULT_OTLP_LOG_MAX_BATCH_LINES: usize = 2000; pub const DEFAULT_OTLP_LOG_MAX_QUEUE_LINES: usize = 20000; +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "snake_case")] +pub enum ReplicaTaskPlacementPolicyKind { + LocalFirst, + Random, + QueueAware, + WeightedRoleAware, + BoundedRoleQueueAware, + PressureRoleQueueAware, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct ReplicaTaskPlacementConfigYaml { + #[serde(default = "default_replica_task_placement_policy")] + pub policy: ReplicaTaskPlacementPolicyKind, + #[serde(default = "default_replica_task_active_node_roles")] + pub active_node_roles: Vec, + #[serde(default = "default_replica_task_remote_only_node_roles")] + pub remote_only_node_roles: Vec, + #[serde(default = "default_replica_task_restrict_to_remote_only_node_roles")] + pub restrict_to_remote_only_node_roles: bool, + #[serde(default = "default_replica_task_remote_only_shard_weight")] + pub remote_only_shard_weight: f64, + #[serde(default = "default_replica_task_role_queue_window_ms")] + pub role_queue_window_ms: f64, + #[serde(default = "default_replica_task_role_pressure_gap_ms")] + pub role_pressure_gap_ms: f64, + #[serde(default = "default_replica_task_role_fabric_guard_ms")] + pub role_fabric_guard_ms: f64, + #[serde(default = "default_replica_task_role_max_shard_imbalance")] + pub role_max_shard_imbalance: f64, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct ReplicaTaskPlacementConfig { + pub policy: ReplicaTaskPlacementPolicyKind, + pub active_node_roles: Vec, + pub remote_only_node_roles: Vec, + pub restrict_to_remote_only_node_roles: bool, + pub remote_only_shard_weight: f64, + pub role_queue_window_ms: f64, + pub role_pressure_gap_ms: f64, + pub role_fabric_guard_ms: f64, + pub role_max_shard_imbalance: f64, +} + +fn default_replica_task_placement_policy() -> ReplicaTaskPlacementPolicyKind { + ReplicaTaskPlacementPolicyKind::LocalFirst +} + +fn default_replica_task_active_node_roles() -> Vec { + vec!["prefill".to_string(), "decode".to_string()] +} + +fn default_replica_task_remote_only_node_roles() -> Vec { + vec!["remote_cache".to_string()] +} + +fn default_replica_task_restrict_to_remote_only_node_roles() -> bool { + true +} + +fn default_replica_task_remote_only_shard_weight() -> f64 { + 1.02 +} + +fn default_replica_task_role_queue_window_ms() -> f64 { + 1.0 +} + +fn default_replica_task_role_pressure_gap_ms() -> f64 { + 0.5 +} + +fn default_replica_task_role_fabric_guard_ms() -> f64 { + 50.0 +} + +fn default_replica_task_role_max_shard_imbalance() -> f64 { + 1.30 +} + +impl Default for ReplicaTaskPlacementConfigYaml { + fn default() -> Self { + Self { + policy: default_replica_task_placement_policy(), + active_node_roles: default_replica_task_active_node_roles(), + remote_only_node_roles: default_replica_task_remote_only_node_roles(), + restrict_to_remote_only_node_roles: + default_replica_task_restrict_to_remote_only_node_roles(), + remote_only_shard_weight: default_replica_task_remote_only_shard_weight(), + role_queue_window_ms: default_replica_task_role_queue_window_ms(), + role_pressure_gap_ms: default_replica_task_role_pressure_gap_ms(), + role_fabric_guard_ms: default_replica_task_role_fabric_guard_ms(), + role_max_shard_imbalance: default_replica_task_role_max_shard_imbalance(), + } + } +} + +impl Default for ReplicaTaskPlacementConfig { + fn default() -> Self { + ReplicaTaskPlacementConfigYaml::default() + .verify() + .expect("default replica_task_placement config must be valid") + } +} + +fn normalize_role_list(raw_roles: Vec, field_name: &str) -> KvResult> { + let mut deduped = std::collections::BTreeSet::new(); + for (idx, raw) in raw_roles.into_iter().enumerate() { + let trimmed = raw.trim(); + if trimmed.is_empty() { + return Err(ConfigError::InvalidClientConfig { + detail: format!("{field_name}[{idx}] must be a non-empty string"), + } + .into_kverror()); + } + deduped.insert(trimmed.to_string()); + } + if deduped.is_empty() { + return Err(ConfigError::InvalidClientConfig { + detail: format!("{field_name} must contain at least one role"), + } + .into_kverror()); + } + Ok(deduped.into_iter().collect()) +} + +fn verify_finite_nonnegative_f64(value: f64, field_name: &str) -> KvResult { + if !value.is_finite() || value < 0.0 { + return Err(ConfigError::InvalidClientConfig { + detail: format!("{field_name} must be a finite non-negative number"), + } + .into_kverror()); + } + Ok(value) +} + +impl ReplicaTaskPlacementConfigYaml { + pub fn verify(self) -> KvResult { + let remote_only_shard_weight = self.remote_only_shard_weight; + if !remote_only_shard_weight.is_finite() || remote_only_shard_weight <= 0.0 { + return Err(ConfigError::InvalidClientConfig { + detail: "replica_task_placement.remote_only_shard_weight must be a finite positive number" + .to_string(), + } + .into_kverror()); + } + let role_max_shard_imbalance = self.role_max_shard_imbalance; + if !role_max_shard_imbalance.is_finite() || role_max_shard_imbalance < 1.0 { + return Err(ConfigError::InvalidClientConfig { + detail: "replica_task_placement.role_max_shard_imbalance must be finite and >= 1.0" + .to_string(), + } + .into_kverror()); + } + + Ok(ReplicaTaskPlacementConfig { + policy: self.policy, + active_node_roles: normalize_role_list( + self.active_node_roles, + "replica_task_placement.active_node_roles", + )?, + remote_only_node_roles: normalize_role_list( + self.remote_only_node_roles, + "replica_task_placement.remote_only_node_roles", + )?, + restrict_to_remote_only_node_roles: self.restrict_to_remote_only_node_roles, + remote_only_shard_weight, + role_queue_window_ms: verify_finite_nonnegative_f64( + self.role_queue_window_ms, + "replica_task_placement.role_queue_window_ms", + )?, + role_pressure_gap_ms: verify_finite_nonnegative_f64( + self.role_pressure_gap_ms, + "replica_task_placement.role_pressure_gap_ms", + )?, + role_fabric_guard_ms: verify_finite_nonnegative_f64( + self.role_fabric_guard_ms, + "replica_task_placement.role_fabric_guard_ms", + )?, + role_max_shard_imbalance, + }) + } +} + fn verify_otlp_log_api(cfg: &mut GreptimeOtlpLogConfigYaml) -> KvResult { let endpoint = cfg.otlp_endpoint.trim(); if endpoint.is_empty() || !endpoint.contains("://") { @@ -578,6 +765,8 @@ pub struct MasterConfigYaml { pub log_dir: String, #[serde(skip_serializing_if = "Option::is_none")] pub master_ui: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub replica_task_placement: Option, #[serde(default)] pub test_spec_config: TestSpecConfig, } @@ -597,6 +786,7 @@ pub struct MasterConfig { pub pprof_duration_seconds: Option, pub log_dir: String, pub master_ui: Option, + pub replica_task_placement: ReplicaTaskPlacementConfig, pub test_spec_config: TestSpecConfig, } @@ -1531,6 +1721,11 @@ impl MasterConfigYaml { None => None, }; + let replica_task_placement = match self.replica_task_placement { + Some(cfg) => cfg.verify()?, + None => ReplicaTaskPlacementConfig::default(), + }; + let mut test_spec_config = self.test_spec_config; let transport_mode_was_explicit = test_spec_config.transport_mode.is_some(); let normalized_rdma_device_names = normalize_test_spec_rdma_device_names( @@ -1567,6 +1762,7 @@ impl MasterConfigYaml { network, log_dir: self.log_dir, master_ui, + replica_task_placement, test_spec_config, }) } @@ -1782,8 +1978,8 @@ test_spec_config: } #[test] - fn client_test_spec_config_implicit_transport_mode_with_rdma_device_names_defaults_to_transfer_with_rpc( - ) { + fn client_test_spec_config_implicit_transport_mode_with_rdma_device_names_defaults_to_transfer_with_rpc() + { let cfg = ClientConfigYaml::from_str( r#" instance_key: test_owner @@ -1848,8 +2044,8 @@ test_spec_config: } #[test] - fn client_test_spec_config_rejects_transfer_rpc_fast_path_ready_timeout_without_explicit_rdma_device_names( - ) { + fn client_test_spec_config_rejects_transfer_rpc_fast_path_ready_timeout_without_explicit_rdma_device_names() + { let cfg = ClientConfigYaml::from_str( r#" instance_key: test_owner @@ -1893,9 +2089,10 @@ test_spec_config: ) .unwrap(); let err = cfg.verify().unwrap_err(); - assert!(err - .to_string() - .contains("test_spec_config.tcp_thread_control_lane_count must be in [1, 8]")); + assert!( + err.to_string() + .contains("test_spec_config.tcp_thread_control_lane_count must be in [1, 8]") + ); } #[test] @@ -2244,6 +2441,76 @@ test_spec_config: assert!(verified.enable_transfer_rpc_fast_path); } + #[test] + fn master_config_accepts_replica_task_placement_policy() { + let cfg = MasterConfigYaml::from_str( + r#" +instance_key: test_master +cluster_name: test_cluster +port: 18080 +etcd_endpoints: ["127.0.0.1:2379"] +network: + subnet_whitelist: ["127.0.0.0/8"] +monitoring: + prometheus_base_url: "http://127.0.0.1:4000/v1/prometheus" +log_dir: /tmp/test_master_logs +replica_task_placement: + policy: bounded_role_queue_aware + active_node_roles: [" decode ", "prefill", "decode"] + remote_only_node_roles: ["remote_cache", " mem_only "] + restrict_to_remote_only_node_roles: true + remote_only_shard_weight: 1.08 + role_queue_window_ms: 2.5 + role_pressure_gap_ms: 0.75 + role_fabric_guard_ms: 40.0 + role_max_shard_imbalance: 1.5 +"#, + ) + .unwrap(); + let verified = cfg.verify().unwrap(); + assert_eq!( + verified.replica_task_placement.policy, + ReplicaTaskPlacementPolicyKind::BoundedRoleQueueAware + ); + assert_eq!( + verified.replica_task_placement.active_node_roles, + vec!["decode".to_string(), "prefill".to_string()] + ); + assert_eq!( + verified.replica_task_placement.remote_only_node_roles, + vec!["mem_only".to_string(), "remote_cache".to_string()] + ); + assert!( + verified + .replica_task_placement + .restrict_to_remote_only_node_roles + ); + assert_eq!(verified.replica_task_placement.role_queue_window_ms, 2.5); + } + + #[test] + fn master_config_rejects_invalid_replica_task_placement_weight() { + let cfg = MasterConfigYaml::from_str( + r#" +instance_key: test_master +cluster_name: test_cluster +port: 18080 +etcd_endpoints: ["127.0.0.1:2379"] +network: + subnet_whitelist: ["127.0.0.0/8"] +monitoring: + prometheus_base_url: "http://127.0.0.1:4000/v1/prometheus" +log_dir: /tmp/test_master_logs +replica_task_placement: + policy: weighted_role_aware + remote_only_shard_weight: 0.0 +"#, + ) + .unwrap(); + let err = cfg.verify().unwrap_err(); + assert!(format!("{err}").contains("remote_only_shard_weight")); + } + #[test] fn master_config_accepts_missing_port_for_auto_discovery() { let cfg = MasterConfigYaml::from_str( diff --git a/fluxon_rs/fluxon_kv/src/external_client_api/external_client_test.rs b/fluxon_rs/fluxon_kv/src/external_client_api/external_client_test.rs index da701cd..1464285 100644 --- a/fluxon_rs/fluxon_kv/src/external_client_api/external_client_test.rs +++ b/fluxon_rs/fluxon_kv/src/external_client_api/external_client_test.rs @@ -3,7 +3,8 @@ use std::collections::HashMap; use crate::cluster_manager::NodeID; use crate::config::{ ClientConfig, ContributeToClusterPoolSize, FluxonKvSpec, LargeFilePaths, MasterConfig, - MonitoringConfig, ProtocolConfig, ProtocolType, TestSpecConfig, TransferEngineType, + MonitoringConfig, ProtocolConfig, ProtocolType, ReplicaTaskPlacementConfig, TestSpecConfig, + TransferEngineType, }; use crate::master_kv_router::MasterKvRouterView; use crate::{ConfigArg, run_client, run_master}; @@ -46,6 +47,7 @@ fn new_master_config( log_dir, pprof_duration_seconds: None, master_ui: None, + replica_task_placement: ReplicaTaskPlacementConfig::default(), test_spec_config: TestSpecConfig::default(), } } diff --git a/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs b/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs index fb60035..222b821 100644 --- a/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs +++ b/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs @@ -1,3 +1,4 @@ +use crate::SharedJsonMeta; use crate::client_kv_api::external_api::{ compute_external_get_start_transfer_prefix, normalize_external_get_start_group_lens, }; @@ -10,7 +11,6 @@ use crate::cluster_manager::{ META_KEY_SHARED_STORAGE_NODE_ID, META_KEY_SHARED_STORAGE_NODE_START_TIME, }; use crate::rpcresp_kvresult_convert::ToResult; -use crate::SharedJsonMeta; use crate::{ client_kv_api::msg_pack::{ ExternalBatchGetCancelReq, ExternalBatchGetReq, ExternalBatchGetStartReq, @@ -33,16 +33,16 @@ use crate::{ msg_pack::{MsgPack, RPCCaller, RPCHandler}, p2p_module::{P2pModule, P2pModuleAccessTrait, RpcTransportPolicy}, }, - rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, KvResult, SharedMemError, OK}, + rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, KvResult, OK, SharedMemError}, }; use async_trait::async_trait; use core::panic; use dashmap::DashMap; use fluxon_commu::ShareGroupOwnerRef; -use fluxon_framework::{define_module, LogicalModule}; +use fluxon_framework::{LogicalModule, define_module}; use fluxon_observability::kv_metrics_actor::{ObserveComponent, ObserveDirection}; use fluxon_util::semaphore_map::SemaphoreMap; -use libc::{mmap, MAP_SHARED, PROT_READ, PROT_WRITE}; +use libc::{MAP_SHARED, PROT_READ, PROT_WRITE, mmap}; use limit_thirdparty::tokio; use limit_thirdparty::tokio::sync::{ARwLock, Notify}; use limit_thirdparty::tokio::time::sleep; @@ -51,8 +51,8 @@ use std::{ fs::File, // path::PathBuf, // 不再使用PathBuf sync::{ - atomic::{AtomicUsize, Ordering}, Arc, OnceLock, Weak, + atomic::{AtomicUsize, Ordering}, }, time::{Duration, Instant}, }; @@ -2610,7 +2610,7 @@ key={}, attempt={}/{}, err={}", let lease_id = opts.lease_id(); let reject_if_inflight_same_key = opts.reject_if_inflight_same_key(); let reject_if_exist_same_key = opts.reject_if_exist_same_key(); - let write_through = opts.write_through(); + let make_replica_task = opts.make_replica_task(); let preferred_sub_cluster = opts.preferred_sub_cluster().map(|s| s.to_string()); let observe_sink = opts.test_observe_put_phases(); let observe_enabled = true; @@ -2647,7 +2647,7 @@ key={}, attempt={}/{}, err={}", lease_id, reject_if_inflight_same_key, reject_if_exist_same_key, - write_through, + make_replica_task, preferred_sub_cluster.as_deref(), observe_enabled, ) @@ -2701,7 +2701,7 @@ key={}, attempt={}/{}, err={}", let lease_id = opts.lease_id(); let reject_if_inflight_same_key = opts.reject_if_inflight_same_key(); let reject_if_exist_same_key = opts.reject_if_exist_same_key(); - let write_through = opts.write_through(); + let make_replica_task = opts.make_replica_task(); let preferred_sub_cluster = opts.preferred_sub_cluster().map(|s| s.to_string()); let observe_sink = opts.test_observe_put_phases(); let observe_enabled = true; @@ -2737,7 +2737,7 @@ key={}, attempt={}/{}, err={}", lease_id, reject_if_inflight_same_key, reject_if_exist_same_key, - write_through, + make_replica_task, preferred_sub_cluster.as_deref(), observe_enabled, ) @@ -2800,7 +2800,7 @@ key={}, attempt={}/{}, err={}", let lease_id = opts.lease_id(); let reject_if_inflight_same_key = opts.reject_if_inflight_same_key(); let reject_if_exist_same_key = opts.reject_if_exist_same_key(); - let write_through = opts.write_through(); + let make_replica_task = opts.make_replica_task(); let preferred_sub_cluster = opts.preferred_sub_cluster().map(|s| s.to_string()); let mut payload_lens = Vec::with_capacity(ptrs_groups.len()); for ptrs in ptrs_groups.iter() { @@ -2831,7 +2831,7 @@ key={}, attempt={}/{}, err={}", lease_id, reject_if_inflight_same_key, reject_if_exist_same_key, - write_through, + make_replica_task, preferred_sub_cluster.as_deref(), transfer_concurrency.max(1), ) @@ -2874,7 +2874,7 @@ key={}, attempt={}/{}, err={}", lease_id: Option, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, - write_through: bool, + make_replica_task: bool, preferred_sub_cluster: Option<&str>, transfer_concurrency: usize, ) -> KvResult>> { @@ -2894,7 +2894,7 @@ key={}, attempt={}/{}, err={}", len: *payload_len, reject_if_inflight_same_key, reject_if_exist_same_key, - write_through, + make_replica_task, preferred_sub_cluster: preferred_sub_cluster.map(|s| s.to_string()), }) .collect(), @@ -2974,7 +2974,6 @@ key={}, attempt={}/{}, err={}", remote_target: start_item.peer_id.is_some(), put_id: Some(put_id), lease_id, - write_through, }, )); continue; @@ -3001,7 +3000,6 @@ key={}, attempt={}/{}, err={}", None }, put_id: Some(put_id), - write_through, lease_id, }, )); @@ -3151,7 +3149,7 @@ key={}, attempt={}/{}, err={}", lease_id: Option, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, - write_through: bool, + make_replica_task: bool, preferred_sub_cluster: Option<&str>, observe_enabled: bool, ) -> KvResult { @@ -3162,7 +3160,7 @@ key={}, attempt={}/{}, err={}", len: payload_len, reject_if_inflight_same_key, reject_if_exist_same_key, - write_through, + make_replica_task, preferred_sub_cluster: preferred_sub_cluster.map(|s| s.to_string()), started_time, test_observe_put_phases: true, @@ -3206,7 +3204,6 @@ key={}, attempt={}/{}, err={}", remote_target, put_id: put_start_ok.put_id, lease_id, - write_through, started_time, test_observe_put_phases: true, }, @@ -3275,7 +3272,6 @@ key={}, attempt={}/{}, err={}", None }, put_id: put_start_ok.put_id.clone(), - write_through, lease_id, started_time, test_observe_put_phases: true, @@ -3321,7 +3317,7 @@ key={}, attempt={}/{}, err={}", lease_id: Option, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, - write_through: bool, + make_replica_task: bool, preferred_sub_cluster: Option<&str>, observe_enabled: bool, ) -> KvResult { @@ -3333,7 +3329,7 @@ key={}, attempt={}/{}, err={}", len: value.len() as u64, reject_if_inflight_same_key, reject_if_exist_same_key, - write_through, + make_replica_task, preferred_sub_cluster: preferred_sub_cluster.map(|s| s.to_string()), started_time, test_observe_put_phases: true, @@ -3376,7 +3372,6 @@ key={}, attempt={}/{}, err={}", remote_target, put_id: put_start_ok.put_id, lease_id, - write_through, started_time, test_observe_put_phases: true, }, @@ -3459,7 +3454,6 @@ key={}, attempt={}/{}, err={}", None }, put_id: put_start_ok.put_id.clone(), - write_through, lease_id, started_time, test_observe_put_phases: true, diff --git a/fluxon_rs/fluxon_kv/src/kv_test.rs b/fluxon_rs/fluxon_kv/src/kv_test.rs index 392ccf1..4db3a7f 100644 --- a/fluxon_rs/fluxon_kv/src/kv_test.rs +++ b/fluxon_rs/fluxon_kv/src/kv_test.rs @@ -12,11 +12,11 @@ use crate::cluster_manager::ClusterManagerRdmaControlInit; use crate::config::{ ClientConfig, ContributeToClusterPoolSize, FluxonKvSpec, LargeFilePaths, MasterConfig, - MonitoringConfig, ProtocolConfig, ProtocolType, TestSpecConfig, TestSpecTransportMode, - TransferEngineType, + MonitoringConfig, ProtocolConfig, ProtocolType, ReplicaTaskPlacementConfig, TestSpecConfig, + TestSpecTransportMode, TransferEngineType, }; use crate::run_master_with_test_overrides; -use crate::{run_client_with_test_overrides, ClientRunTestOverrides, MasterRunTestOverrides}; +use crate::{ClientRunTestOverrides, MasterRunTestOverrides, run_client_with_test_overrides}; // external client runs via run_client when contribution is zero use crate::ConfigArg; use etcd_client::Client as EtcdClient; @@ -519,16 +519,18 @@ async fn verify_rdma_transfer_data_link( ); } - let Some(raw) = - fetch_transfer_link_te_value(cluster_name, from_instance_key, to_instance_key) - .await - .unwrap_or_else(|err| { - panic!( + let Some(raw) = fetch_transfer_link_te_value( + cluster_name, + from_instance_key, + to_instance_key, + ) + .await + .unwrap_or_else(|err| { + panic!( "closed transfer_link probe failed: cluster={} from={} to={} attempt={} err={}", cluster_name, from_instance_key, to_instance_key, attempt, err ) - }) - else { + }) else { if Instant::now() >= deadline { panic!( "closed transfer data probe timed out without transfer_link_te key: cluster={} from={} to={} key_prefix={} key={} attempt={}", @@ -990,6 +992,7 @@ fn new_master_launch( network: None, log_dir, master_ui: None, + replica_task_placement: ReplicaTaskPlacementConfig::default(), // Keep kv_test self-describing: each round carries the intended transfer mode. test_spec_config: kv_test_round_test_spec_config(round.round_profile), }, diff --git a/fluxon_rs/fluxon_kv/src/kvcore_test_lib.rs b/fluxon_rs/fluxon_kv/src/kvcore_test_lib.rs index c74b64a..376cc8a 100644 --- a/fluxon_rs/fluxon_kv/src/kvcore_test_lib.rs +++ b/fluxon_rs/fluxon_kv/src/kvcore_test_lib.rs @@ -10,7 +10,7 @@ use crate::client_kv_api::ClientKvApiView; use crate::cluster_manager::app_logic_ext::ClusterManagerAppLogicExt; use crate::config::{ ClientConfig, ContributeToClusterPoolSize, FluxonKvSpec, MasterConfig, MonitoringConfig, - ProtocolConfig, ProtocolType, TestSpecConfig, TransferEngineType, + ProtocolConfig, ProtocolType, ReplicaTaskPlacementConfig, TestSpecConfig, TransferEngineType, }; use crate::{ConfigArg, Framework, run_client, run_master}; @@ -93,6 +93,7 @@ fn new_master_config_with_cluster( log_dir, pprof_duration_seconds: None, master_ui: None, + replica_task_placement: ReplicaTaskPlacementConfig::default(), test_spec_config: TestSpecConfig::default(), }; println!("fluxonkv core created master config for test: {:?}", conf); diff --git a/fluxon_rs/fluxon_kv/src/lib.rs b/fluxon_rs/fluxon_kv/src/lib.rs index fe69407..609dc47 100644 --- a/fluxon_rs/fluxon_kv/src/lib.rs +++ b/fluxon_rs/fluxon_kv/src/lib.rs @@ -58,8 +58,8 @@ use crate::external_client_api::ExternalClientApiViewTrait; use crate::master_kv_router::MasterKvRouterAccessTrait; use crate::master_kv_router::MasterKvRouterView; use crate::master_kv_router::MasterKvRouterViewTrait; -use crate::master_lease_manager::master_lease_manager::MasterLeaseManagerNewArg; use crate::master_lease_manager::MasterLeaseManager; +use crate::master_lease_manager::master_lease_manager::MasterLeaseManagerNewArg; use crate::master_lease_manager::{ MasterLeaseManagerAccessTrait, MasterLeaseManagerView, MasterLeaseManagerViewTrait, }; @@ -80,21 +80,21 @@ use client_seg_pool::{ClientSegPool, ClientSegPoolNewArg}; use client_transfer_engine::ClientTransferEngine; use cluster_manager::{ClusterManager, ClusterManagerNewArg, ClusterManagerRdmaControlInit}; use config::{ - normalize_etcd_addresses, ClientConfig, ClientConfigYaml, ContributeToClusterPoolSize, - FluxonKvSpec, MasterConfig, MasterConfigYaml, ProtocolConfig, ProtocolType, SideTransferRole, - TestSpecConfig, TestSpecTransportMode, TransferEngineType, + ClientConfig, ClientConfigYaml, ContributeToClusterPoolSize, FluxonKvSpec, MasterConfig, + MasterConfigYaml, ProtocolConfig, ProtocolType, SideTransferRole, TestSpecConfig, + TestSpecTransportMode, TransferEngineType, normalize_etcd_addresses, }; use external_client_api::{ExternalClientApi, ExternalClientApiNewArg}; use fluxon_commu::TransferBackendActivationMode; use fluxon_framework::LogicalModule; -use fluxon_framework::{define_framework, AnyResult}; +use fluxon_framework::{AnyResult, define_framework}; use master_kv_router::{MasterKvRouter, MasterKvRouterNewArg}; use master_seg_manager::MasterSegManager; use metric_reporter::{ - register_greptime_otlp_log_proxy_rpc, serialize_master_observe_broadcast, - wait_master_observe_broadcast, MetricReporter, MetricReporterAccessTrait, MetricReporterNewArg, + META_KEY_KV_OBSERVE_BROADCAST, MetricReporter, MetricReporterAccessTrait, MetricReporterNewArg, MetricReporterView, MetricReporterViewTrait, ObserveProxyCaller, ObserveProxyPicker, - META_KEY_KV_OBSERVE_BROADCAST, + register_greptime_otlp_log_proxy_rpc, serialize_master_observe_broadcast, + wait_master_observe_broadcast, }; use p2p::p2p_module::{P2pModule, P2pModuleNewArg, P2pTcpThreadTransportTuning}; use sha2::{Digest, Sha256}; @@ -1521,6 +1521,7 @@ async fn run_master_impl( master_seg_manager_arg: MasterSegManagerNewArg, master_kv_router_arg: MasterKvRouterNewArg { test_spec_config: config.test_spec_config.clone(), + replica_task_placement: config.replica_task_placement.clone(), }, metric_reporter_arg: MetricReporterNewArg { test_spec_config: config.test_spec_config.clone(), diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/delete.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/delete.rs index b7d65fc..4a25934 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/delete.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/delete.rs @@ -1,12 +1,12 @@ use super::{ + MasterKvRouterView, msg_pack::{ BatchDeleteAckReq, BatchDeleteAckResp, BatchDeleteClientKvMetaCacheReq, DeleteAckReq, DeleteAckResp, DeleteClientKvMetaCacheItem, DeleteReq, DeleteResp, }, - MasterKvRouterView, }; -use crate::master_kv_router::put::PutIDForAKey; use crate::master_kv_router::OneKvNodesRoutes; +use crate::master_kv_router::put::PutIDForAKey; use crate::memholder::{ EnsureMemholderMgmtDeleteActorOwned, MasterOwnerMemMgr, MemholderManagerTrait, }; diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs index 4a290a7..52d348e 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs @@ -1,4 +1,5 @@ use super::{ + InflightGetInfo, KvRouteInfo, MasterKvRouterView, NodeValueReplicaDesc, OwnerHoldingGetInfo, msg_pack::{ BatchGetDoneItemResp, BatchGetDoneReq, BatchGetDoneResp, BatchGetRevokeItemResp, BatchGetRevokeReq, BatchGetRevokeResp, BatchGetStartItemResp, BatchGetStartReq, @@ -7,25 +8,24 @@ use super::{ GetStartResp, MemHolderKeepAliveReq, MemHolderKeepAliveResp, MemHolderReleaseReq, MemHolderReleaseResp, }, - InflightGetInfo, KvRouteInfo, MasterKvRouterView, NodeValueReplicaDesc, OwnerHoldingGetInfo, }; -use crate::master_kv_router::put::PutIDForAKey; use crate::master_kv_router::OneKvNodesRoutes; +use crate::master_kv_router::put::PutIDForAKey; use crate::memholder::MemholderManagerTrait; use crate::{ cluster_manager::NodeID, - master_seg_manager::{one_seg_allocator::Allocation, MasterSegManagerAccessTrait}, + master_seg_manager::{MasterSegManagerAccessTrait, one_seg_allocator::Allocation}, p2p::msg_pack::MsgPack, rpcresp_kvresult_convert::msg_and_error::{self, kv}, }; use dashmap::DashMap; use limit_thirdparty::tokio; -use rand::seq::SliceRandom; use rand::Rng; +use rand::seq::SliceRandom; use std::collections::HashSet; use std::{ collections::HashMap, - sync::{atomic::Ordering, Arc}, + sync::{Arc, atomic::Ordering}, }; fn update_moka_for_node( diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs index 6fb7426..9e02cf4 100644 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs @@ -26,7 +26,7 @@ use self::{ PutAppendRevokeReq, PutAppendStartReq, PutDoneReq, PutRevokeReq, PutStartReq, ReleaseLocalGrantReq, ReserveLocalGrantReq, }, - placement::{PlacementDefault, PlacementPolicy}, + placement::{PlacementPolicy, build_placement_policy}, put::{ handle_batch_prepare_put_keys, handle_batch_put_done, handle_batch_put_revoke, handle_batch_put_start, handle_batch_release_put_key_reservations, handle_put_append_done, @@ -34,18 +34,19 @@ use self::{ handle_put_start, handle_release_local_grant, handle_reserve_local_grant, }, }; +use crate::ClientKvApiAccessTrait; use crate::client_kv_api::ClientKvApi; use crate::cluster_manager::{ ClusterEvent, ClusterManager, ClusterManagerAccessTrait, NodeID, NodeIDString, }; -use crate::config::TestSpecConfig; +use crate::config::{ReplicaTaskPlacementConfig, TestSpecConfig}; use crate::master_kv_router::delete::DeleteKeyInfo; use crate::master_kv_router::put::PutIDForAKey; use crate::master_lease_manager::{MasterLeaseManager, MasterLeaseManagerAccessTrait}; -use crate::master_seg_manager::one_seg_allocator::Allocation; use crate::master_seg_manager::MasterSegManager; use crate::master_seg_manager::MasterSegManagerAccessTrait; use crate::master_seg_manager::NodeTombTag; +use crate::master_seg_manager::one_seg_allocator::Allocation; use crate::memholder::{ EnsureMemholderMgmtDeleteHandle, MasterOwnerMemMgr, MemholderManagerTrait, NodeHolderKey, }; @@ -54,14 +55,13 @@ use crate::p2p::msg_pack::{MsgPack, RPCCaller, RPCHandler}; use crate::p2p::p2p_module::{P2pModule, P2pModuleAccessTrait}; use crate::rpcresp_kvresult_convert; use crate::rpcresp_kvresult_convert::msg_and_error::{KvError, OK}; -use crate::ClientKvApiAccessTrait; -use fluxon_framework::{define_module, LogicalModule}; +use fluxon_framework::{LogicalModule, define_module}; use fluxon_framework_compiled::upgrade_view_guard::UpgradeViewGuard; use async_trait::async_trait; use chrono::Utc; use dashmap::DashMap; -use limit_thirdparty::tokio::sync::{abroadcast, ARwLock}; +use limit_thirdparty::tokio::sync::{ARwLock, abroadcast}; use limit_thirdparty::tokio::{self, sync::ampsc}; use moka::notification::RemovalCause; use parking_lot::Mutex; @@ -69,8 +69,8 @@ use parking_lot::RwLock; use std::borrow::Cow; use std::collections::HashSet; use std::collections::{HashMap, VecDeque}; -use std::sync::atomic::{AtomicU32, AtomicU64, Ordering}; use std::sync::Arc; +use std::sync::atomic::{AtomicU32, AtomicU64, Ordering}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use tracing::{debug, error, info, warn}; @@ -198,6 +198,7 @@ pub enum InflightPutAllocation { pub struct InflightPutCommitInfo { pub node_id: NodeID, pub src_target_allocation: Arc>>, + pub replica_target: Option, } /// Information about a `put` operation that is currently in progress. @@ -207,11 +208,10 @@ pub struct InflightPutInfo { pub req_node_id: NodeID, pub len: u64, pub commit_info: InflightPutCommitInfo, - pub remote_append: Option, } #[derive(Clone)] -pub struct InflightPutAppendInfo { +pub struct InflightReplicaTaskInfo { pub node_id: NodeID, pub key: String, pub put_id: PutIDForAKey, @@ -305,6 +305,7 @@ define_module!( #[derive(Clone, Debug, Default)] pub struct MasterKvRouterNewArg { pub test_spec_config: TestSpecConfig, + pub replica_task_placement: ReplicaTaskPlacementConfig, } #[derive(Clone)] @@ -493,10 +494,11 @@ pub struct MasterKvRouterInner { view: std::sync::OnceLock, pub policy: Box, test_spec_config: TestSpecConfig, + pub replica_task_placement: ReplicaTaskPlacementConfig, /// (key, put_time_ms, put_version) -> inflight_put_info pub inflight_puts: moka::future::Cache<(String, u64, u32), InflightPutInfo>, - pub inflight_put_appends: moka::future::Cache<(String, u64, u32), InflightPutAppendInfo>, + pub inflight_replica_tasks: moka::future::Cache<(String, u64, u32), InflightReplicaTaskInfo>, /// key -> inflight put count pub inflight_put_key_counts: Arc>, pub inflight_gets: moka::future::Cache, @@ -551,6 +553,9 @@ pub struct MasterKvRouterInner { /// Historical final put placement decisions grouped by placement mode. pub put_placement_mode_counts: DashMap<&'static str, Arc>, + /// Historical accepted replica task reservations by target node. + pub replica_task_target_counts: DashMap>, + /// Support replicas: key -> version_id recent_key_versionid_allocator: moka::sync::SegmentedCache>, @@ -634,7 +639,7 @@ impl MasterKvRouter { } pub async fn construct(arg: MasterKvRouterNewArg) -> Result { - let policy_impl: Box = Box::new(PlacementDefault::new()); + let policy_impl = build_placement_policy(arg.replica_task_placement.clone()); let inflight_put_ttl_seconds = if arg.test_spec_config.skip_put_end_commit { INFLIGHT_PUT_TTL_SECONDS_SKIP_PUT_END_COMMIT } else { @@ -661,15 +666,16 @@ impl MasterKvRouter { } }) .build(); - let inflight_put_appends = moka::future::Cache::builder() + let inflight_replica_tasks = moka::future::Cache::builder() .time_to_live(Duration::from_secs(60)) .build(); let inner = MasterKvRouterInner { view: std::sync::OnceLock::new(), policy: policy_impl, test_spec_config: arg.test_spec_config, + replica_task_placement: arg.replica_task_placement, inflight_puts, - inflight_put_appends, + inflight_replica_tasks, inflight_put_key_counts, inflight_gets, get_holding: MasterOwnerMemMgr::default(), @@ -687,6 +693,7 @@ impl MasterKvRouter { put_target_decision_counts: DashMap::new(), put_requester_target_decision_counts: DashMap::new(), put_placement_mode_counts: DashMap::new(), + replica_task_target_counts: DashMap::new(), recent_key_versionid_allocator: moka::sync::SegmentedCache::builder(8) .time_to_idle(Duration::from_secs(5)) .build(), @@ -1037,9 +1044,10 @@ impl MasterKvRouter { let view = view.clone(); let view2 = view.clone(); let view_task = view2.clone(); + let req_node_id = resp.node_id().clone(); let _ = view.spawn("rpc_put_done", async move { let t0 = Utc::now().timestamp_micros(); - let mut ack = handle_put_done(view_task, msg).await; + let mut ack = handle_put_done(view_task, msg, req_node_id).await; ack.serialize_part.server_process_us = Utc::now().timestamp_micros() - t0; if let Err(e) = resp.send_resp(ack).await { error!("Failed to send PutDoneResp: {:?}", e); @@ -1224,9 +1232,10 @@ impl MasterKvRouter { RPCHandler::::new().regist(p2p, move |resp, msg| { let view = view.clone(); let view2 = view.clone(); + let req_node_id = resp.node_id().clone(); view.spawn("rpc_batch_put_done", async move { let t0 = Utc::now().timestamp_micros(); - let mut ack = handle_batch_put_done(view2, msg).await; + let mut ack = handle_batch_put_done(view2, msg, req_node_id).await; ack.serialize_part.server_process_us = Utc::now().timestamp_micros() - t0; if let Err(e) = resp.send_resp(ack).await { error!("Failed to send BatchPutDoneResp: {:?}", e); @@ -1754,6 +1763,17 @@ impl MasterKvRouter { mode_counter.fetch_add(1, Ordering::Relaxed); } + pub fn record_replica_task_target(&self, target_node_id: &str) { + let target_counter = self + .inner() + .replica_task_target_counts + .entry(target_node_id.to_string()) + .or_insert_with(|| Arc::new(AtomicU64::new(0))) + .value() + .clone(); + target_counter.fetch_add(1, Ordering::Relaxed); + } + fn spawn_put_placement_reporter(&self) { let view = self.inner().view().clone(); let view_task = view.clone(); @@ -1791,11 +1811,20 @@ impl MasterKvRouter { .collect(); mode_counts.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(&b.0))); + let mut replica_task_target_counts: Vec<(String, u64)> = router + .inner() + .replica_task_target_counts + .iter() + .map(|entry| (entry.key().clone(), entry.value().load(Ordering::Relaxed))) + .collect(); + replica_task_target_counts.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(&b.0))); + info!( - "put placement historical distribution | target_counts={:?} | mode_counts={:?} | requester_target_counts={:?}", + "put placement historical distribution | target_counts={:?} | mode_counts={:?} | requester_target_counts={:?} | replica_task_target_counts={:?}", target_counts, mode_counts, requester_target_counts, + replica_task_target_counts, ); } _ = shutdown_waiter.wait() => { diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs index efb12c9..2185436 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs @@ -382,7 +382,7 @@ pub struct PutStartReq { pub len: u64, pub reject_if_inflight_same_key: bool, pub reject_if_exist_same_key: bool, - pub write_through: bool, + pub make_replica_task: bool, /// Prefer placing the target allocation on any kvclient within this sub_cluster. pub preferred_sub_cluster: Option, /// Optional source-node override for side-transfer workers that share an owner's mmap. @@ -393,6 +393,14 @@ impl MsgPackSerializePart for PutStartReq { MsgId::PutStartReq as u32 } } +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct PutReplicaTarget { + pub node_id: NodeIDString, + pub target_addr: u64, + pub target_base_addr: u64, + pub len: u64, +} + #[derive(Default, Debug, Clone, Encode, Decode)] pub struct PutStartResp { pub put_id: PutIDForAKey, @@ -408,6 +416,7 @@ pub struct PutStartResp { pub error_json: String, /// Server-side processing time in microseconds for this RPC handler pub server_process_us: i64, + pub replica_target: Option, } impl MsgPackSerializePart for PutStartResp { fn msg_id(&self) -> u32 { @@ -492,7 +501,7 @@ pub struct BatchPutStartItemReq { pub len: u64, pub reject_if_inflight_same_key: bool, pub reject_if_exist_same_key: bool, - pub write_through: bool, + pub make_replica_task: bool, pub preferred_sub_cluster: Option, } @@ -517,6 +526,7 @@ pub struct BatchPutStartItemResp { pub len: u64, pub error_code: ErrorCode, pub error_json: String, + pub replica_target: Option, } #[derive(Default, Debug, Clone, Encode, Decode)] diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/placement.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/placement.rs index d6c04bf..69c5db0 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/placement.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/placement.rs @@ -1,13 +1,16 @@ +use std::collections::{HashMap, HashSet}; use std::sync::Arc; +use std::sync::atomic::Ordering as AtomicOrdering; use crate::{ - cluster_manager::NodeID, + cluster_manager::{ClusterMember, NodeID}, + config::{ReplicaTaskPlacementConfig, ReplicaTaskPlacementPolicyKind}, master_seg_manager::one_seg_allocator::{Allocation, OneSegAllocator}, rpcresp_kvresult_convert::msg_and_error::KvError, }; use async_trait::async_trait; -use rand::seq::SliceRandom; use rand::Rng; +use rand::seq::SliceRandom; use super::MasterKvRouterView; @@ -17,7 +20,6 @@ pub enum PutPlacementTarget { /// Place remotely with a pre-allocated target allocation. Remote { node_id: NodeID, - allocator: Arc, allocation: Allocation, }, } @@ -33,15 +35,29 @@ pub trait PlacementPolicy: Send + Sync { preferred_sub_cluster: Option<&str>, len: u64, ) -> Result; + + /// Selects a remote-only target for replica task placement. + fn select_remote_target( + &self, + view: &MasterKvRouterView, + source_node_id: &NodeID, + excluded_nodes: &HashSet, + preferred_sub_cluster: Option<&str>, + len: u64, + ) -> Result<(NodeID, Allocation), KvError> { + choose_random_remote_target( + view, + source_node_id, + excluded_nodes, + preferred_sub_cluster, + len, + ) + } } -/// Compile-time switch for the master placement default. -/// -/// Change the type alias to switch behavior (and rebuild): -/// - `LocalFirstPlacementPolicy` prefers local placement when possible. -/// - `RandomPlacementPolicy` selects a random eligible target. -pub type PlacementDefault = LocalFirstPlacementPolicy; -// pub type PlacementDefault = RandomPlacementPolicy; +pub fn build_placement_policy(config: ReplicaTaskPlacementConfig) -> Box { + Box::new(ReplicaTaskPlacementPolicy::new(config)) +} /// A policy that prefers placing on the requesting node when possible. pub struct LocalFirstPlacementPolicy; @@ -116,7 +132,6 @@ impl PlacementPolicy for LocalFirstPlacementPolicy { if let Ok(allocation) = allocator.allocate(len) { return Ok(PutPlacementTarget::Remote { node_id, - allocator, allocation, }); } @@ -149,7 +164,6 @@ impl PlacementPolicy for LocalFirstPlacementPolicy { if let Ok(allocation) = allocator.allocate(len) { return Ok(PutPlacementTarget::Remote { node_id, - allocator, allocation, }); } @@ -259,7 +273,6 @@ impl PlacementPolicy for RandomPlacementPolicy { if let Ok(allocation) = allocator.allocate(len) { return Ok(PutPlacementTarget::Remote { node_id, - allocator, allocation, }); } @@ -293,7 +306,6 @@ impl PlacementPolicy for RandomPlacementPolicy { if let Ok(allocation) = allocator.allocate(len) { return Ok(PutPlacementTarget::Remote { node_id, - allocator, allocation, }); } @@ -322,3 +334,680 @@ impl PlacementPolicy for RandomPlacementPolicy { Err(err) } } + +#[derive(Clone)] +struct PlacementCandidate { + node_id: NodeID, + allocator: Arc, + total_bytes: u64, + free_bytes: u64, + used_bytes: u64, + node_write_count: u64, + requester_target_count: u64, + is_remote_only_role: bool, + is_active_role: bool, + preferred_sub_cluster_match: bool, +} + +impl PlacementCandidate { + fn queue_wait_ms(&self) -> f64 { + self.node_write_count as f64 + (self.requester_target_count as f64 * 0.01) + } + + fn mem_pressure(&self) -> f64 { + if self.total_bytes == 0 { + 1.0 + } else { + 1.0 - (self.free_bytes as f64 / self.total_bytes as f64) + } + } + + fn queue_score(&self) -> f64 { + self.queue_wait_ms() + self.mem_pressure() * 0.001 + self.used_bytes as f64 * 1e-9 + } +} + +type NoSpaceCtx = (String, String, u64, u64); + +fn no_space_error(last_no_space_ctx: Option) -> KvError { + if let Some((node, segment, total_capacity, free_capacity)) = last_no_space_ctx { + KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::NoSpace { + node, + segment, + total_capacity, + free_capacity, + }, + ) + } else { + KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::NoSpace { + node: "unknown".to_string(), + segment: "unknown".to_string(), + total_capacity: 0, + free_capacity: 0, + }, + ) + } +} + +fn member_matches_roles(member: Option<&ClusterMember>, roles: &[String]) -> bool { + let Some(member) = member else { + return false; + }; + let metadata_role = member.metadata.get("role").map(|v| v.as_str()); + let metadata_node_role = member.metadata.get("node_role").map(|v| v.as_str()); + let sub_cluster = member.sub_cluster.as_deref(); + roles.iter().any(|role| { + let role = role.as_str(); + metadata_role == Some(role) || metadata_node_role == Some(role) || sub_cluster == Some(role) + }) +} + +fn is_role_aware_policy(policy: ReplicaTaskPlacementPolicyKind) -> bool { + matches!( + policy, + ReplicaTaskPlacementPolicyKind::WeightedRoleAware + | ReplicaTaskPlacementPolicyKind::BoundedRoleQueueAware + | ReplicaTaskPlacementPolicyKind::PressureRoleQueueAware + ) +} + +fn filter_remote_only_candidates(candidates: &[PlacementCandidate]) -> Vec { + candidates + .iter() + .filter(|candidate| candidate.is_remote_only_role) + .cloned() + .collect() +} + +fn collect_remote_candidates( + view: &MasterKvRouterView, + source_node_id: &NodeID, + excluded_nodes: &HashSet, + preferred_sub_cluster: Option<&str>, + config: &ReplicaTaskPlacementConfig, +) -> Vec { + let members_by_id: HashMap = view + .cluster_manager() + .get_client_members() + .into_iter() + .map(|member| (member.id.clone(), member)) + .collect(); + + let mut candidates = Vec::new(); + for (node_id, allocator) in view.master_seg_manager().get_all_segments_allocator() { + if node_id.as_ref() == source_node_id.as_ref() || excluded_nodes.contains(&node_id) { + continue; + } + + let member = members_by_id.get(node_id.as_ref()); + let preferred_sub_cluster_match = preferred_sub_cluster + .map(|sc| member.and_then(|m| m.sub_cluster.as_deref()) == Some(sc)) + .unwrap_or(false); + if preferred_sub_cluster.is_some() && !preferred_sub_cluster_match { + continue; + } + + let total = allocator.total_size_bytes(); + let used = allocator.used_size_bytes(); + let free = total.saturating_sub(used); + let node_key = node_id.as_ref().to_string(); + let node_write_count = view + .master_kv_router() + .inner() + .put_target_decision_counts + .get(&node_key) + .map(|entry| entry.value().load(AtomicOrdering::Relaxed)) + .unwrap_or(0); + let requester_target_count = view + .master_kv_router() + .inner() + .put_requester_target_decision_counts + .get(&super::RequesterTargetPair::new( + source_node_id.as_ref(), + node_id.as_ref(), + )) + .map(|entry| entry.value().load(AtomicOrdering::Relaxed)) + .unwrap_or(0); + + candidates.push(PlacementCandidate { + node_id, + allocator, + total_bytes: total, + free_bytes: free, + used_bytes: used, + node_write_count, + requester_target_count, + is_remote_only_role: member_matches_roles(member, &config.remote_only_node_roles), + is_active_role: member_matches_roles(member, &config.active_node_roles), + preferred_sub_cluster_match, + }); + } + candidates +} + +fn choose_candidate_pool( + view: &MasterKvRouterView, + source_node_id: &NodeID, + excluded_nodes: &HashSet, + preferred_sub_cluster: Option<&str>, + config: &ReplicaTaskPlacementConfig, +) -> Vec { + let global = collect_remote_candidates(view, source_node_id, excluded_nodes, None, config); + let global_remote_only = filter_remote_only_candidates(&global); + let Some(sc) = preferred_sub_cluster else { + if config.restrict_to_remote_only_node_roles { + return global_remote_only; + } + return global; + }; + + let preferred = + collect_remote_candidates(view, source_node_id, excluded_nodes, Some(sc), config); + let preferred_remote_only = filter_remote_only_candidates(&preferred); + if config.restrict_to_remote_only_node_roles { + if !preferred_remote_only.is_empty() { + return preferred_remote_only; + } + if !global_remote_only.is_empty() { + tracing::warn!( + "preferred_sub_cluster has no eligible remote-only kvclients; using global remote-only candidates: source_node_id={} sub_cluster={:?} remote_only_node_roles={:?}", + source_node_id, + sc, + config.remote_only_node_roles + ); + return global_remote_only; + } + tracing::warn!( + "strict remote-only placement has no eligible candidates: source_node_id={} sub_cluster={:?} remote_only_node_roles={:?}", + source_node_id, + sc, + config.remote_only_node_roles + ); + return Vec::new(); + } + + if preferred.is_empty() { + tracing::warn!( + "preferred_sub_cluster has no eligible remote kvclients: source_node_id={} sub_cluster={:?}", + source_node_id, + sc + ); + return global; + } + + if is_role_aware_policy(config.policy) + && !preferred + .iter() + .any(|candidate| candidate.is_remote_only_role) + && global.iter().any(|candidate| candidate.is_remote_only_role) + { + return global; + } + + preferred +} + +fn sort_by_queue_score(candidates: &mut [PlacementCandidate]) { + candidates.sort_by(|a, b| { + a.queue_score() + .total_cmp(&b.queue_score()) + .then_with(|| { + b.preferred_sub_cluster_match + .cmp(&a.preferred_sub_cluster_match) + }) + .then_with(|| a.node_id.as_ref().cmp(b.node_id.as_ref())) + .then_with(|| { + a.allocator + .seg_device_id + .as_str() + .cmp(b.allocator.seg_device_id.as_str()) + }) + }); +} + +fn remote_only_first(candidates: Vec) -> Vec { + let has_remote_only = candidates + .iter() + .any(|candidate| candidate.is_remote_only_role); + if !has_remote_only { + return candidates; + } + candidates + .into_iter() + .filter(|candidate| candidate.is_remote_only_role) + .collect() +} + +fn order_queue_aware(mut candidates: Vec) -> Vec { + sort_by_queue_score(&mut candidates); + candidates +} + +fn order_weighted_role_aware( + candidates: Vec, + config: &ReplicaTaskPlacementConfig, +) -> Vec { + let mut candidates = remote_only_first(candidates); + candidates.sort_by(|a, b| { + let a_role_weight = if a.is_remote_only_role { + config.remote_only_shard_weight + } else { + 1.0 + }; + let b_role_weight = if b.is_remote_only_role { + config.remote_only_shard_weight + } else { + 1.0 + }; + (a.queue_score() / a_role_weight) + .total_cmp(&(b.queue_score() / b_role_weight)) + .then_with(|| b.is_remote_only_role.cmp(&a.is_remote_only_role)) + .then_with(|| { + b.preferred_sub_cluster_match + .cmp(&a.preferred_sub_cluster_match) + }) + .then_with(|| a.node_id.as_ref().cmp(b.node_id.as_ref())) + .then_with(|| { + a.allocator + .seg_device_id + .as_str() + .cmp(b.allocator.seg_device_id.as_str()) + }) + }); + candidates +} + +fn order_bounded_role_queue_aware( + candidates: Vec, + config: &ReplicaTaskPlacementConfig, +) -> Vec { + let Some(best_wait) = candidates + .iter() + .map(|candidate| candidate.queue_wait_ms()) + .min_by(|a, b| a.total_cmp(b)) + else { + return candidates; + }; + let max_wait = best_wait + config.role_queue_window_ms; + let mut eligible: Vec = candidates + .into_iter() + .filter(|candidate| candidate.queue_wait_ms() <= max_wait) + .collect(); + eligible = remote_only_first(eligible); + eligible.sort_by(|a, b| { + let a_weight = if a.is_remote_only_role { + config.remote_only_shard_weight + } else { + 1.0 + } - ((a.used_bytes as f64 / 4096.0) * 1e-6); + let b_weight = if b.is_remote_only_role { + config.remote_only_shard_weight + } else { + 1.0 + } - ((b.used_bytes as f64 / 4096.0) * 1e-6); + b_weight + .total_cmp(&a_weight) + .then_with(|| a.queue_score().total_cmp(&b.queue_score())) + .then_with(|| { + b.preferred_sub_cluster_match + .cmp(&a.preferred_sub_cluster_match) + }) + .then_with(|| a.node_id.as_ref().cmp(b.node_id.as_ref())) + .then_with(|| { + a.allocator + .seg_device_id + .as_str() + .cmp(b.allocator.seg_device_id.as_str()) + }) + }); + eligible +} + +fn average_queue_wait<'a>(candidates: impl Iterator) -> Option { + let mut sum = 0.0; + let mut count = 0usize; + for candidate in candidates { + sum += candidate.queue_wait_ms(); + count += 1; + } + (count > 0).then_some(sum / count as f64) +} + +fn filter_remote_imbalance( + candidates: Vec, + config: &ReplicaTaskPlacementConfig, +) -> Vec { + let Some(min_count) = candidates + .iter() + .map(|candidate| candidate.node_write_count) + .min() + else { + return candidates; + }; + let max_next = (min_count as f64 + 1.0) * config.role_max_shard_imbalance; + let filtered: Vec = candidates + .iter() + .filter(|candidate| candidate.node_write_count as f64 + 1.0 <= max_next) + .cloned() + .collect(); + if filtered.is_empty() { + candidates + } else { + filtered + } +} + +fn order_pressure_role_queue_aware( + candidates: Vec, + config: &ReplicaTaskPlacementConfig, +) -> Vec { + let remote_candidates: Vec = candidates + .iter() + .filter(|candidate| candidate.is_remote_only_role) + .cloned() + .collect(); + if remote_candidates.is_empty() { + return order_queue_aware(candidates); + } + + let active_wait = average_queue_wait(candidates.iter().filter(|candidate| { + candidate.is_active_role || (!candidate.is_remote_only_role && !candidate.is_active_role) + })); + let remote_wait = average_queue_wait(remote_candidates.iter()); + if let (Some(active_wait), Some(remote_wait)) = (active_wait, remote_wait) { + let gap = active_wait - remote_wait; + let fabric_guard_ok = + config.role_fabric_guard_ms == 0.0 || gap <= config.role_fabric_guard_ms; + if gap >= config.role_pressure_gap_ms && fabric_guard_ok { + let mut remote_candidates = filter_remote_imbalance(remote_candidates, config); + sort_by_queue_score(&mut remote_candidates); + return remote_candidates; + } + } + + order_queue_aware(candidates) +} + +fn order_remote_candidates( + candidates: Vec, + config: &ReplicaTaskPlacementConfig, +) -> Vec { + match config.policy { + ReplicaTaskPlacementPolicyKind::LocalFirst | ReplicaTaskPlacementPolicyKind::Random => { + let mut candidates = candidates; + candidates.shuffle(&mut rand::thread_rng()); + candidates + } + ReplicaTaskPlacementPolicyKind::QueueAware => order_queue_aware(candidates), + ReplicaTaskPlacementPolicyKind::WeightedRoleAware => { + order_weighted_role_aware(candidates, config) + } + ReplicaTaskPlacementPolicyKind::BoundedRoleQueueAware => { + order_bounded_role_queue_aware(candidates, config) + } + ReplicaTaskPlacementPolicyKind::PressureRoleQueueAware => { + order_pressure_role_queue_aware(candidates, config) + } + } +} + +fn try_allocate_candidates( + candidates: Vec, + len: u64, + last_no_space_ctx: &mut Option, +) -> Option<(NodeID, Arc, Allocation)> { + for candidate in candidates { + *last_no_space_ctx = Some(( + candidate.node_id.as_ref().to_string(), + candidate.allocator.seg_device_id.clone(), + candidate.total_bytes, + candidate.free_bytes, + )); + if let Ok(allocation) = candidate.allocator.allocate(len) { + return Some((candidate.node_id, candidate.allocator, allocation)); + } + } + None +} + +fn choose_random_remote_target_with_allocator( + view: &MasterKvRouterView, + source_node_id: &NodeID, + excluded_nodes: &HashSet, + preferred_sub_cluster: Option<&str>, + len: u64, +) -> Result<(NodeID, Arc, Allocation), KvError> { + let seg_manager = view.master_seg_manager(); + let mut last_no_space_ctx: Option = None; + + if let Some(sc) = preferred_sub_cluster { + let mut preferred_nodes: Vec = view + .cluster_manager() + .get_client_members() + .into_iter() + .filter_map(|m| (m.sub_cluster.as_deref() == Some(sc)).then_some(m.id.into())) + .collect(); + preferred_nodes.retain(|node_id| { + node_id.as_ref() != source_node_id.as_ref() && !excluded_nodes.contains(node_id) + }); + preferred_nodes.shuffle(&mut rand::thread_rng()); + for node_id in preferred_nodes { + let node_allocators = seg_manager.get_node_allocators(&node_id); + let Some(allocator) = node_allocators.choose(&mut rand::thread_rng()).cloned() else { + continue; + }; + let total = allocator.total_size_bytes(); + let used = allocator.used_size_bytes(); + let free = total.saturating_sub(used); + last_no_space_ctx = Some(( + node_id.as_ref().to_string(), + allocator.seg_device_id.clone(), + total, + free, + )); + if let Ok(allocation) = allocator.allocate(len) { + return Ok((node_id, allocator, allocation)); + } + } + } + + let all_segs = seg_manager.get_all_segments_allocator(); + let mut candidates: Vec<(NodeID, Arc)> = all_segs + .into_iter() + .filter_map(|(node_id, allocator)| { + if node_id.as_ref() == source_node_id.as_ref() || excluded_nodes.contains(&node_id) { + return None; + } + Some((node_id, allocator)) + }) + .collect(); + candidates.shuffle(&mut rand::thread_rng()); + for (node_id, allocator) in candidates { + let total = allocator.total_size_bytes(); + let used = allocator.used_size_bytes(); + let free = total.saturating_sub(used); + last_no_space_ctx = Some(( + node_id.as_ref().to_string(), + allocator.seg_device_id.clone(), + total, + free, + )); + if let Ok(allocation) = allocator.allocate(len) { + return Ok((node_id, allocator, allocation)); + } + } + + Err(no_space_error(last_no_space_ctx)) +} + +fn choose_random_remote_target( + view: &MasterKvRouterView, + source_node_id: &NodeID, + excluded_nodes: &HashSet, + preferred_sub_cluster: Option<&str>, + len: u64, +) -> Result<(NodeID, Allocation), KvError> { + choose_random_remote_target_with_allocator( + view, + source_node_id, + excluded_nodes, + preferred_sub_cluster, + len, + ) + .map(|(node_id, _allocator, allocation)| (node_id, allocation)) +} + +pub struct ReplicaTaskPlacementPolicy { + config: ReplicaTaskPlacementConfig, +} + +impl ReplicaTaskPlacementPolicy { + pub fn new(config: ReplicaTaskPlacementConfig) -> Self { + Self { config } + } + + fn select_remote_target_with_allocator( + &self, + view: &MasterKvRouterView, + source_node_id: &NodeID, + excluded_nodes: &HashSet, + preferred_sub_cluster: Option<&str>, + len: u64, + ) -> Result<(NodeID, Arc, Allocation), KvError> { + let mut last_no_space_ctx: Option = None; + let candidates = choose_candidate_pool( + view, + source_node_id, + excluded_nodes, + preferred_sub_cluster, + &self.config, + ); + let ordered = order_remote_candidates(candidates, &self.config); + if let Some(selected) = try_allocate_candidates(ordered, len, &mut last_no_space_ctx) { + return Ok(selected); + } + + if preferred_sub_cluster.is_some() { + let global_candidates = + choose_candidate_pool(view, source_node_id, excluded_nodes, None, &self.config); + let ordered = order_remote_candidates(global_candidates, &self.config); + if let Some(selected) = try_allocate_candidates(ordered, len, &mut last_no_space_ctx) { + return Ok(selected); + } + } + + Err(no_space_error(last_no_space_ctx)) + } +} + +#[async_trait] +impl PlacementPolicy for ReplicaTaskPlacementPolicy { + async fn select_put_target( + &self, + view: &MasterKvRouterView, + req_node_id: &NodeID, + preferred_sub_cluster: Option<&str>, + len: u64, + ) -> Result { + self.select_remote_target_with_allocator( + view, + req_node_id, + &HashSet::new(), + preferred_sub_cluster, + len, + ) + .map( + |(node_id, _allocator, allocation)| PutPlacementTarget::Remote { + node_id, + allocation, + }, + ) + } + + fn select_remote_target( + &self, + view: &MasterKvRouterView, + source_node_id: &NodeID, + excluded_nodes: &HashSet, + preferred_sub_cluster: Option<&str>, + len: u64, + ) -> Result<(NodeID, Allocation), KvError> { + self.select_remote_target_with_allocator( + view, + source_node_id, + excluded_nodes, + preferred_sub_cluster, + len, + ) + .map(|(node_id, _allocator, allocation)| (node_id, allocation)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::config::{ReplicaTaskPlacementConfig, ReplicaTaskPlacementPolicyKind}; + use crate::master_seg_manager::msg_pack::SegmentDeviceDescription; + + fn test_allocator(id: &str) -> Arc { + Arc::new( + OneSegAllocator::new( + id.to_string(), + SegmentDeviceDescription::Cpu, + 0, + 1024 * 1024, + ) + .unwrap(), + ) + } + + fn candidate( + node_id: &str, + is_remote_only_role: bool, + node_write_count: u64, + ) -> PlacementCandidate { + PlacementCandidate { + node_id: node_id.to_string().into(), + allocator: test_allocator(node_id), + total_bytes: 1024 * 1024, + free_bytes: 1024 * 1024, + used_bytes: 0, + node_write_count, + requester_target_count: 0, + is_remote_only_role, + is_active_role: !is_remote_only_role, + preferred_sub_cluster_match: false, + } + } + + #[test] + fn bounded_role_queue_aware_prefers_remote_only_within_window() { + let mut config = ReplicaTaskPlacementConfig::default(); + config.policy = ReplicaTaskPlacementPolicyKind::BoundedRoleQueueAware; + config.role_queue_window_ms = 2.0; + config.remote_only_shard_weight = 1.02; + + let ordered = order_bounded_role_queue_aware( + vec![ + candidate("active-a", false, 0), + candidate("remote-a", true, 1), + ], + &config, + ); + assert_eq!(ordered[0].node_id.as_ref(), "remote-a"); + } + + #[test] + fn strict_remote_only_candidates_filter_out_active_nodes() { + let filtered = filter_remote_only_candidates(&[ + candidate("prefill-a", false, 0), + candidate("decode-a", false, 0), + candidate("remote-cache-a", true, 10), + ]); + + assert_eq!(filtered.len(), 1); + assert_eq!(filtered[0].node_id.as_ref(), "remote-cache-a"); + } +} diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs index e8598e8..6849105 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs @@ -1,5 +1,9 @@ use super::NodeValueReplicaDesc; use super::{ + CommittedSlotReplica, InflightPutAllocation, InflightPutCommitInfo, InflightPutInfo, + InflightReplicaTaskInfo, KvReplicaBacking, KvRouteInfo, LocalReserveGrantInfo, + MasterKvRouterView, OwnerHoldingGetInfo, PreparedPutKeyReservationInfo, PutPlacementMode, + ReservedCapacityReason, msg_pack::{ BatchPreparePutKeysReq, BatchPreparePutKeysResp, BatchPutDoneItemResp, BatchPutDoneReq, BatchPutDoneResp, BatchPutRevokeItemResp, BatchPutRevokeReq, BatchPutRevokeResp, @@ -11,22 +15,19 @@ use super::{ ReserveLocalGrantResp, }, placement::PutPlacementTarget, - CommittedSlotReplica, InflightPutAllocation, InflightPutAppendInfo, InflightPutCommitInfo, - InflightPutInfo, KvReplicaBacking, KvRouteInfo, LocalReserveGrantInfo, MasterKvRouterView, - OwnerHoldingGetInfo, PreparedPutKeyReservationInfo, PutPlacementMode, ReservedCapacityReason, }; -use crate::master_kv_router::delete::DeleteKeyInfo; use crate::master_kv_router::OneKvNodesRoutes; +use crate::master_kv_router::delete::DeleteKeyInfo; use crate::memholder::MemholderManagerTrait; use crate::{ + OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES, cluster_manager::{ - NodeID, META_KEY_LOCAL_IPC_ROOT, META_KEY_SHARED_STORAGE_NODE_ID, - META_KEY_SHARED_STORAGE_NODE_START_TIME, + META_KEY_LOCAL_IPC_ROOT, META_KEY_SHARED_STORAGE_NODE_ID, + META_KEY_SHARED_STORAGE_NODE_START_TIME, NodeID, }, - master_seg_manager::{one_seg_allocator::Allocation, MasterSegManagerAccessTrait}, + master_seg_manager::{MasterSegManagerAccessTrait, one_seg_allocator::Allocation}, p2p::msg_pack::MsgPack, rpcresp_kvresult_convert::msg_and_error::{self, kv}, - OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES, }; use chrono::Utc; use limit_thirdparty::tokio; @@ -35,7 +36,7 @@ use parking_lot::RwLock; use rand::seq::SliceRandom; use std::{ collections::{HashMap, HashSet}, - sync::{atomic::AtomicU32, Arc}, + sync::{Arc, atomic::AtomicU32}, }; pub type PutIDForAKey = (u64, u32); @@ -268,96 +269,6 @@ fn append_current_route_replica_if_matching( true } -fn choose_remote_append_target( - view: &MasterKvRouterView, - source_node_id: &NodeID, - excluded_nodes: &HashSet, - preferred_sub_cluster: Option<&str>, - len: u64, -) -> msg_and_error::KvResult<(NodeID, Allocation)> { - let seg_manager = view.master_seg_manager(); - let mut last_no_space_ctx: Option<(String, String, u64, u64)> = None; - - if let Some(sc) = preferred_sub_cluster { - let mut preferred_nodes: Vec = view - .cluster_manager() - .get_client_members() - .into_iter() - .filter_map(|m| (m.sub_cluster.as_deref() == Some(sc)).then_some(m.id.into())) - .collect(); - preferred_nodes.retain(|node_id| { - node_id.as_ref() != source_node_id.as_ref() && !excluded_nodes.contains(node_id) - }); - preferred_nodes.shuffle(&mut rand::thread_rng()); - for node_id in preferred_nodes { - let node_allocators = seg_manager.get_node_allocators(&node_id); - let Some(allocator) = node_allocators.choose(&mut rand::thread_rng()).cloned() else { - continue; - }; - let total = allocator.total_size_bytes(); - let used = allocator.used_size_bytes(); - let free = total.saturating_sub(used); - last_no_space_ctx = Some(( - node_id.as_ref().to_string(), - allocator.seg_device_id.clone(), - total, - free, - )); - if let Ok(allocation) = allocator.allocate(len) { - return Ok((node_id, allocation)); - } - } - } - - let all_segs = seg_manager.get_all_segments_allocator(); - let mut candidates: Vec<( - NodeID, - Arc, - )> = all_segs - .into_iter() - .filter_map(|(node_id, allocator)| { - let node_id: NodeID = node_id.into(); - if node_id.as_ref() == source_node_id.as_ref() || excluded_nodes.contains(&node_id) { - return None; - } - Some((node_id, allocator)) - }) - .collect(); - candidates.shuffle(&mut rand::thread_rng()); - for (node_id, allocator) in candidates { - let total = allocator.total_size_bytes(); - let used = allocator.used_size_bytes(); - let free = total.saturating_sub(used); - last_no_space_ctx = Some(( - node_id.as_ref().to_string(), - allocator.seg_device_id.clone(), - total, - free, - )); - if let Ok(allocation) = allocator.allocate(len) { - return Ok((node_id, allocation)); - } - } - - Err( - if let Some((node, segment, total_capacity, free_capacity)) = last_no_space_ctx { - msg_and_error::KvError::Api(msg_and_error::ApiError::NoSpace { - node, - segment, - total_capacity, - free_capacity, - }) - } else { - msg_and_error::KvError::Api(msg_and_error::ApiError::NoSpace { - node: "unknown".to_string(), - segment: "unknown".to_string(), - total_capacity: 0, - free_capacity: 0, - }) - }, - ) -} - fn allocate_from_node_local_segment( view: &MasterKvRouterView, node_id: &NodeID, @@ -404,23 +315,47 @@ fn allocate_from_node_local_segment( )) } -fn reserve_write_back_remote_append( +fn reserve_replica_task( view: &MasterKvRouterView, key: &str, put_id: PutIDForAKey, source_node_id: &NodeID, preferred_sub_cluster: Option<&str>, len: u64, -) -> msg_and_error::KvResult { - let (target_node_id, target_allocation) = choose_remote_append_target( +) -> msg_and_error::KvResult { + reserve_replica_task_excluding( view, + key, + put_id, source_node_id, - &HashSet::new(), preferred_sub_cluster, len, - )?; + &HashSet::new(), + ) +} + +fn reserve_replica_task_excluding( + view: &MasterKvRouterView, + key: &str, + put_id: PutIDForAKey, + source_node_id: &NodeID, + preferred_sub_cluster: Option<&str>, + len: u64, + excluded_nodes: &HashSet, +) -> msg_and_error::KvResult { + let (target_node_id, target_allocation) = view + .master_kv_router() + .inner() + .policy + .select_remote_target( + view, + source_node_id, + excluded_nodes, + preferred_sub_cluster, + len, + )?; tracing::debug!( - "write-back remote append reserved: key={} put_id=({},{}) source_node_id={} target_node_id={} preferred_sub_cluster={:?} len={}", + "replica task reserved: key={} put_id=({},{}) source_node_id={} target_node_id={} preferred_sub_cluster={:?} len={}", key, put_id.0, put_id.1, @@ -429,7 +364,7 @@ fn reserve_write_back_remote_append( preferred_sub_cluster, len ); - Ok(InflightPutAppendInfo { + Ok(InflightReplicaTaskInfo { node_id: target_node_id, key: key.to_string(), put_id, @@ -437,44 +372,132 @@ fn reserve_write_back_remote_append( }) } -fn try_reserve_write_back_remote_append( - view: &MasterKvRouterView, - key: &str, +async fn publish_completed_put_route( + view: MasterKvRouterView, + key: String, put_id: PutIDForAKey, - source_node_id: &NodeID, - preferred_sub_cluster: Option<&str>, - len: u64, -) -> msg_and_error::KvResult> { - match reserve_write_back_remote_append( - view, - key, - put_id, - source_node_id, - preferred_sub_cluster, - len, - ) { - Ok(reserved) => Ok(Some(reserved)), - Err(msg_and_error::KvError::Api(msg_and_error::ApiError::NoSpace { - node, - segment, - total_capacity, - free_capacity, - })) => { - tracing::info!( - "write-back remote append not scheduled; fallback to local-only commit: key={} put_id=({},{}) source_node_id={} preferred_sub_cluster={:?} node={} segment={} total_capacity={} free_capacity={}", - key, - put_id.0, - put_id.1, - source_node_id, - preferred_sub_cluster, - node, - segment, - total_capacity, - free_capacity - ); - Ok(None) + lease_id_opt: Option, + node_id: NodeID, + completed_info: KvRouteInfo, + target_cap_bytes: u64, + local_cache_holder_id: Option, +) -> MsgPack { + let saturated_weight_u32 = if target_cap_bytes > u32::MAX as u64 { + tracing::warn!( + "moka weight saturation: key={} put_id=({},{}) cap={}B exceeds u32::MAX; weight set to u32::MAX", + key, + put_id.0, + put_id.1, + target_cap_bytes + ); + u32::MAX + } else { + target_cap_bytes as u32 + }; + + let mut old_one_kv_routes: Option> = None; + let mut inserted = false; + { + let mut one_kv_routes = view + .master_kv_router() + .inner() + .kv_routes + .entry(key.clone()) + .or_insert_with(|| { + inserted = true; + Arc::new(OneKvNodesRoutes { + put_id, + lease_id: lease_id_opt, + nodes_replicas: RwLock::new(HashMap::new()), + get_durable_slots_used: AtomicU32::new(0), + }) + }); + if !inserted { + old_one_kv_routes = Some(one_kv_routes.clone()); + *one_kv_routes = Arc::new(OneKvNodesRoutes { + put_id, + lease_id: lease_id_opt, + nodes_replicas: RwLock::new(HashMap::new()), + get_durable_slots_used: AtomicU32::new(0), + }); } - Err(err) => Err(err), + one_kv_routes + .nodes_replicas + .write() + .insert(node_id.clone(), completed_info); + } + + if let Some(old) = old_one_kv_routes { + if let Err(err) = view + .master_kv_router() + .inner() + .delete_broadcast + .sender() + .send(DeleteKeyInfo::Key { + key: key.clone(), + nodes_kv_route_info: old, + }) + .await + { + tracing::warn!("Failed to send delete broadcast: {}", err); + } + } + + { + let view_task = view.clone(); + let key_for_spawn = key.clone(); + let node_for_spawn = node_id.clone(); + let do_prefix_index_update = view.master_kv_router().prefix_index_enabled(); + let do_cache_insert = + lease_id_opt.is_none() && view.master_kv_router().replica_cache_enabled(); + let cap_bytes_u32 = saturated_weight_u32; + view.spawn("post_put_done_maintenance", async move { + if do_prefix_index_update { + let inner = view_task.master_kv_router().inner(); + let mut tree = inner.prefix_index.write().await; + tree.insert(&key_for_spawn); + } + + if do_cache_insert { + let cache = view_task + .master_kv_router() + .get_node_cache_controller(&node_for_spawn); + if let Some(cache) = cache { + let desc = NodeValueReplicaDesc { + weight_bytes: cap_bytes_u32, + put_id, + }; + tracing::debug!("Inserting key: {:?} into cache", key_for_spawn); + cache.insert(key_for_spawn.clone(), desc); + tracing::debug!( + "Inserted key: {:?} into cache, current cache size: {}", + key_for_spawn, + cache.weighted_size() + ); + } else { + tracing::warn!( + "No cache controller found for node: {}, node is not ready", + node_for_spawn + ); + } + } + }); + } + + tracing::info!( + "Completed put operation with put_id: {:?}, key: {:?}", + put_id, + key + ); + + MsgPack { + serialize_part: PutDoneResp { + error_code: msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + local_cache_holder_id, + }, + raw_bytes: Vec::new(), } } @@ -550,12 +573,12 @@ pub async fn handle_put_start( let finalize = |commit_node_id: NodeID, response_node_id: NodeID, inflight_alloc: InflightPutAllocation, - remote_append: Option, src_addr: u64, target_addr: u64, src_base_addr: u64, target_base_addr: u64, - len: u64| { + len: u64, + replica_target: Option| { let info = InflightPutInfo { key: key.clone(), len, @@ -563,8 +586,8 @@ pub async fn handle_put_start( commit_info: InflightPutCommitInfo { node_id: commit_node_id, src_target_allocation: Arc::new(Mutex::new(Some(inflight_alloc))), + replica_target: replica_target.clone(), }, - remote_append, }; let view_task = view.clone(); @@ -577,6 +600,19 @@ pub async fn handle_put_start( .insert(inflight_put_key, info) .await; + let response_replica_target = replica_target.as_ref().map(|target| { + let target_allocation_guard = target.target_allocation.lock(); + let target_allocation = target_allocation_guard.as_ref().expect( + "replica target allocation must exist while building put_start response", + ); + super::msg_pack::PutReplicaTarget { + node_id: target.node_id.clone().into(), + target_addr: target_allocation.base_addr() + target_allocation.addr(), + target_base_addr: target_allocation.base_addr(), + len: target_allocation.size(), + } + }); + let resp = PutStartResp { put_id, node_id: response_node_id.into(), @@ -588,6 +624,7 @@ pub async fn handle_put_start( error_code: msg_and_error::OK, error_json: String::new(), server_process_us: 0, + replica_target: response_replica_target, }; ( @@ -600,22 +637,9 @@ pub async fn handle_put_start( } }; - let put_target = if req.serialize_part.write_through { - view.master_kv_router() - .inner() - .policy - .select_put_target( - &view, - &source_node_id, - req.serialize_part.preferred_sub_cluster.as_deref(), - req.serialize_part.len, - ) - .await - } else { - Ok(PutPlacementTarget::Local { - node_id: source_node_id.clone(), - }) - }; + let put_target = Ok(PutPlacementTarget::Local { + node_id: source_node_id.clone(), + }); match put_target { Ok(PutPlacementTarget::Local { node_id }) => { @@ -653,10 +677,8 @@ pub async fn handle_put_start( let src = src_allocation .take() .expect("src_allocation must exist when finalizing local put"); - let remote_append = if req.serialize_part.write_through { - None - } else { - match try_reserve_write_back_remote_append( + let replica_target = if req.serialize_part.make_replica_task { + match reserve_replica_task( &view, &key, put_id, @@ -664,47 +686,57 @@ pub async fn handle_put_start( req.serialize_part.preferred_sub_cluster.as_deref(), req.serialize_part.len, ) { - Ok(reserved) => reserved, + Ok(reservation) => { + view.master_kv_router() + .record_replica_task_target(reservation.node_id.as_ref()); + Some(reservation) + } + Err(msg_and_error::KvError::Api(msg_and_error::ApiError::NoSpace { + node, + segment, + total_capacity, + free_capacity, + })) => { + tracing::info!( + "replica task not pre-reserved; local-only commit remains valid: key={} put_id=({},{}) source_node_id={} preferred_sub_cluster={:?} node={} segment={} total_capacity={} free_capacity={}", + key, + put_id.0, + put_id.1, + source_node_id, + req.serialize_part.preferred_sub_cluster, + node, + segment, + total_capacity, + free_capacity + ); + None + } Err(err) => { - let resp: PutStartResp = - crate::rpcresp_kvresult_convert::FromError::from_error(&err); - return ( - (0, 0), - MsgPack { - serialize_part: resp, - raw_bytes: Vec::new(), - }, + tracing::warn!( + "replica task pre-reserve failed; local-only commit remains valid: key={} put_id=({},{}) source_node_id={} preferred_sub_cluster={:?} err={}", + key, + put_id.0, + put_id.1, + source_node_id, + req.serialize_part.preferred_sub_cluster, + err ); + None } } + } else { + None }; - let (response_node_id, response_target_addr, response_target_base_addr, response_len) = - if let Some(remote_append) = remote_append.as_ref() { - let target_allocation_guard = remote_append.target_allocation.lock(); - let target_allocation = target_allocation_guard - .as_ref() - .expect("reserved remote append allocation must exist during put_start"); - let target_base = target_allocation.base_addr(); - let target_addr = target_base + target_allocation.addr(); - ( - remote_append.node_id.clone(), - target_addr, - target_base, - target_allocation.size(), - ) - } else { - (node_id.clone(), abs, src_base, allocation_size) - }; let fut = finalize( + node_id.clone(), node_id, - response_node_id, InflightPutAllocation::Local(src), - remote_append, abs, - response_target_addr, + abs, + src_base, src_base, - response_target_base_addr, - response_len, + allocation_size, + replica_target, ); let result = fut.await; key_reservation.disarm(); @@ -754,12 +786,12 @@ pub async fn handle_put_start( src, target: target_allocation, }, - None, src_base + src_offset, target_base + target_offset, src_base, target_base, allocation_size, + None, ); let result = fut.await; key_reservation.disarm(); @@ -1057,6 +1089,7 @@ pub async fn handle_put_revoke( pub async fn handle_put_done( view: MasterKvRouterView, req: MsgPack, + req_node_id: NodeID, ) -> MsgPack { tracing::debug!("Handling PutDoneReq: {:?}", req.serialize_part); @@ -1067,10 +1100,7 @@ pub async fn handle_put_done( // Remove from inflight_puts and store in completed_puts if let Some(InflightPutInfo { - key, - commit_info, - remote_append, - .. + key, commit_info, .. }) = view .master_kv_router() .inner() @@ -1453,17 +1483,17 @@ pub async fn handle_put_done( .insert(node_id.clone(), completed_info); } - if let Some(remote_append) = remote_append { + if let Some(replica_target) = commit_info.replica_target { view.master_kv_router() .inner() - .inflight_put_appends + .inflight_replica_tasks .insert( ( - remote_append.key.clone(), - remote_append.put_id.0, - remote_append.put_id.1, + replica_target.key.clone(), + replica_target.put_id.0, + replica_target.put_id.1, ), - remote_append, + replica_target, ) .await; } @@ -1541,6 +1571,104 @@ pub async fn handle_put_done( key ); } else { + if let Some(slot) = req.serialize_part.committed_slot.clone() { + let key = req.serialize_part.key.clone(); + let node_id = req_node_id; + let Some(tomb_tag) = view.master_seg_manager().get_node_tomb_tag(&node_id) else { + let err = msg_and_error::KvError::Api( + msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "local-first put_done node tomb tag missing: key={} put_id=({},{}) node_id={}", + key, put_id.0, put_id.1, node_id + ), + }, + ); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), + raw_bytes: Vec::new(), + }; + }; + if tomb_tag.is_tomb() { + let err = + msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "local-first put_done node is tomb: key={} put_id=({},{}) node_id={}", + key, put_id.0, put_id.1, node_id + ), + }); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), + raw_bytes: Vec::new(), + }; + } + if req.serialize_part.publish_local_cache { + let err = msg_and_error::KvError::Api( + msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "local-first put_done does not support publish_local_cache: key={} put_id=({},{})", + key, put_id.0, put_id.1 + ), + }, + ); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), + raw_bytes: Vec::new(), + }; + } + let target_cap_bytes = slot.len; + if let Some(lease_id) = lease_id_opt { + if let Err(e) = view + .master_lease_manager() + .attach_key(lease_id, key.clone(), put_id) + .await + { + let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = e.into(); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error( + &kv_err, + ), + raw_bytes: Vec::new(), + }; + } + if let Err(e) = view.master_kv_router().adjust_node_cache_reserved_capacity( + node_id.as_ref(), + ReservedCapacityReason::LeaseBoundKv, + target_cap_bytes as i64, + ) { + let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = e.into(); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error( + &kv_err, + ), + raw_bytes: Vec::new(), + }; + } + } + let completed_info = KvRouteInfo { + node_id: node_id.clone(), + backing: KvReplicaBacking::CommittedSlot(CommittedSlotReplica { + owner_node_id: node_id.clone(), + grant_id: slot.grant_id, + slot_index: slot.slot_index, + slot_size: slot.slot_size, + addr: slot.addr, + len: slot.len, + base_addr: slot.base_addr, + }), + tomb_tag, + }; + return publish_completed_put_route( + view, + key, + put_id, + lease_id_opt, + node_id, + completed_info, + target_cap_bytes, + None, + ) + .await; + } tracing::warn!( "Put operation with put_id {:?} not found for completion", put_id @@ -1580,7 +1708,7 @@ pub async fn handle_batch_put_start( len: item.len, reject_if_inflight_same_key: item.reject_if_inflight_same_key, reject_if_exist_same_key: item.reject_if_exist_same_key, - write_through: item.write_through, + make_replica_task: item.make_replica_task, preferred_sub_cluster: item.preferred_sub_cluster, source_node_id: None, }, @@ -1600,6 +1728,7 @@ pub async fn handle_batch_put_start( len: part.len, error_code: part.error_code, error_json: part.error_json, + replica_target: part.replica_target, }); } MsgPack { @@ -1650,6 +1779,7 @@ pub async fn handle_batch_put_revoke( pub async fn handle_batch_put_done( view: MasterKvRouterView, req: MsgPack, + req_node_id: NodeID, ) -> MsgPack { let mut items = Vec::with_capacity(req.serialize_part.items.len()); for item in req.serialize_part.items { @@ -1668,6 +1798,7 @@ pub async fn handle_batch_put_done( }, raw_bytes: Vec::new(), }, + req_node_id.clone(), ) .await; let part = resp.serialize_part; @@ -1697,18 +1828,21 @@ pub async fn handle_put_append_start( ) -> MsgPack { let key = req.serialize_part.key.clone(); let put_id = req.serialize_part.put_id; - let current_route_still_needs_remote = view + let route_snapshot = view .master_kv_router() .inner() .kv_routes .get(&key) - .map(|route| current_route_needs_remote_replica(&route, &req_node_id, put_id)) + .map(|route| route.clone()); + let current_route_still_needs_remote = route_snapshot + .as_ref() + .map(|route| current_route_needs_remote_replica(route, &req_node_id, put_id)) .unwrap_or(false); if !current_route_still_needs_remote { let _ = view .master_kv_router() .inner() - .inflight_put_appends + .inflight_replica_tasks .remove(&(key.clone(), put_id.0, put_id.1)) .await; return MsgPack { @@ -1722,31 +1856,91 @@ pub async fn handle_put_append_start( }; } - let Some(inflight) = view + let append_key = (key.clone(), put_id.0, put_id.1); + let inflight = if let Some(existing) = view .master_kv_router() .inner() - .inflight_put_appends - .get(&(key.clone(), put_id.0, put_id.1)) + .inflight_replica_tasks + .get(&append_key) .await - else { - let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { - detail: format!( - "Write-back append reservation missing: key={} put_id=({},{}) requester_node_id={}", - key, put_id.0, put_id.1, req_node_id - ), - }); - let resp: PutAppendStartResp = crate::rpcresp_kvresult_convert::FromError::from_error(&err); - return MsgPack { - serialize_part: resp, - raw_bytes: Vec::new(), + { + existing + } else { + let excluded_nodes = route_snapshot + .as_ref() + .map(|route| { + route + .nodes_replicas + .read() + .values() + .filter_map(|replica| { + (!replica.tomb_tag.is_tomb()).then_some(replica.node_id.clone()) + }) + .collect::>() + }) + .unwrap_or_default(); + let reservation = match reserve_replica_task_excluding( + &view, + &key, + put_id, + &req_node_id, + req.serialize_part.preferred_sub_cluster.as_deref(), + req.serialize_part.len, + &excluded_nodes, + ) { + Ok(reservation) => reservation, + Err(msg_and_error::KvError::Api(msg_and_error::ApiError::NoSpace { + node, + segment, + total_capacity, + free_capacity, + })) => { + tracing::info!( + "replica task not scheduled; local-only commit remains valid: key={} put_id=({},{}) source_node_id={} preferred_sub_cluster={:?} node={} segment={} total_capacity={} free_capacity={}", + key, + put_id.0, + put_id.1, + req_node_id, + req.serialize_part.preferred_sub_cluster, + node, + segment, + total_capacity, + free_capacity + ); + return MsgPack { + serialize_part: PutAppendStartResp { + scheduled: false, + error_code: msg_and_error::OK, + error_json: String::new(), + ..Default::default() + }, + raw_bytes: Vec::new(), + }; + } + Err(err) => { + let resp: PutAppendStartResp = + crate::rpcresp_kvresult_convert::FromError::from_error(&err); + return MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + }; + } }; + view.master_kv_router() + .record_replica_task_target(reservation.node_id.as_ref()); + view.master_kv_router() + .inner() + .inflight_replica_tasks + .insert(append_key.clone(), reservation.clone()) + .await; + reservation }; let (target_base_addr, target_addr, allocation_size) = { let target_allocation_guard = inflight.target_allocation.lock(); let Some(target_allocation): Option<&Allocation> = target_allocation_guard.as_ref() else { let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { detail: format!( - "Write-back append reservation allocation missing: key={} put_id=({},{}) requester_node_id={}", + "Replica task reservation allocation missing: key={} put_id=({},{}) requester_node_id={}", key, put_id.0, put_id.1, req_node_id ), }); @@ -1787,7 +1981,7 @@ pub async fn handle_put_append_revoke( let _ = view .master_kv_router() .inner() - .inflight_put_appends + .inflight_replica_tasks .remove(&(key, put_id.0, put_id.1)) .await; MsgPack { @@ -1808,7 +2002,7 @@ pub async fn handle_put_append_done( let Some(inflight) = view .master_kv_router() .inner() - .inflight_put_appends + .inflight_replica_tasks .remove(&(key.clone(), put_id.0, put_id.1)) .await else { @@ -1826,7 +2020,7 @@ pub async fn handle_put_append_done( let Some(allocation) = inflight.target_allocation.lock().take() else { let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { detail: format!( - "Put append target allocation already taken: key={} put_id=({},{})", + "Replica task append target allocation already taken: key={} put_id=({},{})", key, put_id.0, put_id.1 ), }); diff --git a/fluxon_rs/fluxon_kv/src/master_lease_manager/lease_manager_test.rs b/fluxon_rs/fluxon_kv/src/master_lease_manager/lease_manager_test.rs index 6b84528..5d344c9 100755 --- a/fluxon_rs/fluxon_kv/src/master_lease_manager/lease_manager_test.rs +++ b/fluxon_rs/fluxon_kv/src/master_lease_manager/lease_manager_test.rs @@ -49,12 +49,14 @@ async fn test1_lease_expire_removes_keys() { tracing::info!("[test1-verify-present-during-ttl] verifying keys exist within TTL window"); for _ in 0..3 { for k in &keys { - assert!(client_view - .client_kv_api() - .inner() - .is_exist(k) - .await - .unwrap()); + assert!( + client_view + .client_kv_api() + .inner() + .is_exist(k) + .await + .unwrap() + ); } sleep(Duration::from_millis(500)).await; } @@ -120,12 +122,14 @@ async fn test2_rebind_to_new_lease_preserves_until_new_expire() { // After l1 expiry, keys should still exist due to l2 sleep(Duration::from_secs(3)).await; for k in &keys { - assert!(client_view - .client_kv_api() - .inner() - .is_exist(k) - .await - .unwrap()); + assert!( + client_view + .client_kv_api() + .inner() + .is_exist(k) + .await + .unwrap() + ); } tracing::info!( "[test2-verify-still-present-after-first-expire] keys still exist after first lease expired, held by second lease" @@ -192,12 +196,14 @@ async fn test3_keepalive() { .await .unwrap(); for k in &keys { - assert!(client_view - .client_kv_api() - .inner() - .is_exist(k) - .await - .unwrap()); + assert!( + client_view + .client_kv_api() + .inner() + .is_exist(k) + .await + .unwrap() + ); } if i % 2 == 0 { tracing::info!( @@ -211,12 +217,14 @@ async fn test3_keepalive() { // Stop keepalive, wait beyond TTL sleep(Duration::from_secs(3)).await; for k in &keys { - assert!(!client_view - .client_kv_api() - .inner() - .is_exist(k) - .await - .unwrap()); + assert!( + !client_view + .client_kv_api() + .inner() + .is_exist(k) + .await + .unwrap() + ); } tracing::info!( "[test3-stop-keepalive-wait-verify-missing] verified keys removed after stopping keepalive and waiting past TTL" @@ -259,12 +267,14 @@ async fn test4_delete_under_lease_then_get_fails() { } sleep(Duration::from_secs(2)).await; for k in &keys { - assert!(!client_view - .client_kv_api() - .inner() - .is_exist(k) - .await - .unwrap()); + assert!( + !client_view + .client_kv_api() + .inner() + .is_exist(k) + .await + .unwrap() + ); } tracing::info!( "[test4-delete-keys-sleep-2s-verify-missing] deleted keys and verified not exist after delay" diff --git a/fluxon_rs/fluxon_kv/src/memholder/memholder_test.rs b/fluxon_rs/fluxon_kv/src/memholder/memholder_test.rs index 692a9a0..d4a6549 100644 --- a/fluxon_rs/fluxon_kv/src/memholder/memholder_test.rs +++ b/fluxon_rs/fluxon_kv/src/memholder/memholder_test.rs @@ -15,7 +15,7 @@ use limit_thirdparty::tokio::time::sleep; use crate::config::{ ClientConfig, ContributeToClusterPoolSize, FluxonKvSpec, MasterConfig, MonitoringConfig, - ProtocolConfig, ProtocolType, TestSpecConfig, TransferEngineType, + ProtocolConfig, ProtocolType, ReplicaTaskPlacementConfig, TestSpecConfig, TransferEngineType, }; use crate::master_kv_router::MasterKvRouterView; use crate::master_seg_manager::one_seg_allocator::Allocation; @@ -58,6 +58,7 @@ fn new_master_config( log_dir: "/tmp/fluxon_master_logs".to_string(), pprof_duration_seconds: None, master_ui: None, + replica_task_placement: ReplicaTaskPlacementConfig::default(), test_spec_config: TestSpecConfig::default(), } } diff --git a/fluxon_rs/fluxon_pyo3/src/error.rs b/fluxon_rs/fluxon_pyo3/src/error.rs index 652ef0b..06246dc 100644 --- a/fluxon_rs/fluxon_pyo3/src/error.rs +++ b/fluxon_rs/fluxon_pyo3/src/error.rs @@ -1,6 +1,6 @@ +use pyo3::PyErr; use pyo3::prelude::*; use pyo3::types::PyDict; -use pyo3::PyErr; use fluxon_mq::MpscError as CoreMpscError; // Re-export the core MPSC error type for callers who want to depend on a single error hub. diff --git a/fluxon_rs/fluxon_pyo3/src/lib.rs b/fluxon_rs/fluxon_pyo3/src/lib.rs index e86ef21..1b89d76 100644 --- a/fluxon_rs/fluxon_pyo3/src/lib.rs +++ b/fluxon_rs/fluxon_pyo3/src/lib.rs @@ -9,54 +9,51 @@ use std::thread; use bytes::Bytes; use fluxon_cli::config::MonitorConfigYaml as MonitorCliConfigYaml; use fluxon_fs::config::{ - FluxonFsRequestIdentity, FluxonFsS3KvMissPolicy, FsAgentDeclaredExportWire, FLUXON_FS_CONTROL_SCHEMA_VERSION, FS_AGENT_DECLARED_EXPORT_JSON_KEY, FS_AGENT_EXPORT_PUBLISH_RPC_PATH, FS_AGENT_EXPORT_UNPUBLISH_RPC_PATH, - FS_MASTER_CONFIG_RPC_PATH, + FS_MASTER_CONFIG_RPC_PATH, FluxonFsRequestIdentity, FluxonFsS3KvMissPolicy, + FsAgentDeclaredExportWire, }; +use fluxon_kv::OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES; +use fluxon_kv::client_kv_api::ClientKvApiViewTrait; use fluxon_kv::client_kv_api::msg_pack::{ ExternalBatchPutCommitItemReq, ExternalBatchPutCommitReq, ExternalBatchPutStartItemReq, ExternalBatchPutStartReq, ExternalBatchPutTransferEndItemReq, ExternalBatchPutTransferEndReq, ExternalPutRevokeReq, }; -use fluxon_kv::client_kv_api::ClientKvApiViewTrait; use fluxon_kv::client_kv_api::{ - ClientKvApiInner, OwnerLocalReserveSlotLease, OwnerLocalReserveSlotRef, OwnerReservedPutItem, + ClientKvApiInner, OwnerLocalPublishItem, OwnerLocalPublishJob, OwnerLocalReserveSlotLease, }; use fluxon_kv::client_seg_pool::ClientSegPoolViewTrait; -use fluxon_kv::cluster_manager::app_logic_ext::ClusterManagerAppLogicExt; use fluxon_kv::cluster_manager::ClusterManagerViewTrait; +use fluxon_kv::cluster_manager::app_logic_ext::ClusterManagerAppLogicExt; use fluxon_kv::config::{ClientConfigYaml, MasterConfigYaml}; use fluxon_kv::external_client_api::ExternalClientApiViewTrait; -use fluxon_kv::master_kv_router::msg_pack::{ - BatchPreparePutKeyItemReq, BatchPutDoneItemReq, BatchPutRevokeItemReq, BatchPutStartItemReq, - PutDoneCommittedSlot, -}; +use fluxon_kv::master_kv_router::msg_pack::{BatchPreparePutKeyItemReq, PutDoneCommittedSlot}; use fluxon_kv::master_lease_manager::msg_pack::{AllocateClientLeaseReq, ClientLeaseKeepaliveReq}; -use fluxon_kv::memholder::kvclient_encode::{flat_kv_decode_borrowed, BorrowedFlatKvValueRange}; +use fluxon_kv::memholder::kvclient_encode::{BorrowedFlatKvValueRange, flat_kv_decode_borrowed}; use fluxon_kv::memholder::{ - ExternalMemHolder as RustExternalMemHolder, MemoryInfo as RustMemoryInfo, - UserMemHolder as RustUserMemHolder, + ExternalMemHolder as RustExternalMemHolder, UserMemHolder as RustUserMemHolder, }; -use fluxon_kv::p2p::msg_pack::{call_rpc, MsgPack, RPCCaller}; +use fluxon_kv::p2p::msg_pack::{MsgPack, RPCCaller, call_rpc}; use fluxon_kv::p2p::p2p_module::P2pModuleViewTrait; -use fluxon_kv::p2p::p2p_module::{user_rpc_register_handler, UserRpcHandler}; +use fluxon_kv::p2p::p2p_module::{UserRpcHandler, user_rpc_register_handler}; use fluxon_kv::rpcresp_kvresult_convert::msg_and_error::{ ApiError as CoreApiError, KvError as CoreKvError, KvResult, OK, }; use fluxon_kv::user_api::FlatDict; use fluxon_kv::user_api::FlatValue; use fluxon_kv::user_api::FluxonUserApi; -use fluxon_kv::OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES; use fluxon_kv::{ + ConfigArg, Framework, KvClientTrait, KvGetResult, config::{ClientConfig, MasterConfig}, - run_client, run_master, ConfigArg, Framework, KvClientTrait, KvGetResult, + run_client, run_master, }; use fluxon_ops; use fluxon_proxy; -use fluxon_util::run_async_from_sync::{borrow_stable_owner, SyncAsyncBridge}; +use fluxon_util::run_async_from_sync::{SyncAsyncBridge, borrow_stable_owner}; use fluxon_util::{ - fluxon_cli_proxy_desc_etcd_key_v2, FluxonCliProxyDescriptorV2, FluxonCliProxyTransportV2, + FluxonCliProxyDescriptorV2, FluxonCliProxyTransportV2, fluxon_cli_proxy_desc_etcd_key_v2, }; use futures::Future; use pyo3::exceptions::{PyOSError, PyPermissionError, PyRuntimeError, PyValueError}; @@ -77,7 +74,7 @@ include!(env!("FLUXON_PYO3_TEST_PYTHON_LINK_RS")); mod memholder; pub use memholder::{ExternalMemHolder, MemHolder}; mod flatdict_zerocopy; -use flatdict_zerocopy::{decode_flat_dict_to_wrapped_py_object, FlatDictDataOwner}; +use flatdict_zerocopy::{FlatDictDataOwner, decode_flat_dict_to_wrapped_py_object}; mod kvfuture; pub use kvfuture::KvFuture; mod error; @@ -2107,7 +2104,6 @@ enum StagedPutPlanData { struct StagedOwnerPutPlanData { keys: Vec, value_len: u64, - write_through: bool, key_reservation_ids: Vec, slot_lease: OwnerLocalReserveSlotLease, } @@ -2116,7 +2112,6 @@ struct StagedOwnerPutPlanData { struct StagedExternalPutPlanData { keys: Vec, value_len: u64, - write_through: bool, started_time: i64, items: Vec, short_circuit_payload: bool, @@ -2132,13 +2127,6 @@ struct StagedExternalPutItem { target_base_addr: u64, } -#[derive(Clone)] -struct StagedPutCommitItem { - idx: usize, - reserved_item: OwnerReservedPutItem, - slot_ref: OwnerLocalReserveSlotRef, -} - #[derive(Clone, Debug, Default)] struct FluxonIoLocalitySnapshot { op_count: u64, @@ -2321,10 +2309,6 @@ async fn release_put_key_reservations_only( .map(|_| ()) } -fn staged_put_uses_direct_local_commit(item: &OwnerReservedPutItem) -> bool { - !item.write_through || (item.peer_node_id.is_none() && item.src_addr == item.target_addr) -} - fn combine_kv_errors( context: &str, primary_err: CoreKvError, @@ -2338,50 +2322,6 @@ fn combine_kv_errors( }) } -fn remove_precommit_local_visible_infos( - inner: &ClientKvApiInner, - keys: &[String], - memory_infos: &[Arc], -) { - for (key, memory_info) in keys.iter().zip(memory_infos.iter()) { - let _ = inner.remove_precommit_local_reserve_resident_slot_if_same(key, memory_info); - } -} - -fn remove_precommit_local_visible_infos_for_items( - inner: &ClientKvApiInner, - items: &[StagedPutCommitItem], - memory_infos: &[Arc], -) { - for item in items { - let _ = inner.remove_precommit_local_reserve_resident_slot_if_same( - &item.reserved_item.key, - &memory_infos[item.idx], - ); - } -} - -async fn revoke_staged_put_items( - inner: &ClientKvApiInner, - items: &[StagedPutCommitItem], -) -> KvResult<()> { - if items.is_empty() { - return Ok(()); - } - inner - .batch_put_revoke( - items - .iter() - .map(|item| BatchPutRevokeItemReq { - key: item.reserved_item.key.clone(), - put_id: item.reserved_item.put_id, - }) - .collect(), - ) - .await - .map(|_| ()) -} - #[pyfunction] fn decode_flat_dict_payload(payload: Vec, py: Python<'_>) -> PyObject { match decode_flat_dict_to_wrapped_py_object(py, FlatDictDataOwner::from_owned_bytes(payload)) { @@ -3506,14 +3446,13 @@ impl KvClient { release_local_grant_blocking_inner(self, grant_id, py).into_py_object(py) } - #[pyo3(signature = (keys, value_len, reject_if_inflight_same_key=false, reject_if_exist_same_key=false, write_through=true))] + #[pyo3(signature = (keys, value_len, reject_if_inflight_same_key=false, reject_if_exist_same_key=false))] fn local_fast_put_start( &self, keys: Vec, value_len: u64, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, - write_through: bool, py: Python, ) -> PyObject { fn local_fast_put_start_inner( @@ -3522,7 +3461,6 @@ impl KvClient { value_len: u64, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, - write_through: bool, py: Python, ) -> ApiResult { if keys.is_empty() { @@ -3556,7 +3494,6 @@ impl KvClient { )); } }; - if framework.is_external_mode() { let framework_for_start = framework.clone(); let keys_for_req = keys.clone(); @@ -3576,7 +3513,7 @@ impl KvClient { len: value_len, reject_if_inflight_same_key, reject_if_exist_same_key, - write_through, + make_replica_task: true, preferred_sub_cluster: None, }) .collect(), @@ -3729,7 +3666,6 @@ impl KvClient { StagedExternalPutPlanData { keys, value_len, - write_through, started_time, items, short_circuit_payload, @@ -3834,7 +3770,6 @@ impl KvClient { StagedOwnerPutPlanData { keys, value_len, - write_through, key_reservation_ids, slot_lease, }, @@ -3855,7 +3790,6 @@ impl KvClient { value_len, reject_if_inflight_same_key, reject_if_exist_same_key, - write_through, py, ) .into_py_object(py) @@ -3930,7 +3864,6 @@ impl KvClient { remote_target: item.peer_id.is_some(), put_id: Some(item.put_id), lease_id: None, - write_through: external_data.write_through, }) .collect(), started_time: external_data.started_time, @@ -3968,7 +3901,6 @@ impl KvClient { None }, put_id: Some(item.put_id), - write_through: external_data.write_through, lease_id: None, }) .collect(), @@ -3997,27 +3929,33 @@ impl KvClient { StagedPutPlanData::Owner(owner_data) => { let client_kv_api_view = framework_for_commit.client_kv_api_view(); let inner = client_kv_api_view.client_kv_api().inner(); - let start_items = owner_data - .keys - .iter() - .map(|key| BatchPutStartItemReq { - key: key.clone(), - len: owner_data.value_len, - reject_if_inflight_same_key: false, - reject_if_exist_same_key: false, - write_through: owner_data.write_through, - preferred_sub_cluster: None, - }) - .collect::>(); let slot_refs = owner_data.slot_lease.slots.clone(); let slot_size = owner_data.slot_lease.slot_size; - let value_len_usize = match usize::try_from(owner_data.value_len) { + if slot_refs.len() != owner_data.keys.len() { + let err = CoreKvError::Api(CoreApiError::Unknown { + detail: format!( + "local_fast_put_commit slot/key length mismatch: keys={} slots={}", + owner_data.keys.len(), + slot_refs.len() + ), + }); + let _ = release_staged_put_resources( + inner, + owner_data.key_reservation_ids, + owner_data.slot_lease, + ) + .await; + return ApiResult::new_success(vec![ + kv_error_to_ret_code(&err); + owner_data.keys.len() + ]); + } + let value_len_u32 = match u32::try_from(owner_data.value_len) { Ok(value) => value, Err(_) => { let err = CoreKvError::Api(CoreApiError::InvalidArgument { - detail: - "local_fast_put_commit value_len does not fit into usize" - .to_string(), + detail: "local_fast_put_commit value_len does not fit into u32" + .to_string(), }); let _ = release_staged_put_resources( inner, @@ -4031,13 +3969,14 @@ impl KvClient { ]); } }; - let mut memory_infos = Vec::with_capacity(owner_data.keys.len()); + let mut publish_items = Vec::with_capacity(owner_data.keys.len()); + let mut ret_codes = Vec::with_capacity(owner_data.keys.len()); for (key, slot_ref) in owner_data.keys.iter().zip(slot_refs.iter()) { let memory_info = inner .build_local_reserve_resident_memory_info( key, slot_ref.ptr, - owner_data.value_len as u32, + value_len_u32, slot_size, slot_ref.grant_id, slot_ref.slot_index, @@ -4047,249 +3986,75 @@ impl KvClient { key, memory_info.clone(), ); - memory_infos.push(memory_info); - } - let mut ret_codes = Vec::with_capacity(owner_data.keys.len()); - match inner - .owner_batch_put_start_reserved(start_items, None) - .await - { - Ok(prepared_items) if prepared_items.len() == slot_refs.len() => { - let mut direct_items = Vec::new(); - let mut copy_items = Vec::new(); - for (idx, (reserved_item, slot_ref)) in prepared_items - .into_iter() - .zip(slot_refs.iter().cloned()) - .enumerate() - { - let item = StagedPutCommitItem { - idx, - reserved_item, - slot_ref, - }; - if staged_put_uses_direct_local_commit(&item.reserved_item) { - direct_items.push(item); - } else { - copy_items.push(item); - } - } - - let mut item_results: Vec> = - (0..slot_refs.len()).map(|_| None).collect(); - - if !copy_items.is_empty() { - let reserved_copy_items = copy_items - .iter() - .map(|item| item.reserved_item.clone()) - .collect::>(); - for item in ©_items { - unsafe { - std::ptr::copy_nonoverlapping( - item.slot_ref.ptr as *const u8, - item.reserved_item.src_addr as *mut u8, - value_len_usize, - ); - } - } - match inner - .owner_batch_put_commit_reserved( - reserved_copy_items, - transfer_concurrency, - ) - .await - { - Ok(copy_results) - if copy_results.len() == copy_items.len() => - { - for (item, result) in - copy_items.iter().zip(copy_results.into_iter()) - { - item_results[item.idx] = Some(match result { - Ok(()) => 0, - Err(err) => kv_error_to_ret_code(&err), - }); - } - } - Ok(copy_results) => { - let err = CoreKvError::Api(CoreApiError::Unknown { - detail: format!( - "local_fast_put_commit copy result length mismatch: expected={} got={}", - copy_items.len(), - copy_results.len() - ), - }); - let code = kv_error_to_ret_code(&err); - for item in ©_items { - item_results[item.idx] = Some(code); - } - } - Err(err) => { - let code = kv_error_to_ret_code(&err); - for item in ©_items { - item_results[item.idx] = Some(code); - } - } - } - remove_precommit_local_visible_infos_for_items( - inner, - ©_items, - &memory_infos, - ); - } - - if !direct_items.is_empty() { - let direct_done_req_items = direct_items - .iter() - .map(|item| BatchPutDoneItemReq { - key: item.reserved_item.key.clone(), - put_id: item.reserved_item.put_id, - lease_id: item.reserved_item.lease_id, - committed_slot: Some(PutDoneCommittedSlot { - grant_id: item.slot_ref.grant_id, - slot_index: item.slot_ref.slot_index, - slot_size, - addr: item.slot_ref.ptr, - base_addr: item.slot_ref.base_addr, - len: owner_data.value_len, - }), - publish_local_cache: false, - }) - .collect::>(); - match inner.batch_put_done(direct_done_req_items).await { - Ok(done_resp) - if done_resp.items.len() == direct_items.len() => - { - for (item, done_item) in - direct_items.iter().zip(done_resp.items.into_iter()) - { - let result = - fluxon_kv::rpcresp_kvresult_convert::try_from_code( - done_item.error_code, - done_item.error_json.clone(), - ); - if result.is_ok() { - let promote = inner - .promote_precommit_local_reserve_resident_slot_if_same( - &item.reserved_item.key, - item.reserved_item.put_id, - memory_infos[item.idx].clone(), - ); - if item.reserved_item.enqueue_write_back_append - { - if let Err(err) = inner - .enqueue_write_back_remote_append( - &item.reserved_item.key, - item.reserved_item.put_id, - item.reserved_item - .preferred_sub_cluster - .as_deref(), - ) - .await - { - tracing::warn!( - "local_fast_put_commit write-back remote append enqueue failed after direct local commit: key={} put_id=({},{}) err={}", - item.reserved_item.key, - item.reserved_item.put_id.0, - item.reserved_item.put_id.1, - err - ); - } - } - inner.record_put_locality( - false, - owner_data.value_len, - 0, - ); - item_results[item.idx] = Some(match promote { - Ok(()) => 0, - Err(err) => kv_error_to_ret_code(&err), - }); - } else if let Err(err) = result { - item_results[item.idx] = - Some(kv_error_to_ret_code(&err)); - let _ = inner - .remove_precommit_local_reserve_resident_slot_if_same( - &item.reserved_item.key, - &memory_infos[item.idx], - ); - } - } - } - Ok(done_resp) => { - let err = CoreKvError::Api(CoreApiError::Unknown { - detail: format!( - "local_fast_put_commit direct done response length mismatch: expected={} got={}", - direct_items.len(), - done_resp.items.len() - ), - }); - let code = kv_error_to_ret_code(&err); - for item in &direct_items { - item_results[item.idx] = Some(code); - } - remove_precommit_local_visible_infos_for_items( - inner, - &direct_items, - &memory_infos, - ); - } - Err(err) => { - let code = kv_error_to_ret_code(&err); - for item in &direct_items { - item_results[item.idx] = Some(code); - } - let _ = - revoke_staged_put_items(inner, &direct_items).await; - remove_precommit_local_visible_infos_for_items( - inner, - &direct_items, - &memory_infos, - ); - } - } + let put_id = inner.next_owner_local_first_put_id(); + let promote = inner + .promote_precommit_local_reserve_resident_slot_if_same( + key, + put_id, + memory_info.clone(), + ); + match promote { + Ok(()) => { + inner.record_put_locality(false, owner_data.value_len, 0); + publish_items.push(OwnerLocalPublishItem { + key: key.clone(), + put_id, + value_len: owner_data.value_len, + lease_id: None, + committed_slot: PutDoneCommittedSlot { + grant_id: slot_ref.grant_id, + slot_index: slot_ref.slot_index, + slot_size, + addr: slot_ref.ptr, + base_addr: slot_ref.base_addr, + len: owner_data.value_len, + }, + make_replica_task: true, + preferred_sub_cluster: None, + }); + ret_codes.push(0); } - - for item in item_results { - ret_codes.push(item.unwrap_or_else(|| { - let err = CoreKvError::Api(CoreApiError::Unknown { - detail: "local_fast_put_commit result slot missing" - .to_string(), - }); - kv_error_to_ret_code(&err) - })); + Err(err) => { + let _ = inner + .remove_precommit_local_reserve_resident_slot_if_same( + key, + &memory_info, + ); + ret_codes.push(kv_error_to_ret_code(&err)); } } - Ok(prepared_items) => { - let err = CoreKvError::Api(CoreApiError::Unknown { - detail: format!( - "local_fast_put_commit final reserve length mismatch: expected={} got={}", - slot_refs.len(), - prepared_items.len() - ), - }); - let _ = inner.owner_batch_put_abort_reserved(prepared_items).await; - remove_precommit_local_visible_infos( - inner, - &owner_data.keys, - &memory_infos, + } + if !publish_items.is_empty() { + if let Err(err) = inner + .enqueue_owner_local_publish(OwnerLocalPublishJob { + items: publish_items, + key_reservation_ids: owner_data.key_reservation_ids.clone(), + }) + .await + { + tracing::warn!( + "local_fast_put_commit owner local publish enqueue failed after local commit: {}", + err ); - ret_codes = vec![kv_error_to_ret_code(&err); owner_data.keys.len()]; - } - Err(err) => { - remove_precommit_local_visible_infos( + if let Err(cleanup_err) = release_put_key_reservations_only( inner, - &owner_data.keys, - &memory_infos, - ); - ret_codes = vec![kv_error_to_ret_code(&err); owner_data.keys.len()]; + owner_data.key_reservation_ids, + ) + .await + { + tracing::warn!( + "local_fast_put_commit key reservation cleanup failed after owner local publish enqueue error: {}", + cleanup_err + ); + } + ret_codes = vec![kv_error_to_ret_code(&err); ret_codes.len()]; } - } - if let Err(err) = + } else if let Err(err) = release_put_key_reservations_only(inner, owner_data.key_reservation_ids) .await { tracing::warn!( - "local_fast_put_commit key reservation cleanup failed: {}", + "local_fast_put_commit key reservation cleanup failed after partial local commit: {}", err ); } @@ -4927,7 +4692,7 @@ impl KvClient { /// on the caller to keep the pointed-to memory alive until the async call completes. /// /// The backend encoding/copy runs on the Rust runtime without holding the Python GIL. - #[pyo3(signature = (key, ptrs, lease_id=None, reject_if_inflight_same_key=false, reject_if_exist_same_key=false, write_through=true, callback=None))] + #[pyo3(signature = (key, ptrs, lease_id=None, reject_if_inflight_same_key=false, reject_if_exist_same_key=false, callback=None))] fn put( &self, key: &str, @@ -4935,7 +4700,6 @@ impl KvClient { lease_id: Option, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, - write_through: bool, callback: Option, py: Python, ) -> PyObject { @@ -4946,7 +4710,6 @@ impl KvClient { lease_id: Option, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, - write_through: bool, callback: Option, py: Python, ) -> ApiResult { @@ -4978,9 +4741,6 @@ impl KvClient { if reject_if_exist_same_key { o.0.push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfExistSameKey); } - if write_through { - o.0.push(fluxon_kv::client_kv_api::PutOptionalArg::WriteThrough); - } o }; @@ -5041,7 +4801,6 @@ impl KvClient { lease_id, reject_if_inflight_same_key, reject_if_exist_same_key, - write_through, callback, py, ) @@ -5049,7 +4808,7 @@ impl KvClient { } /// Put a key-value pair and wait for completion before returning. - #[pyo3(signature = (key, ptrs, lease_id=None, reject_if_inflight_same_key=false, reject_if_exist_same_key=false, write_through=true))] + #[pyo3(signature = (key, ptrs, lease_id=None, reject_if_inflight_same_key=false, reject_if_exist_same_key=false))] fn put_blocking( &self, key: &str, @@ -5057,7 +4816,6 @@ impl KvClient { lease_id: Option, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, - write_through: bool, py: Python, ) -> PyObject { fn put_blocking_inner( @@ -5067,7 +4825,6 @@ impl KvClient { lease_id: Option, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, - write_through: bool, py: Python, ) -> ApiResult { if ptrs.len() > (u32::MAX as usize) { @@ -5104,11 +4861,6 @@ impl KvClient { .0 .push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfExistSameKey); } - if write_through { - put_opts - .0 - .push(fluxon_kv::client_kv_api::PutOptionalArg::WriteThrough); - } let result = match py.allow_threads(|| { runtime.run_async_from_sync(async { unsafe { framework.kv_put_ptrs(&key, ptrs, put_opts).await } @@ -5157,7 +4909,6 @@ impl KvClient { lease_id, reject_if_inflight_same_key, reject_if_exist_same_key, - write_through, py, ) .into_py_object(py) @@ -5166,7 +4917,7 @@ impl KvClient { /// Put a batch of key-value pairs and wait for completion before returning. /// /// Each item uses the same flatdict encoding contract as `put_blocking()`. - #[pyo3(signature = (keys, ptrs_groups, lease_id=None, reject_if_inflight_same_key=false, reject_if_exist_same_key=false, write_through=true, concurrency=None))] + #[pyo3(signature = (keys, ptrs_groups, lease_id=None, reject_if_inflight_same_key=false, reject_if_exist_same_key=false, concurrency=None))] fn batch_put_blocking( &self, keys: Vec, @@ -5174,7 +4925,6 @@ impl KvClient { lease_id: Option, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, - write_through: bool, concurrency: Option, py: Python, ) -> PyObject { @@ -5185,7 +4935,6 @@ impl KvClient { lease_id: Option, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, - write_through: bool, concurrency: Option, py: Python, ) -> ApiResult { @@ -5241,11 +4990,6 @@ impl KvClient { .0 .push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfExistSameKey); } - if write_through { - put_opts - .0 - .push(fluxon_kv::client_kv_api::PutOptionalArg::WriteThrough); - } if !framework.is_external_mode() { let framework_for_backend = framework.clone(); @@ -5411,7 +5155,6 @@ impl KvClient { lease_id, reject_if_inflight_same_key, reject_if_exist_same_key, - write_through, concurrency, py, ) @@ -5463,7 +5206,7 @@ impl KvClient { } /// Native blocking batch put path for payload pointers. - #[pyo3(signature = (keys, payload_ptrs, payload_sizes, lease_id=None, reject_if_inflight_same_key=false, reject_if_exist_same_key=false, write_through=true))] + #[pyo3(signature = (keys, payload_ptrs, payload_sizes, lease_id=None, reject_if_inflight_same_key=false, reject_if_exist_same_key=false))] fn batch_put_from( &self, keys: Vec, @@ -5472,7 +5215,6 @@ impl KvClient { lease_id: Option, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, - write_through: bool, py: Python, ) -> PyObject { fn batch_put_from_inner( @@ -5483,7 +5225,6 @@ impl KvClient { lease_id: Option, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, - write_through: bool, py: Python, ) -> ApiResult { if keys.len() != payload_ptrs.len() || keys.len() != payload_sizes.len() { @@ -5559,11 +5300,6 @@ impl KvClient { .0 .push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfExistSameKey); } - if write_through { - put_opts - .0 - .push(fluxon_kv::client_kv_api::PutOptionalArg::WriteThrough); - } let keys_for_backend = keys.clone(); let ptrs_groups = keys_for_backend @@ -5683,7 +5419,6 @@ impl KvClient { lease_id, reject_if_inflight_same_key, reject_if_exist_same_key, - write_through, py, ) .into_py_object(py) @@ -7408,14 +7143,17 @@ mod tests { discovery.entries[0].provider_path, libs_dir.join("libmlx5-rdmav34.so") ); - assert!(discovery - .outcomes - .iter() - .any(|outcome| { outcome.contains("config_ok:") && outcome.contains("driver=mlx5") })); - assert!(discovery - .outcomes - .iter() - .any(|outcome| outcome.contains("config_parse_fail:"))); + assert!( + discovery.outcomes.iter().any(|outcome| { + outcome.contains("config_ok:") && outcome.contains("driver=mlx5") + }) + ); + assert!( + discovery + .outcomes + .iter() + .any(|outcome| outcome.contains("config_parse_fail:")) + ); } #[test] From 6d4d9e36a20796fa4282887f977367442248e3d6 Mon Sep 17 00:00:00 2001 From: zTz01 <1773266173@qq.com> Date: Wed, 15 Jul 2026 15:37:40 +0800 Subject: [PATCH 03/10] feat(kv): add atomic-group replicas and capacity reclaim --- .gitignore | 3 + ...06\346\210\220\350\256\276\350\256\241.md" | 952 +++++- fluxon_py/config.py | 117 +- fluxon_py/kvclient/fluxon.py | 122 +- fluxon_py/kvclient/kvclient_interface.py | 17 + fluxon_py/tests/test_config.py | 103 + fluxon_rs/fluxon_commu/src/facade/p2p.rs | 25 +- fluxon_rs/fluxon_commu_contract/src/p2p.rs | 7 +- .../fluxon_commu_contract/src/p2p/rpc.rs | 52 + .../fluxon_kv/src/client_kv_api/delete.rs | 38 +- .../src/client_kv_api/external_api.rs | 545 +++- fluxon_rs/fluxon_kv/src/client_kv_api/get.rs | 57 +- .../client_kv_api/local_reserve_rebalance.rs | 557 +++- fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs | 1707 ++++++++++- .../fluxon_kv/src/client_kv_api/msg_pack.rs | 81 + fluxon_rs/fluxon_kv/src/client_kv_api/put.rs | 1255 ++++++-- .../fluxon_kv/src/client_kv_api/reclaim.rs | 429 +++ fluxon_rs/fluxon_kv/src/config.rs | 479 ++- .../external_client_test.rs | 4 + .../fluxon_kv/src/external_client_api/mod.rs | 280 +- fluxon_rs/fluxon_kv/src/kv_test.rs | 3 + fluxon_rs/fluxon_kv/src/kvcore_test_lib.rs | 3 + fluxon_rs/fluxon_kv/src/lib.rs | 43 + .../master_kv_router/count_prefix_index.rs | 101 +- .../fluxon_kv/src/master_kv_router/delete.rs | 23 +- .../fluxon_kv/src/master_kv_router/get.rs | 148 +- .../fluxon_kv/src/master_kv_router/mod.rs | 2670 ++++++++++++++++- .../src/master_kv_router/msg_pack.rs | 408 ++- .../src/master_kv_router/placement.rs | 2 +- .../fluxon_kv/src/master_kv_router/put.rs | 750 +++-- .../fluxon_kv/src/master_kv_router/reclaim.rs | 1291 ++++++++ .../src/master_kv_router/route_maintenance.rs | 349 +++ .../src/master_kv_router/tiered_writeback.rs | 224 ++ .../fluxon_kv/src/memholder/memholder_test.rs | 31 +- fluxon_rs/fluxon_kv/src/memholder/mod.rs | 19 +- fluxon_rs/fluxon_kv/src/p2p/msg_pack.rs | 7 +- .../rpcresp_kvresult_convert/msg_and_error.rs | 6 + fluxon_rs/fluxon_kv/src/user_api/rpc.rs | 11 +- fluxon_rs/fluxon_kv/src/user_rpc.rs | 46 +- fluxon_rs/fluxon_pyo3/src/error.rs | 6 +- fluxon_rs/fluxon_pyo3/src/lib.rs | 543 +++- fluxon_rs/fluxon_util/src/log.rs | 42 +- fluxon_rs/fluxon_util/src/vallocator/mod.rs | 144 +- fluxon_rs/fluxon_util/src/vallocator/test.rs | 35 + fluxon_rs/fluxon_util/tests/log_mgmt.rs | 8 + 45 files changed, 12376 insertions(+), 1367 deletions(-) create mode 100644 fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs create mode 100644 fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs create mode 100644 fluxon_rs/fluxon_kv/src/master_kv_router/route_maintenance.rs create mode 100644 fluxon_rs/fluxon_kv/src/master_kv_router/tiered_writeback.rs diff --git a/.gitignore b/.gitignore index d198634..fa0d6cb 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,6 @@ bench_suite.lock deployment/local/ setup_and_pack/pack_fluxonkv_pylib_env.yaml fluxon_rs/moka/ +fluxon_rs/*.btr +fluxon_rs/moka.bak_non_git_*/ +build_*.rc diff --git "a/fluxon_doc_cn/design/sglang_fluxon_kv\351\233\206\346\210\220\350\256\276\350\256\241.md" "b/fluxon_doc_cn/design/sglang_fluxon_kv\351\233\206\346\210\220\350\256\276\350\256\241.md" index 3b0c1c6..475adab 100644 --- "a/fluxon_doc_cn/design/sglang_fluxon_kv\351\233\206\346\210\220\350\256\276\350\256\241.md" +++ "b/fluxon_doc_cn/design/sglang_fluxon_kv\351\233\206\346\210\220\350\256\276\350\256\241.md" @@ -27,6 +27,28 @@ - 因果链:SGLang KVCache restore 不是普通逐 key `get`,而是面向一批有序 page keys 的 prefix restore。它需要一次性回答“这一批最多恢复到哪里”,并且不能切开一个 radix node 对应的 atomic group。batch 化还能减少逐 key 调用、查表、锁和跨边界调度开销。 - 本设计落点:Fluxon hostless get 以 batch 为单位计算 `raw_prefix_hit_len`、`transferable_len` 和 `prefix_hit_groups`。`get_start` 合并存在性 / prefix 判断和可恢复前缀的数据拉取启动,返回 handle 和 prefix;`get_transfer` 再消费 handle,把可恢复前缀转换成 readable `plan_ptr(value_ptrs)`。 +### Mooncake 对齐实验给出的性能约束 + +2026-07-12 的三机对齐实验使用两台 TP=2 GPU 节点和一台纯 CPU 节点,标称容量均为 +GPU0/GPU1/CPU = 128/128/256 GiB,同一批 1152 个 agent 请求中,原版 SGLang + +Mooncake 达到 6.9192 QPS,Fluxon E15 为 3.5134 QPS。Mooncake 没有本设计的 Put +atomic-group admission;它在本轮也没有进入驱逐区。因此该结果证明 group 完整性是 CPU +副本可消费性的必要条件,但不是这轮端到端差距的唯一来源。 + +| 观测 | Fluxon E15 | Mooncake 对齐轮 | 设计约束 | +| --- | ---: | ---: | --- | +| 总命中率 | 44.57% | 93.05% | 先对齐实际 payload 容量和驱逐水位,再比较 group 策略。 | +| cache hit tokens | 12,794,304 | 26,713,408 | Fluxon 多重算 13,919,104 tokens,是吞吐差距主体。 | +| 单 GPU 有效 payload 驱逐点 | 约 57.6 GiB | 本轮约 106 GiB 且未驱逐 | slot 内部碎片和过早水位不能隐藏在相同标称容量后面。 | +| load-back 平均耗时 | 57.1 ms | 5.99 ms | 容量问题消除后,仍需优化 `kernel + layer_first` 读取路径。 | + +E15 的 4,718,592-byte value 被旧 slot class 扩成 8 MiB,payload 利用率 56.25%;再叠加 +旧 Moka 0.8 水位,每个 128 GiB GPU owner 只承载约 57.6 GiB payload 就开始驱逐。 +失败候选立即回插又导致 571 万次请求区间 reclaim candidates 中只有约 4.59 万次成功。 +本设计因此把 exact-fit slot、可配置水位和失败候选退避视为容量控制面的基础正确性,不能 +用新增 atomic group 掩盖这些问题。完整实验设置、计数和日志位置记录在 +`sglang_fluxon_agent_experiments.md`。 + ### 核心实现思路 核心实现按上面的 insight 逐条落到接口和状态边界: @@ -54,8 +76,8 @@ - **对应适配 SGLang KVCache 特化接口** - 实现思路:把 restore 查询建模成 SGLang KVCache 专用的 batch prefix planning,而不是逐 key 独立 get。 - Reject inflight / exist:KV page 按不可变缓存对象写回,重复 page key 不应产生第二份并发写入。`local_fast_put_start` 固定使用 `reject_if_inflight_same_key` 和 `reject_if_exist_same_key`,在分配 writable memory 前拒绝在途或已存在的同 key value,避免重复写回和未提交数据被误发布。 - - Prefetch 对应 `get_start`:`get_start(keys, prefix_best_effort, atomic_group_lens)` 按 key 顺序完成存在性 / prefix 判断,并在 owner/external 侧启动 `keys[..transferable_len]` 的 prefetch transfer,把“能恢复多少”和“开始拉取可恢复数据”合并在 start 阶段。 - - Batch 和 group 对齐:`get_start` 按 atomic group 边界把 `raw_prefix_hit_len` 收敛成 `transferable_len`;`get_transfer` 只消费这个 handle 和 `keys[..transferable_len]` 的 prefetch 结果,并构造 batch 级 readable `plan_ptr(value_ptrs)`,保证 kernel restore 看到的是连续、完整、可回滚的 readable batch plan。 + - Prefetch 对应 `get_start`:`get_start(keys, prefix_best_effort, atomic_group_lens)` 按 key 顺序完成存在性 / prefix 判断。全 owner-local 批次直接返回 `InlineLocal` holder metadata;混合命中或需要远端 materialization 的批次启动 `keys[..transferable_len]` 的后台 prefetch transfer。 + - Batch 和 group 对齐:`get_start` 按 atomic group 边界把 `raw_prefix_hit_len` 收敛成 `transferable_len`;`get_transfer` 只消费这个 handle 对应的 `InlineLocal` 或 `OwnerRpc` 有限分支,并构造 batch 级 readable `plan_ptr(value_ptrs)`,保证 kernel restore 看到的是连续、完整、可回滚的 readable batch plan。 - 主要落点:`reject_if_inflight_same_key`、`reject_if_exist_same_key`、`GetStartResult`、`atomic_group_lens`、`raw_prefix_hit_len`、`transferable_len`、`prefix_hit_groups`、`get_start/get_transfer`。 因此,本设计要统一的是 L2/L3 的对象归属、可见性和生命周期,同时保留 L2 路径的低延迟数据面。单独替换成普通远端 KV 会丢掉 HiCache L2 的 kernel 直连能力;单独保留本地数组或进程内缓存,又无法让 L2 进入全局命中、驱逐和跨节点复用链路。 @@ -130,6 +152,9 @@ flowchart LR | `reject_if_inflight_same_key` | 固定开启,避免同一 page key 并发写回造成重复 inflight put。 | | `reject_if_exist_same_key` | 固定开启,SGLang 把重复 key 当作已写回或冲突重试处理。 | | `write_through` | 当前配置决定提交策略;调用方显式传入时 Fluxon 必须按字段语义执行。 | +| `make_replica_task` | owner-local write-back 成功后的 batch 级异步副本总开关。 | +| `make_replica_task_mask` | `local_fast_put_start` 的可选逐 key 副本准入结果;长度必须与 `keys` 相同。 | +| `atomic_group_lens` | `local_fast_put_start` 有序 key batch 的原子分组;每项必须大于 0,总和必须严格等于 `keys` 长度。组内副本准入必须一致。 | | `lease_id` | 当前 SGLang hostless 主线不依赖 lease。 | ## Key 与组件命名 @@ -192,6 +217,10 @@ SGLang external-client 模式要求看到 `external_owner:*` segment。注册失 `plan_ptr` 是 Fluxon 返回给 SGLang 的临时句柄,本质上是一段 plan blob 的首地址。SGLang native kernel 通过 `plan_ptr` 找到 blob,再从 blob 里读取本次 batch 对应的 value 地址表。 +引入 plan blob 的目的不是单纯定义一个新句柄,而是把 KV 数据面的控制面展开从热路径中移走。实际测试中,如果 KV 接口用 Python dict/list 传递 page、layer 和 value 地址信息,或者用 C++ 结构体承载同等信息,调用链仍然会在 Python 层或 C++ 层按 `page_count * layer_count` 做大量遍历、校验和拷贝任务组织;长上下文场景下,这部分 CPU 控制面开销会被显著放大,直接抬高 backup / restore 延迟。 + +因此这里需要一套足够扁平、稳定、可被 native kernel 直接消费的协议:Fluxon 只把本次 batch 已经分配或 materialize 好的 value 起始地址压成 `value_ptrs[]`,通过 `plan_ptr` 交给 SGLang kernel;kernel 再按自己的 KV layout 参数解释这些地址,并直接发起 GPU KV cache 和 Fluxon host value memory 之间的搬运。对 backup 来说,这条路径让 kernel 直接把 GPU KV bytes 写到 CPU host value memory;对 restore 来说,则从这些 host value 地址恢复回 GPU KV cache。这正是开头“hostless 数据面能力”的落点:Fluxon 管地址、路由和生命周期,SGLang kernel 管 KV layout 和真实数据搬运。 + plan blob 是 Fluxon 在 `local_fast_put_start(...)` 或 `get_transfer(...)` 时创建的一段连续 host memory,格式固定: ```c @@ -225,6 +254,32 @@ hostless backup 的核心约束是:Fluxon 负责 GPU KV cache 之下的本机/ 这条 backup 路径按 write-back 最终一致性设计:native write 完成后先进入本地可见和后台 commit 流程,跨 worker / 跨节点可见性以 `KvFuture` 成功为准。提交失败不会破坏推理语义,只会让对应 page 失去 shared backing;上层清理 `storage_*` 状态后按 cache miss 处理。 +### 本地主副本与异步副本控制 + +`write_through` 和 `make_replica_task` 是两个独立契约。`write_through` 选择同步远端放置还是 owner-local write-back;`make_replica_task` 只控制 owner-local commit 成功后是否创建异步副本任务。SGLang 的纯本地模式必须使用 `write_through=false, make_replica_task=false`,不能把关闭副本等同于开启 write-through。 + +| 模式 | `write_through` | `make_replica_task` | 主数据 | 异步副本 | +| --- | --- | --- | --- | --- | +| local-only | `false` | `false` | 当前 GPU owner | 无 | +| local + remote replica | `false` | `true` | 当前 GPU owner | 由 master 的 `replica_task_placement` 选择 | +| write-through | `true` | 不参与异步副本决策 | master 直接选择远端 target | 无额外异步副本任务 | + +`PutOptionalArgs.make_replica_task` 必须贯穿 Python store、PyO3 和 Rust put request。兼容层如果只识别 `write_through` 而丢弃该字段,SGLang 即使记录 `replica_admitted=0`,Rust 仍可能按旧默认创建副本;因此启动检查必须同时确认 Python `PutOptionalArgs` 和 `fluxon_pyo3.KvClient.local_fast_put_start` 的签名都包含 `make_replica_task`。 + +page admission 还要求 `make_replica_task_mask` 贯穿同一条链路。mask 缺省时,Fluxon 把 batch 级 `make_replica_task` 广播到所有 keys,保留 eager-all 和 local-only 的标量契约;mask 存在时,其长度必须严格等于 `keys` 长度,实际逐项决策为 `!write_through && make_replica_task && make_replica_task_mask[i]`。Python store 在调用 PyO3 前检查容器、长度和元素类型,PyO3 在任何 reserve 或 RPC 之前再次检查长度。external 模式把结果写入每个 `ExternalBatchPutStartItemReq.make_replica_task`;owner 模式把整份 mask 保存在 staged plan 中,commit 时按相同 key 顺序写入每个 `OwnerLocalPublishItem.make_replica_task`。 + +Put 与 Get 使用同一种 `atomic_group_lens` 分区语义。SGLang hostless backup 把一个 radix node 的全部 page keys 标成一个 atomic group;副本策略只能整组 admitted 或整组 skipped。`min_replica_pages` 选择完整 group,允许为了满足最小值而超过它;`max_replica_pages_per_batch` 是硬上限,只保留能够完整装入预算的 group,不能截取 group 的前几页。ratio/score 策略先得到 group 级概率和优先级,再展开为组内全 true 或全 false 的 per-key mask。 + +该契约做双层 fail-fast。Python store 要求 group lengths 是严格的 `list[int]`、每项大于 0、总和等于 key 数,并拒绝组内混合 mask;PyO3 在任何 owner slot reserve 或 external RPC 前重复同样校验。未传 `atomic_group_lens` 时,每个 key 视为长度 1 的独立 group,保留已有调用方的逐 key 行为。存在性过滤或冲突重试若只能留下半个 group,SGLang hostless 路径直接放弃该次 backup,不能把剩余 keys 重新声明成一个完整 group。 + +标量降级不能用于 page admission。若一批中只有一页 admitted,把 mask 折叠为 `any(mask)` 会让整个 batch 都创建副本;逻辑 admission 日志与物理 CPU transfer 因而失配。启动自检必须同时确认 Python `PutOptionalArgs` 和 PyO3 签名包含 `make_replica_task_mask`,端到端验收则比较 SGLang admitted page 数、master CPU target 数和 GPU owner 成功 transfer 数,而不能只看 admission 日志。 + +SGLang 的 admitted 只表示该 atomic group 通过客户端准入并为组内 pages 请求创建副本,不表示目标 owner 已经接收整组。当前 replica actor 仍逐 key 完成 transfer/append;相同 key 的并发副本可能在目标侧返回 `KeyBeingWritten`。因此 Put 原子准入消除了策略主动制造的稀疏组,但尚未把远端复制提交升级成组事务。数据面仍需检查“成功 `local_fast_put_start` 行中的 admitted 数 = 成功 transfer 数 + 可逐项对账的目标侧拒绝数”,并继续要求“成功 transfer 数 = `appended=true` 数 = master CPU target 数”。全局 admission 累计计数可能包含随后被 backend 拒绝并重试的尝试,不能直接作为已 staged page 数或物理复制分母。 + +CPU-only 副本模式不新增第二个客户端开关。客户端仍设置 `make_replica_task=true`,master 再通过 `restrict_to_remote_only_node_roles=true` 和 `remote_only_node_roles=["remote_cache"]` 把 replica target 限定到 CPU owner。若 strict 候选为空,任务返回 NoSpace,不回退到其它 GPU owner。 + +端到端验收以实际数据面计数为准:local-only 要求 GPU owner 的 `put_transfer success`、`replica task append done` 和 master `replica_task_target_counts` 全部为 0;CPU-only 副本要求两台 GPU owner 的 transfer/append 总数严格等于 master 的 CPU target 数,并且 GPU target 为 0。仅检查 SGLang 配置日志不足以证明副本策略已经生效。 + ### 弹性本地侧预分配 弹性本地侧预分配对应 owner 本地写入预留池。它是在 owner shared segment 中为 SGLang hostless put 预先划分的 writable slots。`local_fast_put_start` 从这些 slots 中为本次 put 分配地址,并把地址写入 `plan_ptr(value_ptrs)` 返回给 SGLang native kernel。此时 slot 只处于 reserved/prepared 状态,还没有绑定为 Fluxon KV 的正式 `key -> value` route。 @@ -260,11 +315,51 @@ Free | --- | --- | | grant 物理粒度 | `OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES = 512 * 1024 * 1024` | | 最小 slot size | `4 KiB` | -| slot size 计算 | `max(value_len, 4 KiB).next_power_of_two()` | +| slot size 计算 | `align_up(max(value_len, 4 KiB), 4 KiB)`;按页对齐 exact-fit,不再向上取整到 2 的幂。 | | slot 上限 | `slot_size <= 512 MiB` | | refill 触发 | 当前 slot class free slots 不足时登记 pending demand 并唤醒 rebalance actor。 | -| 默认等待 | soft wait `10 ms`,hard timeout `1 s`。 | +| 预期容量预热 | owner 可配置 `owner_local_reserve_expected_capacity: {value_len, payload_capacity_bytes}`。启动时按 grant 内真实可用 slots 计算并申请所需 grants;SGLang 启动脚本必须等预热完成。 | +| shrink 下限 | 配置预期容量后,rebalance 不把该 slot class 缩到 `expected_grants` 以下;业务瞬时 pending demand 仍可临时增加 grant。它不是物理上限。 | +| 默认等待 | soft wait `10 ms`,hard timeout `10 s`。hard timeout 保护一次 refill/reclaim 事务,不用于掩盖 master 调度饥饿。 | | shrink 单位 | 整个 grant;不做 live grant compaction。 | +| Moka 计费权重 | committed slot 使用 4 KiB 对齐后的实际 `slot_size`,而不是原始 `value_len`;容量驱逐因此对应真实内存占用。 | +| Moka 容量水位 | master `replica_cache_capacity_ratio`,合法范围 `(0, 1]`,默认 `0.95`;它只决定常规冷条目选择水位,不改变 owner segment 配置容量。 | +| 常规容量驱逐 | Moka 到达配置容量后选择冷条目,并通过 eviction listener 进入安全回收流程。Moka 只负责选择候选,不直接释放 owner backing。 | +| 物理 NoSpace 兜底 | refill 申请不到 `512 MiB` grant 时,按 `slot_size * required_free_slots` 计算目标权重,扣除已经在途的回收权重后调用 `evict_some(additional_weight)`;随后按 route 扫描可安全释放的 slots。 | +| 容量不变量 | `evict_some` 只驱逐一部分条目,不修改 Moka `max_capacity`,也不修改 owner 配置容量。 | +| route 维护反压 | route 发布后的 prefix-index/Moka 更新进入容量 512 的有界队列,由单 actor 每批最多处理 512 项;队列满时 `put_done` 等待,避免 metadata/Moka 水位落后于 owner 物理分配并饿死 reserve RPC。 | + +Qwen3-VL-8B、TP=2、page size 64 的单 rank K/V value 是 4,718,592 bytes,正好是 +4 KiB 的整数倍。exact-fit 后一个 512 MiB grant 可以提供 113 个 slots;旧的 +`next_power_of_two` 会把每页扩成 8 MiB,一个 grant 只能提供 64 个 slots。以 128 GiB +owner 为例,旧 `0.8` 水位叠加 56.25% slot payload 利用率后只有约 57.6 GiB 的有效 KV +payload,会在物理 owner 仍有大量空闲时提前驱逐。exact-fit 与 0.95 水位分别解决内部碎片 +和过早驱逐;两项都不修改 owner 的 128 GiB segment 容量。 + +预期容量的 grant 数必须计入每个 grant 尾部不能容纳完整 slot 的碎片,而不能简单用总 payload +除以 512 MiB。计算为: + +```text +slot_size = align_up(value_len, 4 KiB) +slots_per_grant = floor(512 MiB / slot_size) +expected_grants = ceil(payload_capacity_bytes / (slots_per_grant * slot_size)) +``` + +Qwen3-VL 本轮 `value_len=4,718,592`、0.8 payload 目标 109,951,162,777 bytes 对应 +207 grants;可用 23,391 slots / 110,372,585,472 bytes,实际物理预留 +111,132,278,784 bytes。owner 配置容量仍为 128 GiB。配置层会拒绝非正 value/capacity/timeout、 +`hard_timeout <= soft_timeout`、value 大于 512 MiB、预热物理容量超过 owner DRAM,以及在 +master、external client 或 side worker 上设置 owner-only expected capacity。claim 超时统一 +返回 local-reserve timeout 类错误,并用 `stage=claim_turn|refill` 和完整 pool 状态区分等待 +claim 顺序与 refill/reclaim 失败。 + +route 发布与容量记账必须保持有界距离。local-first `BatchPutDone` 可以一次发布上百个 page; +如果每个 page 都独立 spawn prefix/Moka 维护任务,route 已提交和 owner slot 已占用的速度会 +超过 Moka 记账速度。此时即使 segment 仍有大量空闲,master 运行时也可能被任务和逐 page +日志占满,使新的 512 MiB reserve RPC 超过 hard timeout。当前实现用一个有界批处理 actor +统一消费 post-route 事件:一次 prefix-index write lock 覆盖整批,随后逐项推进 Moka;消费 +前校验当前 route 仍匹配 `put_id + owner replica`。容量 512 的队列同时承担反压边界,不能 +改回无界任务生成,也不能用增加 owner 容量代替该控制面约束。 底层物理释放收束在 grant 级别。单个 committed slot 只是 grant 内逻辑索引,不直接拥有释放整块 mmap/registered memory 的权力。 @@ -300,8 +395,8 @@ sequenceDiagram participant O as Fluxon owner participant M as Fluxon master - U->>B: local_fast_put_start(missing_keys, value_len) - B->>F: local_fast_put_start(storage_keys, value_len, opts) + U->>B: local_fast_put_start(page_keys, value_len, atomic_group_lens) + B->>F: local_fast_put_start(storage_keys, value_len, opts(mask, groups)) F->>O: claim local reserve slots / external owner offsets O-->>F: plan_ptr(value_ptrs) B-->>U: plan_ptr @@ -322,6 +417,8 @@ hostless backup 默认不依赖 put 前 exists 扫描。重复 key 或在途 key - `keys` 不能为空。 - `value_len` 必须大于 0,且同一批 keys 共享同一个 value size。 +- `atomic_group_lens` 存在时必须由正整数构成,且总和严格等于 `keys` 长度;同组的 `make_replica_task_mask` 值必须完全一致。 +- SGLang 的 radix node backup 默认使用 `[len(node_page_keys)]`。过滤已有 key 或冲突重试不能切开该组;无法保留完整组时本次 backup 失败关闭。 - SGLang 必须在 `local_fast_put_commit` 前完成 native write;写入失败时必须调用 `put_abort`。 - `local_fast_put_commit` 只能调用一次;调用后 plan 从 registry 清理,后续只能等待返回的 `KvFuture`。 @@ -331,16 +428,16 @@ commit 请求会带上 `len`、`src_offset` 和 target 信息。Fluxon 用这些 hostless restore 的核心约束是:SGLang 只能恢复有序 page keys 的连续前缀,并且不能切开一个 radix node 对应的 atomic group。Fluxon 需要先在本机/远端 KV 层里判断这批 keys 的可恢复边界,再把真正可恢复的部分提前 materialize 到当前进程可读的 holder / memory view 中,最后转换成 SGLang kernel 可读取的 `plan_ptr(value_ptrs)`。 -因此读取侧分成 prefetch 和 restore 两段: +因此读取侧分成 prefetch 和 restore 两段。当前实现把 start-to-transfer 计划显式限定为两个分支: -- Prefetch:`get_start(keys, prefix_best_effort, atomic_group_lens)` 按 key 顺序做 local visible check / owner get start,计算 page 级连续命中前缀 `raw_prefix_hit_len`,再按 `atomic_group_lens` 向下收敛成 `transferable_len`。prefix 发布后,owner/external 侧会启动后台 prefetch transfer,只处理 `keys[..transferable_len]`,并把 holder / transfer result 保存在 shared op 中。 -- Restore:SGLang 拿到 `transferable_len` 后再决定是否分配 GPU KV pages 并继续恢复。`get_transfer(handle)` 消费 `get_start` 返回的 handle,等待或取得 prefetch 结果,生成持有 holder 引用的 readable `plan_ptr`。随后 SGLang native kernel 使用 `restore_*_from_fluxon_values(...)`,把 Fluxon value memory 拷回 GPU KV cache。 +- Prefetch:`get_start(keys, prefix_best_effort, atomic_group_lens)` 按 key 顺序做 local visible check / owner get start,计算 page 级连续命中前缀 `raw_prefix_hit_len`,再按 `atomic_group_lens` 向下收敛成 `transferable_len`。全 owner-local 批次返回 `InlineLocal { items }`:owner 为每个导出 page 安装独立 external holding,并把 offset、len、holding ID 和 owner generation 随 start response 返回;该分支不创建 transfer registry,也不启动后台 transfer。混合命中、master fallback 或需要远端 materialization 的批次返回 `OwnerRpc`,继续由 shared op 保存后台 prefetch 的 holder / transfer result。 +- Restore:SGLang 拿到 `transferable_len` 后再决定是否分配 GPU KV pages 并继续恢复。`get_transfer(handle)` 消费 `get_start` 返回的 handle。`InlineLocal` 分支在 external 进程校验 owner generation 和 mmap 范围后直接构造 holders;`OwnerRpc` 分支等待或取得原有 prefetch 结果。两个分支最终都生成持有 holder 引用的 readable `plan_ptr`,随后 SGLang native kernel 使用 `restore_*_from_fluxon_values(...)` 把 Fluxon value memory 拷回 GPU KV cache。 读取阶段拆成 prefetch 和 restore 两步,主要是为了保证: - prefix 安全:中间 page miss 时,只恢复连续命中的完整前缀,不构造带洞的 GPU KV 状态。 - atomic group 安全:`transferable_len` 不会切开 radix node group,避免恢复半个 node。 -- 资源效率:SGLang 在知道可恢复边界后再分配 GPU KV pages,同时 Fluxon 可以提前 prefetch 可恢复前缀,重叠远端 materialization 和 SGLang 侧 GPU page 分配。 +- 资源效率:SGLang 在知道可恢复边界后再分配 GPU KV pages。`OwnerRpc` 可以重叠远端 materialization 和 GPU page 分配;`InlineLocal` 省去第二次 owner transfer RPC 和无用后台任务。 - 生命周期安全:`get_transfer` 返回的 plan 持有 holder 引用,直到 `release_views(plan_ptr)` 后才释放,保证 kernel restore 期间 value 地址稳定。 ```mermaid @@ -356,25 +453,31 @@ sequenceDiagram B->>F: get_start(storage_keys, prefix_best_effort, atomic_group_lens) F->>E: batch_get_start(keys) E->>O: ExternalBatchGetStartReq - O->>O: local visible check / owner get start + O->>O: local visible snapshot / owner get start O->>O: compute raw_prefix_hit_len and transferable_len - par return prefix - O-->>E: handle + raw_prefix_hit_len - E-->>F: backend handle + raw_prefix_hit_len - F->>F: build GetStartResult(raw_prefix_hit_len, transferable_len, ...) - F-->>B: GetStartHandle + GetStartResult - B-->>U: transferable_len / prefix_hit_groups / first_miss_index - U->>U: allocate GPU KV pages for transferable prefix - and background prefetch - O->>O: prefetch transfer keys[..transferable_len] - O->>O: keep holders / transfer results in shared op + alt fully owner-local + O->>O: allocate external holding IDs and install holdings + O-->>E: handle + InlineLocal(items, generation) + E->>E: cache inline plan by handle + else mixed hit or remote materialization + O->>O: create shared op and prefetch keys[..transferable_len] + O-->>E: handle + OwnerRpc end + E-->>F: backend handle + raw_prefix_hit_len + F->>F: build GetStartResult(raw_prefix_hit_len, transferable_len, ...) + F-->>B: GetStartHandle + GetStartResult + B-->>U: transferable_len / prefix_hit_groups / first_miss_index + U->>U: allocate GPU KV pages for transferable prefix alt transferable_len > 0 and caller chooses restore U->>B: get_transfer(handle) B->>F: get_transfer(handle) F->>E: batch_get_transfer(handle, transferable keys) - E->>O: ExternalBatchGetTransferReq - O-->>E: prefetched holders / transfer results + alt InlineLocal + E->>E: validate generation and mmap range, construct holders + else OwnerRpc + E->>O: ExternalBatchGetTransferReq + O-->>E: prefetched holders / transfer results + end E-->>F: plan_ptr(value_ptrs, holders kept alive) F-->>B: plan_ptr B-->>U: plan_ptr @@ -385,8 +488,13 @@ sequenceDiagram U->>B: cancel_get_transfer(handle) B->>F: cancel_get_transfer(handle) F->>E: cancel_batch_get_start(handle) - E->>O: ExternalBatchGetCancelReq - O->>O: release get-start handle / prefetched holders + alt InlineLocal + E->>O: ExternalBatchGetCancelReq(holding IDs) + O->>O: release exact external holdings + else OwnerRpc + E->>O: ExternalBatchGetCancelReq + O->>O: release shared op / prefetched holders + end end ``` @@ -406,6 +514,7 @@ sequenceDiagram - `get_start` 成功后,调用方必须二选一:`get_transfer(handle)` 或 `cancel_get_transfer(handle)`;放弃 restore 时必须取消 handle,释放可能已经启动的 prefetch 资源。 - `get_transfer(handle)` 成功后,handle 已被消费;后续由 returned `plan_ptr` 和 `release_views(plan_ptr)` 管理。 - `release_views(plan_ptr)` 必须在 native restore 完成后执行,即使 native restore 失败也要释放。 +- `InlineLocal` holding 从 owner 返回 start response 前已经安装;`get_transfer` 把它移交给 returned plan,`cancel_get_transfer` 则携带 holding IDs 精确释放。owner 重启或 generation 不匹配时不能继续使用旧 inline plan。 - `get_start` 只命中部分前缀时,SGLang 只能恢复 `transferable_len` 覆盖的完整 atomic groups,不能构造半个 atomic group 的 GPU KV 状态。 - `get_transfer` 返回 miss / KeyNotFound 时,SGLang 必须放弃本次 restore 并执行 rollback。 @@ -417,12 +526,793 @@ Fluxon client/external 侧会维护当前进程可直接访问的 value 索引 | --- | --- | --- | | precommit local visible | `local_fast_put_commit` 开始后,由 owner-local reserve slot 对应的 `MemoryInfo` 记录到 `precommit_local_visible_info` | 表示本次 put 的 value 已在当前进程可读,但后台 put commit 尚未最终完成;成功后转为 `get_cached_info` 中的 committed entry,失败或取消时移除。 | | committed local visible info | put commit 成功后,由 SGLang 进程内的 Fluxon external/client 将 `MemoryInfo` 记录到 `get_cached_info` | 保存 key、put version、`holder_id`、`offset`、`len` 和 owner node;后续 `get_start/get_transfer` 可以复用这份 `MemoryInfo` 构造 readable plan。 | +| inline external holding | owner 判定整个 transferable batch 都在本地可见后,为每个导出 page 分配 external holding ID 并安装 holding | start response 到达 external 后由 handle 缓存;随后必须移交给 `get_transfer` plan 或由 cancel 携带 holding IDs 释放。holding 绑定 owner generation。 | | get-transfer holder | `get_transfer` 成功后绑定到 readable plan,并由 plan 持有引用 | `release_views(plan_ptr)` 后释放引用;plan 生命周期内 holder 保证对应 value 不被释放。 | 收到 `local_cache_holder_id` 后,SGLang 进程内的 Fluxon external/client 使用 `holder_id`、`offset` 和 `len` 构造 `MemoryInfo`,并记录到自身 `get_cached_info`。`MemoryInfo` 记录当前进程访问该 value 所需的地址信息和释放动作;后续 `get_start` 命中 `get_cached_info` 时,可以直接把这份 `MemoryInfo` 纳入本次 get 结果,`get_transfer` 再把这些 value 地址写入 readable plan。底层内存的回收由 owner route、holder 引用和 owner-local reserve grant 生命周期共同约束。 +内部 `MemoryInfo.holder_id` 与 external holding ID 属于两个生命周期域。resident local-reserve page 的内部 holder ID 可以为 0;每次 external export 仍由 owner 分配非零、递增且独立的 holding ID,同一内部 backing 的并发导出也不能复用 ID。这样 cancel/delete ACK 可以按本次 export 精确对账,多个 resident page 不会因内部 ID 相同而覆盖 holding。external 在构造 inline holder 前还必须验证 response generation 与当前 mmap owner generation 一致,并验证 `offset + len` 位于 mapping 范围内。 + `precommit_local_visible_info` 只覆盖 commit 进行中的短窗口。put commit 成功并确认 holder 后,会移除 precommit entry 并记录 committed entry;如果 commit 失败,precommit entry 必须被清理,不能作为后续 storage-backed 恢复来源。 +## Local-side 主动驱逐与安全回收 + +local-side 主动驱逐不是在 Moka eviction callback 中直接释放内存。无论候选来自常规 Moka capacity eviction,还是 owner refill 遇到物理 NoSpace 后显式调用 `evict_some`,都必须经过同一套 master/owner 安全回收协议。其外部可见不变量是:已经释放或复用的 backing 不会仍然作为一个可访问 route 提供给新的 put/get/replica;如果暂时无法证明可以安全释放,则候选保持 pending 并退避重试,队列关闭等无法继续推进的路径才把当前版本放回 Moka。 + +### 触发与职责边界 + +- Moka 使用 `NodeValueReplicaDesc.weight_bytes` 计费;对于 committed slot,该权重对应真实 `slot_size`。 +- Moka 只做冷条目选择。eviction listener 把 `owner_node_id + key + put_id + weight` 放入 safe reclaim queue,不直接 drop `MemHolder`,也不直接释放 slot。 +- `evict_some(requested_weight)` 的参数是“希望移除的权重”,不是目标 cache size;它沿 LRU 顺序驱逐到满足请求或没有候选为止,并返回实际驱逐权重。由于条目必须整项驱逐,返回值可以大于请求值。它不会通过临时调低再调高 `max_capacity` 来制造驱逐,因此 owner/Moka 配置容量在调用前后保持不变。 +- `eviction_reclaim_pending_weight` 记录已被 Moka 选中、但尚未完成物理回收的权重。NoSpace 兜底只对 `requested_weight - pending_weight` 调用 `evict_some`,避免对同一轮压力重复过量驱逐。 +- activity、holder 或短暂 owner Busy 导致候选无法回收时,不立即插回仍然超限的 Moka。该候选继续计入 pending weight,并以 `10 ms` 起步、最大 `1 s` 的指数退避重新进入 safe reclaim queue;route/put_id 已变化时结束 pending,不复活旧版本。这避免同一个热 key 在 eviction 与 reinsert 之间形成高频循环。 +- safe reclaim queue 满或关闭时,入口立即回滚 pending weight,并且仅在 route 仍是相同 `put_id`、owner replica 仍 live 时把条目重新插回 Moka;旧版本候选不会被复活。 + +### 安全回收时序 + +```mermaid +sequenceDiagram + participant C as Moka cache controller + participant M as Fluxon master + participant O as Fluxon owner + + C->>C: capacity eviction / evict_some 选择候选 + C->>M: enqueue(key, put_id, owner, weight) + M->>M: 校验 route/version/backing + M->>M: try_install_reclaim(key) + alt put/get/replica 在途或已有 reclaim fence + M->>M: 保留 pending weight,指数退避后重试 + else per-key activity 已静默 + Note over M: fence 存在期间拒绝新的 put/get/replica + M->>O: Prepare(item, epoch, exact backing) + O->>O: 隐藏本地索引并检查 pending put / holder + alt Busy 或 Stale + O-->>M: Busy / Stale + M->>O: Abort(需要时) + M->>M: 当前版本仍有效则退避重试;旧版本结束 pending + else Prepared + O-->>M: Prepared + M->>O: Commit + O->>O: 校验并释放精确 slot/backing + O-->>M: Committed + M->>M: 删除相同 put_id 的 owner replica/route + M->>O: Finalize + O-->>M: Finalized + M->>M: 清除 master reclaim fence + end + end +``` + +Master 与 owner 两侧分别承担下面的正确性约束: + +| 约束 | 当前实现 | +| --- | --- | +| 并发线性化 | Master 为每个 key 统计 put/get/replica activity。只有三个计数都为零且没有其它 reclaim 时才能原子安装 reclaim fence;安装后新的 put/get/replica 不能取得 activity lease。replica append 在完整任务期间持有 lease,避免远端副本尚未完成时回收 local backing。 | +| 版本隔离 | 每个候选携带 `put_id` 和 reclaim `epoch`。Master 在安装 fence 前、Prepare 后以及删除 route 前重复检查当前 route 仍是同一版本。 | +| backing/slot 防 ABA | committed slot 必须同时匹配 owner、`grant_id`、`slot_index` 和 `slot_size`;旧驱逐请求不能释放新版本或已经复用的 slot。 | +| 现有读者排空 | Owner Prepare 在同一个 key-control lock 下先从 `get_cached_info` 隐藏索引,阻止新本地读者;随后要求 `Arc::strong_count(mem_holder) == 1`。若已有 get/plan 持有引用,则恢复索引并返回 Busy。 | +| 写入冲突隔离 | Owner Prepare 遇到 `local_puts`、`precommit_local_visible_info` 或 `external_pending_puts` 时返回 Busy,不会回收正在写入或尚未发布完成的 value。 | +| 精确物理释放 | Owner Commit 持有 key-control lock,使用 `Arc::try_unwrap` 取得唯一 backing,并再次断言 slot identity 后释放 owner-side committed-slot route、resident holder 和内存引用,使该 slot 可以回到 Free。identity 不一致按内部不变量失败,而不是继续释放未知 backing;整个 grant 的 mmap/registered memory 仍按独立的 grant 生命周期回收。 | +| route 更新顺序 | Owner Commit 释放物理 backing 后,Master 只删除相同 `put_id` 且 backing identity 相同的 replica;这个短窗口仍受 master reclaim fence 保护,对新请求不可访问。Master 更新 route 后才 Finalize owner fence。 | +| 幂等与失败关闭 | Prepare/Commit/Abort/Finalize 都按 `item + epoch` 判定已应用状态。Prepare 或 Commit RPC 不确定时通过 Abort 查询/收敛;如果 owner 已经 Commit,则不能回滚 backing,而是继续删除 route 并 Finalize。Abort/Finalize RPC 失败会退避重试;未收敛时保留 fence,优先阻塞该 key 而不是暴露已释放内存。 | +| 失败候选收敛 | 暂时 Busy 的当前版本保持 pending 并退避重试,不立即插回 Moka;stale route 或版本变化直接结束 pending。只有队列关闭等无法继续推进的路径,才在 route 仍匹配 `put_id` 且 owner replica live 时重新插入,避免旧条目覆盖新版本。 | + +从可观察状态看,回收事务允许 Owner Commit 与 Master route 删除之间短暂存在“owner slot 已回收到 allocator、可以复用,但旧 route 对象尚在”的内部状态,但对应 key 的 master reclaim fence 在整个窗口内拒绝新操作;安装 fence 之前已经取得 lease 的 get/put/replica 又必须先结束。因此调用方不会通过该 route 访问已经释放或复用的 backing。 + +### 副本保留语义 + +内存/并发正确性与“驱逐后是否仍有另一份可恢复数据”是两个不同契约: + +- `OwnerReclaimReason::Reserve` 用于物理 NoSpace 下的 route-scan 回收。它只选择存在另一份非 tomb replica 的 key,因而 local backing 释放后仍有 recoverable replica。 +- Moka eviction listener 产生的请求使用 `OwnerReclaimReason::CapacityEviction`。当前实现允许它删除最后一份 cache replica;最后一份被删除时,Master 同时删除整个 route,后续表现为正常 cache miss。这与本文前述“KV Cache 副本可丢失,miss 后重新计算”的缓存语义一致。 +- NoSpace 处理会先调用 `evict_some`,再执行 `Reserve` route-scan;其中 `evict_some` 产生的 listener 请求仍属于 `CapacityEviction`。因此不能因为后半段 route-scan 有副本检查,就推导整个 NoSpace 兜底都保证保留 remote replica。 +- 因此,当前已经保证并发访问、版本和 slot 复用安全,但没有对所有 `CapacityEviction` 保证“local 驱逐后 remote side 一定保留一份”。write-through 已成功建立 remote replica 时可以从 remote side 恢复;replica append 尚在途时 activity lease 会阻止并发回收。 +- 如果产品契约改为“任何 local-side 主动驱逐都必须可从 remote side 恢复”,则必须让 `CapacityEviction` 对 active/local owner 同样要求 `has_recoverable_replica`,并补充无远端副本、远端 tomb、replica append 并发及 RPC 故障注入测试。不能只依赖 write-through 通常会产生远端副本这一经验条件。 +- Put `atomic_group_lens` 只保证副本准入不主动切组,不能单独证明 CPU 侧整组已经完成。下一阶段的可恢复优先驱逐需要记录组内 remote append 完成状态,并让 GPU Moka / `CapacityEviction` 优先选择已有完整 CPU 副本的 group;远端只完成部分 pages 的 group 不能作为“驱逐后仍可恢复”的依据。 + +### 当前验证证据与覆盖边界 + +三机 SGLang 正式压力还覆盖了 expected-capacity 与常规驱逐的组合。E16a4 使用两台 TP=2 +GPU owner 和一台 CPU-only owner,标称容量保持 128/128/256 GiB;两 GPU 各预热 207 grants, +正式请求期间各按 pending demand 增到 208 grants。1152/1152 请求成功,QPS 4.845,两侧 +Moka 稳定在 23,296 entries / 109,924,319,232 weighted bytes,owner reserve 在继续写入时 +稳定维持约 128--170 free slots;refill timeout、NoSpace、OOM、scheduler fatal 均为 0。 +master 的 replica target 只有 CPU owner,共 19,395 个,GPU 间副本为 0。这证明预热和 +shrink 下限不改变 owner 容量,也不会阻止达到水位后的常规 `evict some` 持续回收。 + +同拓扑 E16b 把水位和 expected payload 从 0.8/102.4 GiB 提到 0.95/121.6 GiB 后,QPS +从 4.845 提高到 5.967,总命中从 73.67% 提高到 90.28%;Mooncake 为 6.919 QPS、 +93.05% 命中。容量对齐后只剩 2.77pp 命中差,但仍有 13.76% QPS 差距。两 GPU 的 +`init_load_back` 平均总时长分别为 80.07/52.49 ms,其中 `restore_sync` 平均 +68.46/42.33 ms、radix eviction 平均 9.66/8.31 ms,而 kernel launch 记账约 0.05 ms。 +因此 expected capacity、exact-fit 和 group 完整性都不能替代数据面优化:需要继续减少 +同步点,分析 GPU0/GPU1 restore sync 不对称,并评估 `page_first_direct` 组织方式。E16b +仍有 26/24 次 TP transferable mismatch;common-prefix retry 是独立的命中修复,不应被当成 +剩余全部性能差距的解释。 + +E16c 的单变量结果进一步确认了这个边界。启用 TP-invariant Put atomic-group admission 和 +TP common-prefix retry 后,总命中从 90.28% 提高到 92.76%,与 Mooncake 的 93.05% 只差 +0.29pp;TP mismatch skip 从 26/24 降到 0。但 QPS 只从 5.967 提高到 6.136,仍比 +Mooncake 低 11.32%。E16c 的 GPU0/GPU1 load-back 平均总时长仍为 80.55/53.84 ms, +`restore_sync` 仍占 69.29/43.51 ms。结论是:atomic group 是 CPU selective replica 可消费性 +与 TP 正确收敛所必需的协议信息,但在命中率已经对齐后,主要性能工作必须转向 restore +kernel 的同步边界、GPU radix eviction 和 page/layer 搬运顺序。 + +后续 E16f 的逐层 restore kernel 把 Fluxon QPS 提到 6.635;E16s 的 deferred +`release_views` 和 E16t 的整批 local-visible snapshot 继续把 QPS 提到 6.808。E16u 再为 +全 owner-local get 增加 `InlineLocal` 分支,两个独立冷栈正式轮分别为 6.754/6.760 QPS, +1152/1152 成功且各自实际备份 3,869,056 tokens。`get_transfer` mean 已从 E16t 的 +4.192/1.957 ms 降到 0.558/0.585 ms,但冷 QPS 没有继续提高;一次复用旧 owner keys 的热轮 +达到 6.894 QPS,却只实际备份 246,976 tokens,不能作为冷 A/B。 + +E16u 冷复测把剩余 radix eviction 进一步定位到同步 write-back。GPU0/GPU1 的 +`init_load_back` mean 为 10.621/8.399 ms,其中 eviction 为 8.859/6.688 ms;阻塞 +`_wait_for_fluxon_hostless_backup` 与 `writing_check(write_back=True)` 的累计 duration 约占 +这些 eviction 累计时间的 95.7%/90.5%。parent-chain backup mean 为 6.508/4.435 ms,主要 +由 stream sync 3.735/2.322 ms 和 `local_fast_put_start` 1.988/1.366 ms 构成。因此当前性能 +边界已经从 get transfer RPC 转到 write-back 时机与批次组织。后续优化需要在不改变 owner +128/128/256 GiB 容量、不降低连续完整前缀命中的前提下,评估有界 proactive write-back 或 +多 radix node 共用 Put plan/一次 stream sync;单纯继续减少 get 控制面 RPC 的收益不足以 +代表冷端到端收益。 + +### Write-through parent 依赖与驱逐时补备份 + +hostless write-through 的 `storage_backed` 也必须满足连续前缀不变量:一个 child 只有在 +parent 已经 remote-backed 后才能成为独立可恢复节点。proactive `write_backup` 遇到 parent +尚在途时会先提交 parent,但不会自动把 child 排队到 parent ACK 之后重试。因此 child 可能 +既没有 `storage_backed`,也没有 `storage_pending`;后续 device eviction 若直接删除该 radix +node,会丢失仍可通过一次补写保留的前缀。 + +驱逐时的收敛顺序应为: + +1. 已经 `storage_backed`:直接走 `_evict_to_fluxon_storage`。 +2. 当前 node 有 `ongoing_fluxon_hostless_backup` 或 pending ACK:只等待已有操作;成功后走 + Fluxon tombstone。 +3. 没有可恢复副本也没有 pending:调用 `write_backup(node, write_back=True)`;该调用递归 + 补齐缺失 parent,随后 `writing_check(write_back=True)` 阻塞到 ACK。 +4. ACK 后再次检查 `_fluxon_hostless_node_storage_ready`。只有确认完整 KV(及需要时 Mamba) + 均 remote-backed 才释放 device backing;提交失败、ACK 失败或仍不可恢复时保留原来的 + fail-closed 删除语义。 + +E16w 只实现第 2 步,但两台 GPU 的新分支触发均为 0,排除了“主要是 ACK 尚在途”的假设。 +E16x 补齐第 3--4 步,正式轮中 GPU0/GPU1 分别产生 118/114 条 TP-rank 同步补备份提交, +失败为 0;其中直接 leaf completion 各 88 条,parent-chain completion 为 30/26 条。 +总命中由 E16w 的 92.38% 提高到 92.73%,增加 99,520 tokens;QPS 仅从 6.8081 降到 +6.7915。每次 load-back 的 radix eviction mean 只增加 0.169/0.127 ms。这说明按需补齐 +parent chain 可以作为正确性和命中保底,不需要把所有 write-through 操作重新变成同步写。 + +该结果也进一步限定 atomic group 的作用边界。Mooncake 没有 Fluxon Put atomic-group +admission,仍达到 93.05% 命中和 6.9192 QPS;E16x 在命中只低 0.323pp 时仍低 1.85% QPS。 +因此 Put atomic group 是 TP 一致准入、CPU selective replica 完整组和“有完整远端副本才 +优先驱逐”的正确性信息,但不是剩余端到端差距的充分解释。Mooncake 每次 restore 平均跨 +3.20/3.26 个 radix node,E16x 为 10.15/10.08 个;Mooncake 的命中主要经过 32 GiB 本地 +HiCache L2,Fluxon hostless 的命中主要表现为 external L3。后续数据面比较必须记录每个 +request 的实际 restore bytes、来源 locality、CUDA event 等待和合并后的 batch 数,不能仅 +比较命中率或 atomic-group 数量。 + +E16x 的分节点指标显示剩余差距集中在 GPU0:Fluxon TTFT/E2E mean 为 1.036/1.629s, +Mooncake 为 0.865/1.522s;GPU1 的 Fluxon 1.719/2.499s 反而略快于 Mooncake 的 +1.728/2.524s。GPU0 同时承载 Fluxon master、owner、router 和 workload,因此还需把 +restore 数据面耗时与 master/owner CPU 竞争分开测量;在证据出来前,不应通过扩大 owner +容量或改变副本语义掩盖该不对称。 + +E16y 对该不对称做了 NUMA 定向实验。两台 GPU 都属于 NUMA node1,但 E16x 的 GPU0/GPU1 +owner backing 分别有 128.14/97.40 GiB 落在远端 NUMA0。把 owner 与 SGLang 绑定到 +NUMA1、把 master/router/workload 绑定到 NUMA0 后,两台 owner 都有约 128.25 GiB 落在 +NUMA1;备份量、命中率和 fallback 数保持相同,QPS 从 6.7915 提高到 6.8520,与 Mooncake +只差 0.97%。因此大块 registered host backing 的 first-touch NUMA 必须成为部署契约,而 +不能依赖进程启动瞬间的随机 CPU。 + +但 E16y 不是最终绑核方案:GPU1 layerwise completion 降低 5.20%,GPU0 却没有改善,且 +两端 `get_start` p50/p90 因 owner 与 SGLang 共用受限 CPU 集而上升。正确的后续拆分是只让 +owner 在 GPU-local NUMA 完成大块 backing first-touch,SGLang/master/router/workload 保持 +正常调度;若需要长期绑核,再为 owner data plane 与 SGLang scheduler 分配不重叠的 core +集合。不能把“NUMA-local memory”与“所有线程绑在同一个 NUMA CPU 集”视为同一要求。 + +E16z 完成该拆分后,在备份量和 fallback 数不变的条件下达到 6.9007 QPS,比 E16x 提高 +1.61%,与 Mooncake 只差 0.27%;完整 1152 请求 wall 仅差 0.45s。由此 owner backing 的 +GPU-local first-touch 应固化为部署步骤,而 SGLang 不应与 owner 共用同一受限 affinity。 +steady-state owner 也不一定要永久绑核:E16z 的 `get_start` p50 仍比 unrestricted E16x 高 +约 0.5--0.6 ms。更精确的生命周期是 owner 在 segment/backing 与 expected-capacity reserve +建立期间绑定 GPU-local NUMA,完成后把全部已有线程 affinity 放宽;first-touch 页面会保持 +原 NUMA placement,控制/RPC 线程则可以重新使用其它 CPU 和 NIC-local core。 + +E16aa 对这一两阶段生命周期做了正式 A/B。放宽后 `get_start` p50 确实从 E16z 的 +2.55/2.60 ms 降到 2.15/2.29 ms,页面仍驻留 NUMA1;但 QPS 为 6.8902,比 E16z 低 +0.15%,没有形成端到端正收益。考虑实现和运维复杂度,当前建议采用 E16z 的简单规则: +GPU owner 整个生命周期绑定 GPU-local NUMA CPU 集,SGLang/master/router/workload 不绑核。 +E16z 6.9007 QPS 与 Mooncake 6.9192 只差 0.27%;若后续追求稳定的亚百分比收益,应先 +增加独立冷轮重复次数和 per-request CUDA/CPU tracing,而不是继续叠加 affinity 状态切换。 + +E16ab 随后按 E16z 配置做了独立全冷栈复测。两个 GPU owner 启动后分别有 +128.151/128.143 GiB 页面位于 NUMA1,容量、副本开关、请求序列和 active source 均未变化。 +本轮 1152/1152 成功、严格 576/576,得到 6.8812 QPS、92.72% 总命中;它比 E16z 低 +0.28%,比 Mooncake 单轮低 0.55%。两次 E16z 形态冷轮均值为 6.8909 QPS,比 Mooncake +低 0.41%。因此原先 0.27% 差值确实落在单轮波动量级,但不能据此宣称 Fluxon 已超过 +Mooncake。两轮的 `get_start`、`init_load_back`、radix eviction、restored-node 数和 +layerwise completion 高度复现,未出现新的系统瓶颈或错误。 + +“Fluxon 有额外优化所以理应直接超过 Mooncake”并不是有效的性能推导。Put atomic group 和 +缺失 parent 补写首先是正确性/可恢复性契约;InlineLocal、batch local-visible、deferred +`release_views` 和 layerwise kernel 则用于抵消 external owner/hostless 路径相对进程内 L2 +的 RPC、holder 和恢复组织成本。Mooncake 对齐轮有 70.55% tokens 命中进程内本地 L2,并把 +512 GiB 五个 segment 全部作为 primary capacity,285.3 GB 数据没有发生容量驱逐;E16z/E16ab +约 62% tokens 经过 external owner,只使用两个 128 GiB GPU owner 保存 primary,256 GiB +CPU owner 为空。因此现有优化是在不同路径上把端到端拉平,并不是在 Mooncake 相同基线上的 +额外加速项。 + +能够形成 Fluxon 独有容量收益的下一闭环仍是“完整 CPU 副本 -> GPU 优先驱逐该完整 group -> +CPU 成为可恢复剩余副本”。Put `atomic_group_lens` 目前只保证准入不主动切组;replica actor +仍逐 key append,owner/Moka 也没有完整 group 的 remote-complete 状态可用于候选排序。只有 +补齐远端整组完成记账、版本失效和 recoverable-first eviction 后,CPU 256 GiB 才会从异步 +复制开销转化为 GPU eviction 后的额外命中。这比继续压缩已经只有约 2--3 ms 的 `get_start` +或 0.7--0.8 ms 的 radix eviction 更可能带来稳定超过 Mooncake 的收益。 + +E16ad 进一步纠正了“配置容量”和“实际参与容量”的表述。E16z/E16ab 虽然启动了 +128/128/256 GiB 三台 owner,但 `replica_task.enabled=false`;SGLang +`external_batch_put_start` 又直接使用 requester-local reserve,因此只有两个 GPU owner 保存 +primary,CPU owner entries 为 0。CPU 的 256 GiB 在这两轮只是注册容量,不能计作实际数据 +容量。Mooncake 对齐轮则确实把五个 segment 都作为 primary 使用,两者的容量利用语义并不 +等价。 + +E16ad 在相同物理容量和 NUMA 配置上启用 CPU-only `kv_score_only` replica,master 严格限制 +remote target role 为 `remote_cache`,GPU 间仍无副本。由于当前 PyO3 契约令 +`write_through || !make_replica_task` 都跳过 replica,本轮 HiCache 使用 write-back。最终 +GPU0/GPU1/CPU 分别保存 121.585/121.584/142.938 GiB,CPU 有 18,296 entries,master +记录 18,336 个 CPU target 和 0 个 GPU target,证明三台 owner 均实际进入数据面。 + +但该轮只有 6.8124 QPS、92.69% 总命中;相对 no-replica 冷复测 E16ab,QPS 低 1.00%, +命中低 0.03pp,同时产生约 0.517 Gbps 聚合 RDMA TX。CPU 没占满 256 GiB 是 kv-score 跳过 +低分 group 的预期结果,更关键的是这 142.938 GiB 仍为重复副本。当前 GPU capacity eviction +没有利用“完整 CPU group 已完成”的状态选择候选,所以 CPU 写入没有转化为更多可消费命中。 + +这里必须区分两个后续实现方向: + +- 若维持“CPU 只存副本”,需要补齐完整组 remote append 完成、版本失效和 + recoverable-first GPU eviction;GPU 本地 copy 被驱逐后,CPU copy 才转化为有效扩容。 +- 若要求像 Mooncake 一样把 128+128+256 GiB 全部作为独立 primary pool,需要实现 + requester-local first、local 压力后 spill 到 CPU 的 remote-primary batch put。当前 + external batch commit 显式拒绝 remote primary,修改 `prefer_local_placement` 不能得到 + 该语义。 + +因此“三 owner 都有占用”已经由 E16ad 验证;“512 GiB 都是独立有效容量”尚未成立,不能把 +副本字节与 primary 字节直接相加。 + +### 低分 KV 提前 CPU write-back 策略 + +SGLang Fluxon HiCache 新增显式准入策略 `kv_score_low_only`。它保留 GPU requester-local +owner 上的 primary,同时为低分 KV atomic group 提前创建 replica task;三机 CPU-only +拓扑由 master 的 `remote_cache` target role 约束副本只落到 CPU owner。策略本身只决定 +replica task 准入,不改变 target role、owner 容量或 GPU 间副本规则。 + +配置示例: + +```json +{ + "replica_task": { + "enabled": true, + "admission": { + "policy": "kv_score_low_only", + "score_threshold": 0.55, + "min_replica_pages": 0, + "max_replica_pages_per_batch": 512 + } + } +} +``` + +该策略使用包含边界的 `score <= score_threshold`。Put 仍按 `atomic_group_lens` 作整体决策, +同一 group 的 mask 全 true 或全 false。group priority 使用 `1 - mean(group scores)`;因此触发 +`min_replica_pages` 补选或 `max_replica_pages_per_batch` 裁剪时,优先选择最低分 group,且不会 +为了填满页数预算切开 group。原 `kv_score_only` 保持 `score >= score_threshold` 和高分优先 +语义不变。 + +物理 storage key 继续区分 TP rank,准入 identity 则保留 TP size 并去掉 TP rank;同一逻辑 +group 在所有 TP ranks 上得到一致的低分准入结果。该实现属于 proactive CPU write-back +admission:CPU append 成功前 GPU primary 不会提前释放,成功后当前 eviction 也尚未按 +remote-complete group 排序。完整的“低分提前写回 -> GPU `evict some` 优先回收已完整备份组 +-> CPU 副本承担后续恢复”闭环仍需 remote-complete 记账、版本失效和 recoverable-first +eviction。 + +E16ae 已用与 E16ad 相同的 128/128/256 GiB、双 TP=2、owner-only NUMA1 和 1152 请求配置 +完成低分策略正式压力。1152/1152 成功,QPS 为 6.8073,总命中 92.72%;E16ad 高分策略为 +6.8124 QPS、92.69% 命中,差异分别为 -0.075% 和 +0.03pp。低分策略把 CPU retained usage +从 142.938 GiB 提高到 243.188 GiB,历史 CPU targets 从 18,336 提高到 42,214,聚合 RDMA +TX 从 0.517 提高到 1.189 Gbps,但没有得到可测的吞吐或命中收益。两 GPU 仍各保存约 +121.570 GiB primary,GPU replica target 为 0;CPU cache 已达到 95% effective capacity。 +这进一步证明 admission 选择本身不能替代 recoverable-first eviction:额外 CPU 副本在当前 +消费路径上仍主要体现为重复容量和写流量。 + +Mooncake 对齐轮也必须按相同抽象层解释。SGLang 启动参数是 +`--hicache-write-policy write_back`,安装版 Mooncake `ReplicateConfig()` 默认 +`replica_num=1`。Mooncake master 管理 120,928 keys,每个对象 2,359,296 bytes;乘积 +285,304,946,688 bytes 与 master allocated bytes、五个 segment allocated bytes 之和完全 +相等。这证明 global store 中每个对象只有一份,五个 segment 共同承担单份对象的 placement。 +它不是“GPU segment 保留 primary,再 write-through 一份 CPU replica”。 + +因此更严格的路径映射是:Mooncake 的 SGLang device/L2/L3 采用 write-back demotion,global +store 的 512 GiB 提供单份对象容量;Fluxon E16ad 则在 GPU owner primary 仍存在时异步写 +CPU replica。二者都可能在层间迁移瞬间短暂同时持有数据,但稳态容量语义不同。若目标是复刻 +Mooncake 同时发挥 Fluxon 的统一管理优势,Fluxon 更合适的实现是 local owner 到 CPU owner +的 single-copy demotion/spill:CPU commit 成功后删除 local copy,而不是长期保留两份。 +recoverable-first replica eviction 可以作为现有协议的过渡实现,但验收最终应统计单份逻辑 +字节、物理总字节和迁移后 source 删除,不能只统计 CPU entries 非零。 + +### Master 两级 Moka 提前写回 + +Master 新增可选的包含式两级 Moka,用 master Moka 的实际容量淘汰序列代替 Put 时的 score +预测。这里的 T1/T2 是 +Fluxon master 的 owner route 元数据层级,不是 SGLang HiCache 的 GPU L1 / host L2: + +| 层级 | 容量 | 淘汰动作 | 是否释放 owner 数据 | +| --- | --- | --- | --- | +| T1 hot tier | `replica_writeback_tier1_capacity_ratio × owner segment` | 批量通知源 owner 发起 remote-only replica task | 否 | +| T2 resident tier | `replica_cache_capacity_ratio × owner segment` | 进入现有 fenced owner reclaim | 是 | + +T1 是 T2 的热数据子集。新 route 同时进入 T2 和 T1,因此启用 T1 不会从 T2 切走容量,也不会 +改变 owner 的 `max_capacity`。经 master get 路径观察到的 T2 命中会把对应 key 重新提升到 +T1。T1 因容量发生 `Size` 淘汰时,master 按源 owner 合并请求,再通过内部 +`BatchEnqueueReplicaTaskReq` 通知 owner。 +Owner 继续复用已有的 `put_append_start -> RDMA transfer -> put_append_done` replica actor;目标仍 +由 `replica_task_placement` 选择。启用两级写回时,配置校验要求 +`restrict_to_remote_only_node_roles=true`,防止写回落到另一个 GPU owner。 + +```mermaid +sequenceDiagram + participant M as Fluxon master T1/T2 + participant G as GPU owner + participant C as remote CPU owner + + G->>M: publish local route + M->>M: insert T2 resident + T1 hot + M->>M: T1 Size eviction + M->>G: BatchEnqueueReplicaTaskReq(key, put_id) + G->>M: put_append_start + M-->>G: reserve CPU target + G->>C: RDMA transfer + G->>M: put_append_done + M->>M: append CPU replica route + Note over M,G: GPU owner source remains in T2 + M->>G: later T2 fenced reclaim +``` + +Master 配置示例: + +```yaml +replica_task_placement: + remote_only_node_roles: ["remote_cache"] + restrict_to_remote_only_node_roles: true +replica_cache_capacity_ratio: 0.95 +replica_writeback_tier1_capacity_ratio: 0.75 +``` + +`replica_writeback_tier1_capacity_ratio` 必须大于 0,且严格小于 +`replica_cache_capacity_ratio`。不配置该字段时保留原单层 resident Moka 行为。以 +128 GiB owner、T2 `0.95`、T1 `0.75` 为例,owner resident 上限仍约为 121.6 GiB;约 25.6 +GiB 的 T1/T2 容量差提供 replica 完成窗口,而不是把 owner 容量降到 96 GiB。 +Master 的周期日志同时报告 `writeback_tier1_triggered`、 +`writeback_tier1_owner_accepted` 和 `writeback_tier1_failed`。其中 accepted 只表示源 owner +已把任务放入 replica actor,CPU route 是否完成仍以 `replica_task_target_counts` 和 +`put_append_done appended=true` 为准。 + +当前实现仍是过渡策略,边界如下: + +- T1 淘汰只启动逐 key remote replica,尚未记录 SGLang radix atomic group,也没有整组完成 + 状态。 +- Owner `InlineLocal` fast path 当前不经过 master get,因此这类本地命中不会刷新 T1;当前顺序 + 是 master 可观察的 insert/get 淘汰序列,不是所有 SGLang 访问的全局 LRU。 +- CPU replica 完成后不会立即删除 GPU owner source;source 只有在后续 T2 reclaim 时释放。 +- 该策略能让写回时机跟随 master 实际热度淘汰,并为异步复制提供有界提前量;它尚未实现 + Mooncake 式 single-copy demotion。 +- 运行该策略时,SGLang Put 侧应关闭 `kv_score_only` / `kv_score_low_only` eager admission, + 避免同一 key 同时由 Put admission 和 T1 淘汰重复请求副本。 + +#### E16ag 三机验收结果 + +首轮 E16af 虽然成功解析 T1/T2 比例,但把 source eligibility 错误绑定到 +`prefill/decode` active-client role。实际 GPU storage owner 的 role 是 `sglang_owner`,因此 +两台 GPU 都没有构造 T1。E16ag 把资格修正为“已注册且非 `remote_cache` 的 owner”,从而 +允许 GPU storage owner 作为写回源,同时继续排除纯 CPU owner。 + +E16ag 在固定 GPU0/GPU1/CPU = 128/128/256 GiB、双 TP=2、96 sessions × 12 turns、 +concurrency 16 的正式三机压力中得到 1152/1152 成功、6.8151 QPS、92.74% 总命中。两台 +GPU 的 resident weighted bytes 均为 121.570 GiB,T2 上限仍为 121.600 GiB;T1 均为 +95.977 GiB,上限为 96 GiB。因此包含式 T1 没有改变 owner 配置容量,也没有把 T2 降到 +T1 容量。 + +CPU 最终持有 13,061 entries / 102.039 GiB,历史完成 13,090 个 replica targets,目标全部是 +`remote_cache` CPU,GPU target 为 0。流水线计数满足: + +```text +T1 triggered 16525 + = pre-dispatch stale 226 + + owner source-missing/version-mismatch 1209 + + owner accepted 15090 + +owner accepted 15090 + = target KeyBeingWritten 2000 + + CPU replica completed 13090 +``` + +这说明策略已经生效,版本检查也正确阻止了过期 source 被复制;同时暴露了两个明确窗口。 +第一,T1 淘汰事件入队后,source 可能先被 T2 回收,现有 holder 获取发生得太晚。第二,owner +接单只表示任务进入 replica actor,目标侧相同 key 仍可能处于写入中。下一版应在 T1 eviction +时为相同 `put_id` 安装短期 source pin,复制完成/失败后释放,并对 `KeyBeingWritten` 做有界、 +版本安全的重试。观测上应把 pre-dispatch stale、source missing 和 busy key 分开计数,不能只 +用 `writeback_tier1_failed` 聚合。 + +性能上,E16ag 相对无 T1 的 E16af 提高 0.75%,但相对 no-replica E16ab 低 0.96%,相对 +Mooncake 低 1.50%。CPU 副本物理存在不等于形成额外可消费命中:当前 source 在 T2 前仍保留, +CPU 字节主要是暂时重复容量;逐 key 成功也不能证明完整 radix group 可恢复。因此 source pin / +busy-key retry 解决复制完成率之后,仍需记录 atomic group remote-complete,并让 T2 +recoverable-first eviction 优先选择已有完整 CPU 副本的 group,才能把 CPU 容量稳定转化为 +命中收益。 + +### Owner-local hot Moka 提前写回 + +当前实现把提前写回的热度观察点下沉到 storage owner。每个 GPU owner 维护一个逐 key 的 +owner-local hot Moka;本地 committed value 进入该 tier,`InlineLocal` 等 owner 本地命中会刷新 +热度。hot tier 发生 `RemovalCause::Size` 时,owner 立即 pin 当前 `put_id` 的 backing,再把该 +value 交给现有 replica actor 异步写入 remote CPU owner。Master T2 resident Moka 仍是唯一的 +物理回收决策入口。 + +```mermaid +sequenceDiagram + participant S as SGLang / external client + participant G as GPU storage owner + participant H as owner-local hot Moka + participant M as Fluxon master T2 + participant C as remote CPU owner + + S->>G: local commit(key, put_id) + G->>H: insert weak entry(key, put_id, slot_size) + S->>G: InlineLocal hit + G->>H: touch current entry + H->>G: Size eviction(key, put_id) + G->>G: key fence + version check + Arc pin + G->>M: put_append_start(key, put_id) + M-->>G: reserve remote-only target + G->>C: RDMA transfer + G->>M: put_append_done + M->>M: append CPU replica route + alt owner-hot demotion intent 且完整 TP cohort 可从同一 CPU owner 恢复 + M->>M: Size-evict exact source cohort + M->>G: fenced Prepare / Commit / Finalize + G-->>M: release current local backing + else append/版本/整组检查失败或 CPU NoSpace + M-->>G: retain GPU source + end + G->>G: release pin and inflight dedup guard +``` + +Owner 配置只增加一个 canonical 参数: + +```yaml +replica_writeback_hot_capacity_ratio: 0.75 +``` + +该比例必须有限且位于 `(0, 1)`,并且只能出现在非零容量 owner 配置中。hot Moka 的 +`max_capacity` 等于该比例乘 owner DRAM;128 GiB owner 配置 `0.75` 时,逻辑 hot 水位为 +96 GiB。这个计算不修改 `contribute_to_cluster_pool_size.dram`、local-reserve grant 数量、owner +segment 或 master T2 的 `replica_cache_capacity_ratio`。Moka value 只保存 +`Weak`;所有 hot entries 因而不会整体 pin 住 owner backing。计费优先使用 +local-reserve 的实际 `slot_size`,普通 allocation 使用 payload length。 + +CPU-only 目标仍由 master 的 placement 契约提供: + +```yaml +replica_task_placement: + remote_only_node_roles: ["remote_cache"] + restrict_to_remote_only_node_roles: true +replica_cache_capacity_ratio: 0.95 +# replica_writeback_tier1_capacity_ratio 不配置 +``` + +第一版实验必须关闭 master T1 和 SGLang Put 侧的 eager replica admission,避免同一个 key 有 +多个独立提前写回触发器。owner hot tier 只决定写回时机;如果 master 没有限定 +`remote_only_node_roles`,目标仍可能由普通 placement 选到其它 owner。 + +并发与失败处理遵守下面的不变量: + +| 场景 | 当前处理 | +| --- | --- | +| hot eviction 与 T2 reclaim 竞争 | 两者使用同一个 `owner_key_control` fence。reclaim 先取得 fence 时,hot eviction 放弃 stale source;hot eviction 先 clone `Arc` 时,reclaim 的唯一强引用检查返回 Busy,等 replica 任务释放 pin 后再重试。 | +| 版本替换、delete、显式失效 | eviction listener 只消费 `RemovalCause::Size`。`Replaced` 和 `Explicit` 不创建 replica;reclaim/delete 按 `put_id` 条件失效 hot entry,不能删除随后安装的新版本。 | +| 旧事件与重复事件 | listener 同时校验 `put_id` 和 `MemoryInfo` identity;dispatcher 入队前再次校验当前 owner index。`(key, put_id)` guard 覆盖排队、transfer 和 append-done 全周期。 | +| 控制面阻塞 | Moka callback 只完成 fence 内 pin 和容量 4096 的事件队列 `try_send`,不等待 RPC/RDMA;dispatcher 再进入现有容量 128 的 replica task queue。事件队列满时计入 dispatch-failed 并立即释放 pin,避免积压事件阻止 T2 reclaim。 | +| append start busy key | owner-hot 任务遇到 `KeyBeingWritten` 时最多尝试 3 次,重试间隔为 25/50 ms。其它错误不做这一层重试;最终失败释放 pin,保留 GPU primary,不会把失败任务解释为 CPU replica 已完成。 | +| 可观察性 | owner 每 30 秒记录 hot capacity/weighted bytes、Size eviction、enqueued/completed/already-satisfied/failed/obsolete、dispatch-failed、inflight 以及 stale/reclaim/duplicate skip 计数。CPU 数据面完成仍以 `put_append_done appended=true` 和 master target 计数为准。 | + +E16ah 的第一版实现修复了 master T1 的两个直接缺口:source 在 eviction callback 内完成 pin, +且 owner `InlineLocal` 命中能参与热度更新;当时仍是逐 key proactive replica write-back,CPU +append 成功后不会直接删除 GPU source。后续版本把 Put atomic group 存入 route,并让 owner +在任一 group member 被 hot Moka 淘汰时 pin、排队完整 group。Master 进一步按 canonical +`__` 后缀验证所有 TP rank 的逻辑 group 边界及同一 CPU owner 上的完整副本。 + +E16ap 在该完整性信息之上增加 single-copy demotion。只有 owner-hot 任务的内部 append 请求 +携带 demotion intent;普通 eager replica 不携带。append 成功或同版本 CPU route 已存在时, +Master 再次验证 source 版本、atomic group、TP cohort 和共同 `remote_cache` owner,然后以 +`RemovalCause::Size` 从 resident Moka 选择该 exact cohort,复用既有两阶段 fenced reclaim。 +检查不通过、CPU NoSpace、append 失败或版本变化时保留 GPU source。该路径不新增用户侧副本 +开关,也不修改 owner segment、local-reserve grant 或 `contribute_to_cluster_pool_size.dram`。 + +#### E16ah 三机验收结果 + +E16ah 在固定 GPU0/GPU1/CPU = 128/128/256 GiB、96 sessions × 12 turns、concurrency 16 +的三机正式压力中得到 1152/1152 成功、6.8174 QPS 和 92.96% 总命中。两个 GPU owner 的 +T2 resident 均为 121.570 GiB,上限仍为 121.600 GiB;两个 owner-local hot Moka 上限均为 +96 GiB。CPU 终态持有 19,538 entries / 152.641 GiB。Master T1 容量为 0,SGLang eager +replica 关闭,19,658 个历史 replica target 全部指向 CPU `remote_cache` owner。 + +两个 GPU 的 `pending_eviction_reclaim_bytes` 终态分别为 4.500/4.406 GiB,且 workload 结束 +超过 15 分钟后仍未下降;E16ab 为 0/0,E16ag 为 0.125/0 GiB。它不改变 128 GiB owner +配置或 121.6 GiB resident T2 上限,但代表已从 Moka 淘汰、尚未完成 owner reclaim 的权重, +会消耗 segment headroom。高峰期 owner 拒绝原因为 active holder,终态 hot inflight 已归零, +后续 retry 却没有再到达 owner phase。当前观测还不能区分 master key-activity fence 泄漏和 +reclaim retry 停滞,因此 local-side 物理回收尚未完全闭环。 + +终态流水线满足: + +```text +44626 Size eviction = 43762 enqueued + 864 duplicate +43762 enqueued = 19658 completed + 24103 already-satisfied + 1 failed +19658 completed = 19658 master CPU replica targets +``` + +stale、reclaim、obsolete、dispatch-failed 和 inflight 均为 0。相较 E16ag,dispatch 前 stale +与 source-gone/version-mismatch 从 226/1,209 降为 0,最终 `KeyBeingWritten` 丢失从 2,000 +降为 1;这验证了 owner callback 内立即 pin 和有界 busy retry。唯一失败是一个 key 在三次 +append-start 尝试后仍处于 `KeyBeingWritten`;transfer 和 append-done failure 均为 0。 + +性能上,E16ah 相对 E16ag QPS 只提高 0.034%,相对 no-replica E16ab 低 0.93%,相对 +Mooncake 低 1.47%。总命中相对 E16ag 提高 0.218 pp,与 Mooncake 只差 0.089 pp,但单轮变化 +不能全部归因于 CPU;当前 get 指标还没有按 source owner 拆分。owner-local hot Moka 已修复 +副本触发和完成窗口,仍需 atomic-group remote-complete 与 recoverable-first T2 eviction 才能 +把包含式 CPU 副本稳定转成独立有效容量和吞吐收益。 + +在启用 group-aware 淘汰前,应先给 pending reclaim 增加 master-activity、owner-holder、 +route-changed、retry-queued 和 retry-completed 分原因计数,并保证 source pin 释放后请求最终 +reclaim 或安全回插。否则 logical T2 命中和 CPU replica 完成率提高时,物理 segment headroom +仍可能被未终结的 reclaim 占用。 + +#### E16ai Local-side reclaim 闭环验收 + +E16ai 在不修改 owner 容量的前提下完成了上述 pending 闭环。修复包含三个关键生命周期约束: + +- completed `get_holding` 只是 holder backing 的观测状态,不再作为 master 侧 reclaim 的 + blanket veto;真实读者由 owner Prepare 对 `MemoryInfo` 强引用进行权威检查; +- put/get/replica activity lease 在 done、revoke、TTL 和响应发送失败等终态显式幂等释放, + `Drop` 只作兜底,Moka retired clone 不再延迟 activity 计数; +- `ReuseReplica` get done 只有在相同版本、相同 Allocation identity 下才把 master route 标成 + `owner_local_indexed`,确保后续进入 owner 两阶段 reclaim,而不是错误的 master-only 删除。 + +Capacity eviction 对 Busy 请求最多执行 8 次有界指数退避;达到上限后,只在 route 仍是同一 +`put_id` 时把当前条目安全回插 Moka。queue 关闭路径也先结束 pending weight,再按同样的 +current-version 条件回插。pending weight 使用 checked subtraction,运行时分别暴露 +master-activity、master-holder-observed、owner-holder、owner-other、route-changed、retry +queued/completed/restored 和 reclaim-completed 计数。 + +固定 GPU0/GPU1/CPU = 128/128/256 GiB、GPU T2 ratio 0.95、hot ratio 0.75、96 sessions × +12 turns、concurrency 16 的三机正式轮中,两个 GPU pending 的最大 30 秒快照为 +1.031/1.477 GiB;workload 结束后的首个快照均为 0,并在超过 12 分钟的静默观察中保持 0。 +GPU T2 resident 仍为 121.570/121.570 GiB,上限仍为 121.600/121.600 GiB。E16ah 长期残留的 +4.500/4.406 GiB 以及两个 GPU 各 12 次 local get-target NoSpace 均消失。 + +```text +reclaim counter GPU0 GPU1 total +master activity deferred 10 7 17 +completed holder observed 5939 5707 11646 +owner real-holder deferred 5092 4978 10070 +route changed / terminal removal 3149 2996 6145 +retry queued 5007 4583 9590 +retry completed 965 868 1833 +bounded-retry restored 95 402 497 +reclaim completed 3149 2996 6145 +terminal pending bytes 0 0 0 +``` + +这些计数是 attempt 计数,不构成逐列相加的 unique-key 等式;唯一终态要求是 pending 请求 +最终 route removal/change 或安全回插,且 pending bytes 归零。本轮没有 pending underflow、 +safe reclaim queue full/closed 或 retry queue closed。静默期 master 仍有 71 个 completed +`get_holding` / 335,020,032 bytes;它们是 client 仍持有的真实 backing,不是 activity lease, +也不再阻塞其它无真实 reader 的 owner reclaim。 + +正式结果为 1152/1152 成功、6.7585 QPS、92.9691% 总命中。CPU 保留 20,717 entries / +161.852 GiB,20,773 个历史副本目标全部指向 CPU;owner-hot 对账严格满足: + +```text +46576 Size eviction = 45204 enqueued + 35 reclaim-race skip + 1337 duplicate +45204 enqueued = 20773 completed + 24431 already-satisfied +20773 completed = 20773 master CPU replica targets +``` + +E16ai 相对 E16ah QPS 低 0.865%,总命中只高 0.008 pp;因此 reclaim 闭环解决了正确性和 +物理 headroom,但没有把包含式 CPU 副本转成性能收益。atomic-group remote-complete 与 +recoverable-first T2 eviction(或 single-copy demotion)仍是下一层容量策略,不能回退上述 +activity、holder、版本和 slot identity 安全约束。 + +#### E16ao 手动聚合回收与 E16ap 完整组降级 + +E16ao 修复了 resident Moka 八个 segment 各自执行硬容量淘汰的问题。resident Moka 只作为 +无界 metadata/LRU index,Master 按 owner 的 0.95 聚合有效容量显式调用 `evict_some_if`;存在 +ready CPU tier 时,GPU ordinary fallback 为 0,只允许完整 TP cohort 且已有 CPU 副本的条目 +进入两阶段 reclaim。固定三机压力得到 1152/1152 成功、6.6634 QPS、92.58% 总命中和 1,240 +次 CPU-source Get。两个 GPU 的 pending reclaim 终态为 0,recoverable selected 合计约 +34.6 GB,CPU 却保留约 200.9 GB;测量窗口只从 CPU 读取 5.85 GB。该结果证明 group、TP +cohort、CPU Get 和物理 reclaim 均已生效,同时表明大部分 CPU 字节仍是包含式重复副本。 + +E16ap 把 owner-hot write-back 的成功终态收敛为 exact-cohort demotion,内部状态流如下: + +| 阶段 | 必须满足的条件 | 失败行为 | +| --- | --- | --- | +| hot 触发 | Moka `RemovalCause::Size`、当前 `put_id` 和 `MemoryInfo` identity 匹配,完整 owner atomic group 可 pin | 不创建任务,GPU source 保持当前状态 | +| remote append | target 被 `remote_only_node_roles=["remote_cache"]` 限定,append 发布同版本 CPU route | NoSpace/transfer/append 失败释放 pin,不请求 source demotion | +| cohort 验证 | 每个 atomic-group member 当前、每个 TP rank 边界一致,所有成员在同一个 CPU owner 上 live | 本次只计 attempt,不选择任何 GPU resident entry | +| exact selection | resident descriptor 仍是预期版本且当前 route 仍可恢复 | 跳过变化条目,不能删除随后写入的新版本 | +| 物理回收 | Moka Size listener 安装 master activity fence,再执行 owner Prepare/Commit/Finalize | Busy 有界重试;耗尽后仅把仍为当前版本的条目安全回插 | + +E16ap 压测把 owner hot ratio 设为 0.95,与 master resident ratio 对齐。128 GiB GPU owner 的 +逻辑触发点为 121.6 GiB;这只改变冷数据开始异步迁移的时机,不改变 128 GiB 物理 segment。 +CPU 未满时,完整冷 cohort 写入 CPU 后释放 GPU copy;CPU 无空间时,任务不降级,GPU 仍可 +使用剩余物理 headroom。Master 每 30 秒额外报告 `owner_hot_demotion_attempts`、 +`owner_hot_demotion_cohorts` 和 `owner_hot_demotion_selected_bytes`,用于区分“复制完成”与 +“已经转化为独立二级容量”。正式三机结果需要同时满足非零 demotion、CPU-source Get、两侧 +pending 归零和 QPS 高于双 GPU no-replica 基线,不能只用 CPU retained bytes 判定策略有效。 + +两 Fluxon 模拟压测的完整记录保存在本工作区的 `remote_cpu.md`。当前一次完整压力运行得到: + +```text +Moka eviction callbacks: 11463 +safe reclaim reclaimed: 11452 +safe reclaim restored: 11 +processed eviction weight: 96158613504 bytes +``` + +`reclaimed + restored` 与 callback 数严格相等;11 个 Busy/未回收条目按当前版本重新插回 Moka。8 个均匀抽样 key 的 payload 长度和首尾字节均校验通过,其中 3 个已确认在 A local backing 被驱逐后通过 B -> A P2P 读取恢复。该次日志中 safe reclaim queue full/closed、NoSpace 返回调用方、panic、OOM 和 batch failure 均为 0。 + +这次稳态压力运行由按真实 slot 权重的常规 Moka capacity eviction 提前释放内存,因此没有实际触发“申请不到 `512 MiB` grant 后调用 `evict_some`”的 NoSpace 兜底。`evict_some` 另有定向 Moka 契约测试,覆盖请求驱逐量大于/小于现有占用、Busy 条目回插后的 LRU 顺序,并断言调用前后 `max_capacity` 不变。Master activity fence 和 Moka 路径已有单元测试;Owner Prepare/Commit/Abort/Finalize 的主要证据目前来自端到端压测,后续仍应补充直接的并发与故障注入单元测试。 + +#### E16au--E16ax 包含式写回与 local IPC 结论 + +E16au 将 owner-hot 的成功终态改为包含式 CPU write-through:CPU route 发布成功后不立即 +demote GPU source,GPU backing 只由独立的 95% resident 压力回收。固定 +GPU0/GPU1/CPU = 128/128/256 GiB 的正式压力得到 1152/1152、6.7446 QPS、92.90% 总命中; +CPU 保留 8,793 entries / 73.761 GB,CPU-source Get 为 4,349 / 20.521 GB,owner-hot +demotion 与终态 pending reclaim 均为 0。包含式语义消除了主动降级争用,但仍未超过双 GPU +baseline 或 Mooncake;提前 CPU copy 大多只是已有 GPU source 的替代恢复源。 + +这轮有 255,972 条 iceoryx2 `FailedToDeliverSignal`。开放层调低日志等级无法控制闭源 +`libfluxon_commu_core.so` 内静态链接的独立 log-level 符号;完全关闭 local IPC 又在同机 +direct P2P 路径触发 608、`KeyBeingWritten` 终态失败和 Prefill OOM。E16ax 只把 +owner/client receiver 改为 WaitSet 后虽完成 1152/1152,QPS 降至 6.6932;warning 仍有 +232,723 条,且 96.85% 移入 SGLang 关键进程。故 local IPC 必须保留,WaitSet 和完全禁用 +两条方案均不能作为当前修复。 + +#### E16ay Get-target 压力与 local reserve 物理容量闭环 + +local reserve 的 expected capacity 是下限而非硬上限。Put 并发需求可使它从配置的 grant 数 +继续扩张;后续 slot 回收只让 grant 内部变空,并不会自动把这段 512 MiB 物理 allocation +归还 master segment allocator。原 shrink actor 还只检查队尾 grant,并要求连续全空 5 秒。 +另一方面,CPU -> GPU remote Get 的 target 仍是 master 直接从请求 owner 的普通 allocator +分配。因此系统可能同时出现: + +- master Get target 报 `NoSpace/free_capacity=0`; +- owner reserve 内存在大量 free slots; +- `pending_eviction_reclaim_bytes=0`,说明这不是 safe reclaim backlog。 + +E16ax 的实测即为 GPU0/GPU1 18/9 次 Get-target `NoSpace`,而 reserve 最终仍有 1,085/989 个 +空闲 4,718,592-byte slot。E16au 精确重扫也有 10/26 次。该错误会在 atomic-group prefix +计算前截断可传输前缀,使已经存在的 CPU route 不能转成额外命中。 + +修复契约如下: + +| 阶段 | 规则 | +| --- | --- | +| 首次 batch get-start | 保留每个 item 的独立结果,只收集 `API_NO_SPACE` 索引;成功项、KeyNotFound 和其它错误不重发。 | +| 物理让位 | owner 可同步摘除任意完全空闲的多余 grant,不受队尾和 idle cooldown 限制;必须先收到 `release_local_grant` 完成,再重试 Get。 | +| 容量下限 | 归还后 grant 数不得低于 `max(expected_grants, ceil((used_slots + pending_slot_demand) / slots_per_grant))`;Prepared、PendingLocalVisible、Committed 或仍有 holder 的 slot 都不能释放。 | +| 有界重试 | 每轮只替换仍为 NoSpace 的 item,最多 8 轮;不能安全归还 grant 时保留原错误和 prefix fallback。 | +| 容量语义 | 不修改 `contribute_to_cluster_pool_size.dram`、resident/hot Moka capacity 或 expected reserve;这是把已经空闲的物理 grant 及时归还 allocator,不是缩 owner 容量。 | + +该路径与 `evict_some` 的职责不同:本步骤优先回收“已经完全空闲但仍被 reserve 持有”的 +grant,不产生新的 KV 淘汰;若没有这种 grant,现有 safe reclaim/NoSpace 语义继续生效,不能 +为了 Get 强行释放 live backing。新增定向测试覆盖只选 NoSpace item、非队尾 grant 与容量下限。 + +E16ay 的固定 128/128/256 GiB 三机正式验收得到 1152/1152、6.8269 QPS 和 93.02% 总命中。 +GPU0/GPU1 分别通过 2/3 次 pressure retry 恢复 30/54 个 NoSpace item,全部首轮达到 +`no_space_after=0`,没有错误传到 SGLang。CPU-source Get 为 4,942 / +23,319,281,664 bytes;CPU 保留 8,855 entries / 74,281,123,840 bytes;两个 GPU terminal +pending 与 owner-hot demotion 都为 0。配置的 owner 容量、resident/hot 容量和 232-grant +expected 下限没有改变。这证明同步归还空 grant 可以闭合 Get-target 物理 headroom,但 QPS +仍比双 GPU baseline 低 0.79%、比 Mooncake 低 1.33%。 + +#### E16az external local-IPC busy-poll 验收 + +E16ay 的两个 GPU owner 仍分别产生 147,124/150,701 条 iceoryx2 +`FailedToDeliverSignal`。失败的是 owner -> SGLang external 的逐消息 event notification, +subscriber 数据本身仍存在。E16az 保持 E16ay release 与所有容量/策略/工作负载不变,仅令 GPU +owner 和 SGLang external receiver 使用 `iceoryx_external_busy_poll=true`。此模式直接 drain +subscriber,发送端不会创建 notifier;owner/client 内部 receiver 原有的 busy-poll 设置不变。 + +正式轮仍为 1152/1152、576/576,四份相关日志的 `FailedToDeliverSignal` 全部为 0,GPU owner +日志缩到约 132/137 KB。local IPC 和 RDMA 数据路径仍存活,CPU-source Get 为 4,965 / +23,427,809,280 bytes,CPU 保留 8,610 entries / 72,225,914,880 bytes;74 个 Get-target +NoSpace item 全部被 E16ay 路径恢复。terminal pending、surfaced NoSpace、业务 5xx、P2P 608、 +OOM 和 scheduler exception 均为 0。 + +性能为 6.7888 QPS、93.02% 总命中,比 E16ay 低 0.56%、比双 GPU baseline 低 1.34%。因此 +事件告警格式化不是剩余吞吐主瓶颈;持续 external polling 的 CPU contention 可能抵消省下的 +日志工作,且这一小幅差值可能包含单轮波动。设计上可把 external busy-poll 作为避免 notifier +风暴的运行模式,但不能把它视为 CPU replica 转化为吞吐收益的容量策略。下一步仍应直接减少 +包含式重复副本的无效工作,或降低 CPU Get/replica 进入 SGLang 关键路径的等待开销。 + +#### E16ba Hot/resident lead-window 契约 + +包含式 owner-hot write-through 不能通过简单地把 hot capacity 提到 resident capacity 来实现 +“驱逐即 write-back”。hot eviction 只产生异步 CPU append 信号;resident eviction 则要求 +CPU 上已经存在完整、同版本、同 TP cohort 的 durable backing。两者必须保留足够的 lead +window,否则 resident pressure 会先于 remote completion 到达。 + +固定 resident=0.95、reserve=0.90 和 128/128/256 GiB 容量,对 hot=0.92/0.94/0.95 的三次 +正式冷启动扫描结果为: + +| hot | QPS | CPU placement | CPU Gets | recoverable selected | shortfall | +| ---: | ---: | ---: | ---: | ---: | ---: | +| 0.90 E16ay | 6.826884 | 8,860 | 4,942 | 65,729,986,560 B | 0 | +| 0.92 | 6.824876 | 7,413 | 3,214 | 51,091,865,600 B | 0 | +| 0.94 | 6.792892 | 5,893 | 2,108 | 41,800,433,664 B | 0 | +| 0.95 | 6.623042 | 5,341 | 1,496 | 36,394,500,096 B | 32,925,181,564 B | + +四轮 overall hit 都为 93.02%,因此下降不是 cache miss 数量变化。0.92 以几乎相同 QPS +减少 16.3% placement 和 35.0% CPU Get,证明较早触发包含冗余工作;0.94 开始变慢;0.95 +请求 69,316,116,502 bytes recoverable victim 时只有 36,394,500,096 bytes 已 CPU-complete, +QPS 相对 0.90 下降 2.99%。三轮均无 surfaced NoSpace、terminal pending、业务错误或容量变化。 + +因此静态 hot threshold 在该 workload 下必须比 resident 至少提前约 3--5pp。若设计目标是真正 +的 eviction-time write-back,应由 resident 的精确 victim 触发 CPU append,并为该 victim +建立有界 completion fence;或者根据 replica queue depth、传输延迟和 resident growth rate +动态计算 lead。不能让两个独立 Moka 同阈值后依赖调度碰巧完成。 + +#### E16bc--E16bj SGLang 调度容量、replica pipeline 与发布门禁 + +固定 Fluxon GPU0/GPU1/CPU owner 为 128/128/256 GiB 后,端到端吞吐的最大增益并非继续改 +Moka 水位,而是解除 SGLang scheduler 的串行与 token-pool 约束。E16bc 只把每个 TP=2 服务的 +`max_total_tokens` 从 100,000 提到 200,000,QPS 从 E16bb 的 6.773531 提到 8.645063;E16cc +再启用默认 overlap scheduler,正式冷启动达到 10.056034 QPS。该轮 1,152/1,152 成功、两端 +各 576 请求、总命中 92.96%,GPU 初始化后仍各有约 53.51 GiB 可用显存。这里的 +`max_total_tokens` 是 SGLang GPU scheduler/KV pool 参数,不修改 Fluxon owner segment、resident +Moka、hot Moka 或 local-reserve 的容量;配置与结果记录不能把两种“容量”混为一谈。 + +overlap scheduler 允许 HiCache restore/prefill 的调度推进与 GPU decode 工作交叠。关闭 overlap +时,同样的外部命中率并不表示同样的吞吐,因为 storage future、prefill admission 和 decode +会在 scheduler step 边界上串行等待。因此正式性能对比必须同时固定 +`max_total_tokens`、`disable_overlap_schedule`、CUDA graph、并发和 workload round barrier。 + +owner replica actor 原先全局只能有一个 append pipeline 在途,每个不同 key 都依次等待 +append-start、RDMA completion 与 append-done。`test_spec_config.replica_task_max_inflight` 将其改为 +1--64 的有界跨 key 并发,默认 1 保持兼容;全局 semaphore 限制总在途数,每个 key 另有单许可 +semaphore,所以不同 key 可以并行,同 key 的版本/任务仍严格串行。E16bh 在两个 GPU owner 设为 +16,CPU owner 保持 1;该参数改变复制流水线深度,不改变 owner 容量、placement 或原子组完整性。 + +组合发布还必须经过目标机 ABI 预检。E16bf 的 wheel 文件名虽然声明 +`manylinux_2_28_x86_64`,其中新 closed core 实际引用了 `GLIBC_2.39`,三台正式机器因此在 master +import 阶段 fail-fast,未发送任何 workload。发布门禁应对 wheel 内每个 bundled `.so` 检查最高 +GLIBC symbol version,并在三种目标 Python/宿主环境做 import smoke;仅检查 wheel tag 或构建成功 +不足以证明可部署。兼容性回退 E16bd 保留开放层 replica pipeline,并沿用已验证 closed core。 + +E16bj 在真实 manylinux 2.28 builder 中重建 closed core 后,通过了 wheel 内全部 `.so` 的 +symbol-version 扫描和 Python 3.10/3.11/3.12 import smoke。正式三机冷启动保持 +GPU0/GPU1/CPU = 128/128/256 GiB、GPU pipeline=16、CPU-only placement、200k token pool 和 +overlap scheduler,得到 1,152/1,152、576/576、10.045299 QPS 和 92.99% 总命中。CPU 承担 +8,770 个 replica target 与 4,990 次 remote Get;GPU replica target、终态 replica inflight、 +replica failure 和 pending reclaim 均为 0。E16cc/E16bh/E16bj 的最低和平均 QPS 为 +10.020985/10.040772,说明 10-QPS 结果可由可部署组合版本复现。 + +E16be closed sharding 修复要求所有正长度 transfer 的 child 都非空:按 sharding quantum 做 ceil +division并省略空 child;只有显式零长度请求保留一个零长度 child,以维持 completion contract。 +这项约束属于通信正确性和尾延迟卫生,不能用 wheel tag 代替测试,也不能从 E16bj 相对 E16bh +仅 +0.24% 的单轮差值推导出稳定吞吐增益。 + ## SGLang Node Storage 状态 SGLang 侧的 node metadata 不等价于 Fluxon master route 状态。当前四个字段建议按下面语义解释: @@ -438,6 +1328,18 @@ SGLang 侧的 node metadata 不等价于 Fluxon master route 状态。当前四 TP 场景下,每个 rank 仍有各自的 radix tree 和恢复决策。`get_start` 的结果只描述当前 rank 这批 keys 的可恢复前缀;如果一个 rank miss、另一个 rank hit,上层必须按 SGLang 的 TP restore 约束处理一致性,不能把单 rank 的部分成功当作完整 request 已恢复。 +Put admission 的随机 identity 必须跨 TP rank 稳定。物理 storage key 保留 `_0_2`、`_1_2` +等 rank 后缀,用于区分不同 rank 的 KV bytes;ratio/score jitter 和 atomic-group hash 则使用 +保留 TP size、去掉 TP rank 的 admission key。同一个逻辑 radix group 因而在所有 TP ranks +上得到同一 admitted/skipped 决策,同时仍生成不同物理 keys。只约束单 rank 内 mask 不切组, +无法满足这个跨 rank 不变量。 + +各 rank 首次 `get_start` 的 `transferable_len` 不一致时,SGLang 先用 collective 取最小值。 +该最小值必须落在共同的 atomic-group 边界;每个 rank 取消原 handle,再以该最小完整-group +前缀重新执行一次 `get_start`,随后再次 collective 校验长度一致。第二次仍不一致才放弃本轮 +restore。不能直接使用较长 rank 的 handle,也不应因为尾部差异把两个 rank 已共同命中的 +前缀全部作废。 + ## 失败处理 | 场景 | 必须动作 | diff --git a/fluxon_py/config.py b/fluxon_py/config.py index 5861f64..74f8746 100644 --- a/fluxon_py/config.py +++ b/fluxon_py/config.py @@ -66,6 +66,7 @@ def _yaml_template(): protocol_type: # Protocol type (('tcp'|'rdma')) rdma_device_names: # Explicit RDMA devices for protocol config (['{str}'](optional)) pprof_duration_seconds: # Dump pprof flamegraph after N seconds (int(optional)) +replica_writeback_hot_capacity_ratio: 0.75 # Owner-local hot working-set ratio in the open interval zero to one (float(optional)) contribute_to_cluster_pool_size: # Capacity contributed to cluster pool (dict(optional)) dram: 1677721600 # - DRAM contribution (int(multiple of 16777216)) vram: # - VRAM contribution per GPU (dict(dynamic_key)) @@ -82,11 +83,17 @@ def _yaml_template(): prefer_local_placement: false # Prefer placing new KV writes on the requester-local owner when possible (bool(optional)) short_circuit_put_payload_path: false # Keep large put_start allocation but skip payload memcpy + transfer (bool(optional)) skip_put_end_commit: false # Return success after payload transfer without put_done commit; inflight_put TTL cleanup only (bool(optional)) + owner_local_reserve_soft_wait_timeout_ms: # Local-reserve polling interval, >0 (int(optional)) + owner_local_reserve_hard_timeout_ms: # Local-reserve end-to-end claim timeout, > soft wait (int(optional)) + owner_local_reserve_expected_capacity: # Owner-only local-reserve prewarm target (dict(optional)) + value_len: # Canonical value payload bytes, >0 and <=512 MiB (int) + payload_capacity_bytes: # Expected payload capacity to keep resident, >0 (int) transport_mode: # transfer_only|transfer_with_rpc (str(optional)) tcp_thread_reactor_shard_count: # tcp_thread reactor shard count, 1..16 (int(optional)) tcp_thread_bulk_lane_count: # tcp_thread bulk lane count, 1..8 (int(optional)) tcp_thread_control_lane_count: # tcp_thread control lane count, 1..8 (int(optional)) user_rpc_sync_handler_thread_count: # Owner-dedicated sync user-RPC worker thread count, >0 (int(optional)) + replica_task_max_inflight: # Concurrent replica append pipelines, 1..64; per-key order stays serialized (int(optional)) require_transfer_rpc_fast_path_ready_timeout_seconds: # Require owner-owner transfer-rpc fast path before owner ready/shared.json publication (int(optional)) rdma_device_names: # Explicit RDMA devices for benchmark/test fast-path fanout (['{str}'](optional)) enable_side_transfer: false # Enable TCP side-transfer fast-path (bool(optional)) @@ -135,11 +142,15 @@ def _normalize_test_spec_config(raw: Any, ctx: str) -> Dict[str, Any]: "prefer_local_placement", "short_circuit_put_payload_path", "skip_put_end_commit", + "owner_local_reserve_soft_wait_timeout_ms", + "owner_local_reserve_hard_timeout_ms", + "owner_local_reserve_expected_capacity", "transport_mode", "tcp_thread_reactor_shard_count", "tcp_thread_bulk_lane_count", "tcp_thread_control_lane_count", "user_rpc_sync_handler_thread_count", + "replica_task_max_inflight", "require_transfer_rpc_fast_path_ready_timeout_seconds", "rdma_device_names", "enable_side_transfer", @@ -234,6 +245,7 @@ def _normalize_test_spec_config(raw: Any, ctx: str) -> Dict[str, Any]: ("tcp_thread_reactor_shard_count", 1, 16), ("tcp_thread_bulk_lane_count", 1, 8), ("tcp_thread_control_lane_count", 1, 8), + ("replica_task_max_inflight", 1, 64), ): value = raw.get(key) if value is None: @@ -254,6 +266,50 @@ def _normalize_test_spec_config(raw: Any, ctx: str) -> Dict[str, Any]: raise ValueError(f"{ctx}.user_rpc_sync_handler_thread_count must be > 0") out["user_rpc_sync_handler_thread_count"] = user_rpc_sync_handler_thread_count + reserve_timeouts: Dict[str, int] = {} + for key in ( + "owner_local_reserve_soft_wait_timeout_ms", + "owner_local_reserve_hard_timeout_ms", + ): + value = raw.get(key) + if value is None: + continue + if isinstance(value, bool) or not isinstance(value, int): + raise ValueError(f"{ctx}.{key} must be an int") + if value <= 0: + raise ValueError(f"{ctx}.{key} must be > 0") + reserve_timeouts[key] = value + out[key] = value + soft_timeout_ms = reserve_timeouts.get("owner_local_reserve_soft_wait_timeout_ms", 10) + hard_timeout_ms = reserve_timeouts.get("owner_local_reserve_hard_timeout_ms", 10_000) + if hard_timeout_ms <= soft_timeout_ms: + raise ValueError( + f"{ctx}.owner_local_reserve_hard_timeout_ms must be greater than " + f"{ctx}.owner_local_reserve_soft_wait_timeout_ms" + ) + + expected_capacity = raw.get("owner_local_reserve_expected_capacity") + if expected_capacity is not None: + expected_ctx = f"{ctx}.owner_local_reserve_expected_capacity" + if not isinstance(expected_capacity, dict): + raise ValueError(f"{expected_ctx} must be a mapping") + unknown_expected = sorted( + set(expected_capacity.keys()) - {"value_len", "payload_capacity_bytes"} + ) + if unknown_expected: + raise ValueError(f"{expected_ctx} contains unknown keys: {unknown_expected}") + normalized_expected: Dict[str, int] = {} + for key in ("value_len", "payload_capacity_bytes"): + value = expected_capacity.get(key) + if isinstance(value, bool) or not isinstance(value, int): + raise ValueError(f"{expected_ctx}.{key} must be an int") + if value <= 0: + raise ValueError(f"{expected_ctx}.{key} must be > 0") + normalized_expected[key] = value + if normalized_expected["value_len"] > 512 * 1024 * 1024: + raise ValueError(f"{expected_ctx}.value_len must be <= 536870912") + out["owner_local_reserve_expected_capacity"] = normalized_expected + side_transfer_worker_count = raw.get("side_transfer_worker_count") if side_transfer_worker_count is not None: if isinstance(side_transfer_worker_count, bool) or not isinstance(side_transfer_worker_count, int): @@ -348,6 +404,23 @@ def _validate_fluxonkv_contract(cfg: Dict[str, Any]) -> None: raise ValueError("fluxonkv_spec must be a mapping") is_zero_contribution = _is_zero_contribution_fluxonkv_config(cfg) + test_spec_config = cfg.get("test_spec_config") or {} + expected_capacity = test_spec_config.get("owner_local_reserve_expected_capacity") + hot_capacity_ratio = cfg.get("replica_writeback_hot_capacity_ratio") + + if hot_capacity_ratio is not None: + if isinstance(hot_capacity_ratio, bool) or not isinstance( + hot_capacity_ratio, (int, float) + ): + raise ValueError( + "replica_writeback_hot_capacity_ratio must be a number in (0, 1)" + ) + hot_capacity_ratio = float(hot_capacity_ratio) + if not 0.0 < hot_capacity_ratio < 1.0: + raise ValueError( + "replica_writeback_hot_capacity_ratio must be finite and in (0, 1)" + ) + cfg["replica_writeback_hot_capacity_ratio"] = hot_capacity_ratio share_mem_path = spec.get("share_mem_path") if not isinstance(share_mem_path, str) or not share_mem_path.strip(): @@ -360,6 +433,14 @@ def _validate_fluxonkv_contract(cfg: Dict[str, Any]) -> None: raise ValueError("fluxonkv_spec.transfer_engine has been removed from Fluxon KV config") if is_zero_contribution: + if hot_capacity_ratio is not None: + raise ValueError( + "replica_writeback_hot_capacity_ratio is only valid on owner configs" + ) + if expected_capacity is not None: + raise ValueError( + "test_spec_config.owner_local_reserve_expected_capacity is only valid on owner configs" + ) forbidden_spec_keys = [ "etcd_addresses", "redis_compat", @@ -379,6 +460,23 @@ def _validate_fluxonkv_contract(cfg: Dict[str, Any]) -> None: if int(contrib["dram"]) == 0: raise ValueError("owner mode requires non-zero contribute_to_cluster_pool_size.dram") + if expected_capacity is not None: + value_len = int(expected_capacity["value_len"]) + payload_capacity_bytes = int(expected_capacity["payload_capacity_bytes"]) + slot_size = max(value_len, 4096) + slot_size = (slot_size + 4095) & ~4095 + slots_per_grant = (512 * 1024 * 1024) // slot_size + value_count = (payload_capacity_bytes + value_len - 1) // value_len + expected_grants = (value_count + slots_per_grant - 1) // slots_per_grant + physical_reserve_bytes = expected_grants * 512 * 1024 * 1024 + owner_dram_bytes = int(contrib["dram"]) + if physical_reserve_bytes > owner_dram_bytes: + raise ValueError( + "test_spec_config.owner_local_reserve_expected_capacity requires " + f"{physical_reserve_bytes} physical bytes across {expected_grants} grants, " + f"exceeding owner dram contribution {owner_dram_bytes}" + ) + if "etcd_addresses" not in spec: raise ValueError("fluxonkv_spec.etcd_addresses is required for owner mode") etcd_addresses = spec.get("etcd_addresses") @@ -434,6 +532,10 @@ def __init__(self, config_dict: Dict[str, Any]): raise ValueError( "exactly one of [mooncake_spec, fluxonkv_spec] is required (and the chosen spec must not be null)" ) + if "replica_writeback_hot_capacity_ratio" in plain and not has_fluxon: + raise ValueError( + "replica_writeback_hot_capacity_ratio requires fluxonkv_spec" + ) pprof_duration_seconds = plain.get("pprof_duration_seconds") if pprof_duration_seconds is None: @@ -750,8 +852,8 @@ def parse_type_recursive(type_str: str) -> Optional[Tuple[str, Dict[str, Any]]]: return parsed_type_name, merged_params return type_name, {"constraint": constraint} - # 6) Primitive types: str, int, bool, None - if type_str in ["str", "int", "bool", "None"]: + # 6) Primitive types: str, int, float, bool, None + if type_str in ["str", "int", "float", "bool", "None"]: return type_str, {} debug_print("type_str ", type_str, "not matched to any type") @@ -871,7 +973,16 @@ def raise_validation_error(msg: str): raise_validation_error(f"Value must be multiple of {multiple}, got {value}") else: return None - + + elif type_name == "float": + if isinstance(value, bool) or not isinstance(value, (int, float)): + if raise_err: + raise_validation_error( + f"Expected float-compatible number, got {type(value).__name__}" + ) + else: + return None + elif type_name == "bool": if not isinstance(value, bool): if raise_err: diff --git a/fluxon_py/kvclient/fluxon.py b/fluxon_py/kvclient/fluxon.py index ae9df9a..c794c63 100644 --- a/fluxon_py/kvclient/fluxon.py +++ b/fluxon_py/kvclient/fluxon.py @@ -55,6 +55,63 @@ _SIDE_TRANSFER_WORKER_PYTHON_ENV = "FLUXON_KV_SIDE_WORKER_PYTHON" _BLOCKING_PUT_OUTER_TOTAL_LOG_INTERVAL_NS = 10 * 1_000_000_000 +_MIN_EXPLICIT_RPC_TIMEOUT_MS = int(fluxon_pyo3.MIN_EXPLICIT_RPC_TIMEOUT_MS) + + +def _validate_explicit_rpc_timeout_ms(timeout_ms: int) -> None: + if not isinstance(timeout_ms, int): + raise InvalidArgumentError(message=f"timeout_ms must be int; got {type(timeout_ms)}") + if timeout_ms < _MIN_EXPLICIT_RPC_TIMEOUT_MS: + raise InvalidArgumentError( + message=( + f"timeout_ms must be >= {_MIN_EXPLICIT_RPC_TIMEOUT_MS}; " + f"got {timeout_ms}" + ) + ) + + +def _validate_put_atomic_groups( + keys: List[str], + atomic_group_lens: Optional[List[int]], + make_replica_task_mask: Optional[List[bool]], +) -> Optional[List[int]]: + if atomic_group_lens is None: + return None + if not isinstance(atomic_group_lens, list): + raise ValueError( + "atomic_group_lens must be list[int] when provided; " + f"got {type(atomic_group_lens)}" + ) + normalized_group_lens: List[int] = [] + for index, length in enumerate(atomic_group_lens): + if type(length) is not int: + raise ValueError( + "atomic_group_lens items must be int; " + f"index={index} got={type(length)}" + ) + if length <= 0: + raise ValueError( + "atomic_group_lens entries must be > 0; " + f"index={index} got={length}" + ) + normalized_group_lens.append(length) + group_sum = sum(normalized_group_lens) + if group_sum != len(keys): + raise ValueError( + "atomic_group_lens must sum to keys length; " + f"sum={group_sum} keys={len(keys)}" + ) + if make_replica_task_mask is not None: + offset = 0 + for group_index, group_len in enumerate(normalized_group_lens): + group_mask = make_replica_task_mask[offset : offset + group_len] + if any(item != group_mask[0] for item in group_mask[1:]): + raise ValueError( + "make_replica_task_mask must be uniform within each atomic group; " + f"group_index={group_index} offset={offset} len={group_len}" + ) + offset += group_len + return normalized_group_lens def _percentile_nearest_rank_ns(sorted_values: List[int], percentile: int) -> int: @@ -480,6 +537,9 @@ def put( bool(opts.reject_if_exist_same_key) if opts is not None else False ) write_through = bool(opts.write_through) if opts is not None else True + make_replica_task = ( + bool(opts.make_replica_task) if opts is not None else True + ) inner_res = self._client.put( key, ptrs, @@ -487,6 +547,7 @@ def put( reject_if_inflight_same_key=reject_if_inflight_same_key, reject_if_exist_same_key=reject_if_exist_same_key, write_through=write_through, + make_replica_task=make_replica_task, ) if not inner_res.is_ok(): err = inner_res.unwrap_error() @@ -534,6 +595,9 @@ def put_blocking( bool(opts.reject_if_exist_same_key) if opts is not None else False ) write_through = bool(opts.write_through) if opts is not None else True + make_replica_task = ( + bool(opts.make_replica_task) if opts is not None else True + ) inner_res = self._client.put_blocking( key, ptrs, @@ -541,6 +605,7 @@ def put_blocking( reject_if_inflight_same_key=reject_if_inflight_same_key, reject_if_exist_same_key=reject_if_exist_same_key, write_through=write_through, + make_replica_task=make_replica_task, ) if not inner_res.is_ok(): return Result.new_error(inner_res.unwrap_error()) @@ -605,6 +670,7 @@ def batch_put_blocking( bool(opts.reject_if_exist_same_key) if opts is not None else False ) write_through = bool(opts.write_through) if opts is not None else True + make_replica_task = bool(opts.make_replica_task) if opts is not None else True keepalive_groups: List[List[bytes]] = [] dlpack_groups: List[List[object]] = [] @@ -624,6 +690,7 @@ def batch_put_blocking( reject_if_inflight_same_key=reject_if_inflight_same_key, reject_if_exist_same_key=reject_if_exist_same_key, write_through=write_through, + make_replica_task=make_replica_task, concurrency=concurrency if concurrency is not None else self._batch_concurrency, ) if not inner_res.is_ok(): @@ -741,6 +808,9 @@ def put_payload_from_ptr( bool(opts.reject_if_exist_same_key) if opts is not None else False ) write_through = bool(opts.write_through) if opts is not None else True + make_replica_task = ( + bool(opts.make_replica_task) if opts is not None else True + ) inner_res = self._client.put( key, ptrs, @@ -748,6 +818,7 @@ def put_payload_from_ptr( reject_if_inflight_same_key=reject_if_inflight_same_key, reject_if_exist_same_key=reject_if_exist_same_key, write_through=write_through, + make_replica_task=make_replica_task, ) if not inner_res.is_ok(): return Result.new_error(_map_nospace_to_storagefull(inner_res.unwrap_error())) @@ -786,6 +857,9 @@ def put_payload_from_ptr_blocking( bool(opts.reject_if_exist_same_key) if opts is not None else False ) write_through = bool(opts.write_through) if opts is not None else True + make_replica_task = ( + bool(opts.make_replica_task) if opts is not None else True + ) inner_res = self._client.put_blocking( key, ptrs, @@ -793,6 +867,7 @@ def put_payload_from_ptr_blocking( reject_if_inflight_same_key=reject_if_inflight_same_key, reject_if_exist_same_key=reject_if_exist_same_key, write_through=write_through, + make_replica_task=make_replica_task, ) if not inner_res.is_ok(): return Result.new_error(inner_res.unwrap_error()) @@ -989,6 +1064,7 @@ def batch_put_from( bool(opts.reject_if_exist_same_key) if opts is not None else False ) write_through = bool(opts.write_through) if opts is not None else True + make_replica_task = bool(opts.make_replica_task) if opts is not None else True try: inner_res = self._client.batch_put_from( @@ -999,6 +1075,7 @@ def batch_put_from( reject_if_inflight_same_key=reject_if_inflight_same_key, reject_if_exist_same_key=reject_if_exist_same_key, write_through=write_through, + make_replica_task=make_replica_task, ) if inner_res.is_ok(): submit_results = list(inner_res.unwrap()) @@ -1203,10 +1280,7 @@ def rpc_call( try: if self._client is None: raise GeneralError(message="Store not initialized when rpc_call(). Call setup() first.") - if not isinstance(timeout_ms, int): - raise InvalidArgumentError(message=f"timeout_ms must be int; got {type(timeout_ms)}") - if timeout_ms < 10_000: - raise InvalidArgumentError(message=f"timeout_ms must be >= 10000; got {timeout_ms}") + _validate_explicit_rpc_timeout_ms(timeout_ms) encoded = encode_flat_kv_dict(payload) if not encoded.is_ok(): @@ -1233,10 +1307,7 @@ def rpc_call_bytes( raise GeneralError(message="Store not initialized when rpc_call_bytes(). Call setup() first.") if not isinstance(payload, (bytes, bytearray)): raise InvalidArgumentError(message=f"payload must be bytes; got {type(payload)}") - if not isinstance(timeout_ms, int): - raise InvalidArgumentError(message=f"timeout_ms must be int; got {type(timeout_ms)}") - if timeout_ms < 10_000: - raise InvalidArgumentError(message=f"timeout_ms must be >= 10000; got {timeout_ms}") + _validate_explicit_rpc_timeout_ms(timeout_ms) inner = self._client.rpc_call(node_id, path, bytes(payload), timeout_ms) if not inner.is_ok(): @@ -1328,10 +1399,7 @@ def sync_kv_to_file( raise InvalidArgumentError(message=f"file_offset must be int; got {type(file_offset)}") if file_offset < 0: raise InvalidArgumentError(message=f"file_offset must be >= 0; got {file_offset}") - if not isinstance(timeout_ms, int): - raise InvalidArgumentError(message=f"timeout_ms must be int; got {type(timeout_ms)}") - if timeout_ms < 10_000: - raise InvalidArgumentError(message=f"timeout_ms must be >= 10000; got {timeout_ms}") + _validate_explicit_rpc_timeout_ms(timeout_ms) return self._client.sync_kv_to_file( target_instance_key, @@ -1452,12 +1520,41 @@ def local_fast_put_start( bool(opts.reject_if_exist_same_key) if opts is not None else False ) write_through = bool(opts.write_through) if opts is not None else True + make_replica_task = bool(opts.make_replica_task) if opts is not None else True + make_replica_task_mask: Optional[List[bool]] = None + if opts is not None and opts.make_replica_task_mask is not None: + requested_mask = opts.make_replica_task_mask + if not isinstance(requested_mask, list): + raise ValueError( + "make_replica_task_mask must be list[bool] when provided; " + f"got {type(requested_mask)}" + ) + if len(requested_mask) != len(keys): + raise ValueError( + "make_replica_task_mask length must match keys length; " + f"keys={len(keys)} mask={len(requested_mask)}" + ) + for index, item in enumerate(requested_mask): + if type(item) is not bool: + raise ValueError( + "make_replica_task_mask items must be bool; " + f"index={index} got={type(item)}" + ) + make_replica_task_mask = list(requested_mask) + atomic_group_lens = _validate_put_atomic_groups( + keys, + opts.atomic_group_lens if opts is not None else None, + make_replica_task_mask, + ) inner_res = self._client.local_fast_put_start( keys, value_len, reject_if_inflight_same_key=reject_if_inflight_same_key, reject_if_exist_same_key=reject_if_exist_same_key, write_through=write_through, + make_replica_task=make_replica_task, + make_replica_task_mask=make_replica_task_mask, + atomic_group_lens=atomic_group_lens, ) if not inner_res.is_ok(): err = inner_res.unwrap_error() @@ -1609,6 +1706,7 @@ def cancel_get_transfer(self, handle: GetStartHandle) -> None: raise RuntimeError( f"cancel_get_transfer backend error: {inner_res.unwrap_error()}" ) + _ = inner_res.unwrap() handle.closed = True def get_transfer( diff --git a/fluxon_py/kvclient/kvclient_interface.py b/fluxon_py/kvclient/kvclient_interface.py index e126eec..bb248da 100644 --- a/fluxon_py/kvclient/kvclient_interface.py +++ b/fluxon_py/kvclient/kvclient_interface.py @@ -75,11 +75,22 @@ class PutOptionalArgs: - write_through: keep synchronous remote-placement semantics when the backend supports an async write-back path. Defaults to True to match SGLang HiCache's default write policy. + - make_replica_task: enqueue an asynchronous replica after a local write-back + commit. Set False for a local-only write-back. + - make_replica_task_mask: optional per-key replica admission decisions for + local_fast_put_start(). Its length must match the key batch. The scalar + make_replica_task remains the batch-wide gate. + - atomic_group_lens: optional positive lengths that partition the ordered + local_fast_put_start() key batch into atomic groups. Replica admission + must be uniform within every group. """ lease_id: Optional[int] = None reject_if_inflight_same_key: bool = False reject_if_exist_same_key: bool = False write_through: bool = True + make_replica_task: bool = True + make_replica_task_mask: Optional[List[bool]] = None + atomic_group_lens: Optional[List[int]] = None def support_mooncake(self) -> Tuple[bool, List[str]]: """ @@ -100,6 +111,12 @@ def support_mooncake(self) -> Tuple[bool, List[str]]: unsupported.append("reject_if_exist_same_key") if self.write_through: unsupported.append("write_through") + if not self.make_replica_task: + unsupported.append("make_replica_task") + if self.make_replica_task_mask is not None: + unsupported.append("make_replica_task_mask") + if self.atomic_group_lens is not None: + unsupported.append("atomic_group_lens") return (len(unsupported) == 0, unsupported) diff --git a/fluxon_py/tests/test_config.py b/fluxon_py/tests/test_config.py index 6de5180..3ed2a5e 100644 --- a/fluxon_py/tests/test_config.py +++ b/fluxon_py/tests/test_config.py @@ -54,6 +54,7 @@ def _build_checks(selected_test_id: Optional[str]) -> List[Tuple[str, Callable[[ ("fluxonkv_protocol_field", test_fluxonkv_protocol_field), ("fluxonkv_runtime_defaults_are_internal", test_fluxonkv_runtime_defaults_are_internal), ("fluxonkv_removed_rdma_config_keys", test_fluxonkv_removed_rdma_config_keys), + ("fluxonkv_owner_hot_writeback", test_fluxonkv_owner_hot_writeback), ("fluxonkv_test_spec_config", test_fluxonkv_test_spec_config), ("fluxon_pyo3_import_authority", test_fluxon_pyo3_import_authority), ] @@ -444,6 +445,61 @@ def test_fluxonkv_removed_rdma_config_keys(): print(f"❌ FAIL: test_fluxonkv_removed_rdma_config_keys - {e}") +def test_fluxonkv_owner_hot_writeback(): + """Validate the owner-only hot-tier ratio and preserve it in Rust YAML.""" + try: + owner = _owner_fluxonkv_base_config(tag="owner_hot_writeback") + owner["replica_writeback_hot_capacity_ratio"] = 0.75 + loaded = yaml.safe_load( + FluxonKvClientConfig(owner).to_fluxon_kv_client_config_yaml_str() + ) + assert loaded["replica_writeback_hot_capacity_ratio"] == 0.75 + + for invalid in (0, 1, -0.1, float("nan"), True, "0.75"): + invalid_owner = _owner_fluxonkv_base_config(tag="owner_hot_invalid") + invalid_owner["replica_writeback_hot_capacity_ratio"] = invalid + try: + FluxonKvClientConfig(invalid_owner) + print( + "❌ FAIL: test_fluxonkv_owner_hot_writeback - invalid ratio should be rejected" + ) + return + except ValueError: + pass + + external = { + "instance_key": "external_hot_invalid", + "replica_writeback_hot_capacity_ratio": 0.75, + "fluxonkv_spec": { + "cluster_name": "test_cluster", + "share_mem_path": "/tmp/kvcache_shared_memory/external_hot_invalid", + }, + } + try: + FluxonKvClientConfig(external) + print( + "❌ FAIL: test_fluxonkv_owner_hot_writeback - external ratio should be rejected" + ) + return + except ValueError: + pass + + mooncake = config_dict() + mooncake["replica_writeback_hot_capacity_ratio"] = 0.75 + try: + FluxonKvClientConfig(mooncake) + print( + "❌ FAIL: test_fluxonkv_owner_hot_writeback - Mooncake ratio should be rejected" + ) + return + except ValueError: + pass + + print("✅ PASS: test_fluxonkv_owner_hot_writeback") + except Exception as e: + print(f"❌ FAIL: test_fluxonkv_owner_hot_writeback - {e}") + + def test_fluxonkv_test_spec_config(): """Ensure test_spec_config is accepted, normalized, and serialized.""" try: @@ -473,6 +529,7 @@ def test_fluxonkv_test_spec_config(): rdma_devices["test_spec_config"]["tcp_thread_reactor_shard_count"] = 2 rdma_devices["test_spec_config"]["tcp_thread_bulk_lane_count"] = 4 rdma_devices["test_spec_config"]["tcp_thread_control_lane_count"] = 3 + rdma_devices["test_spec_config"]["replica_task_max_inflight"] = 16 rdma_devices["test_spec_config"][ "require_transfer_rpc_fast_path_ready_timeout_seconds" ] = 45 @@ -487,12 +544,58 @@ def test_fluxonkv_test_spec_config(): assert loaded["test_spec_config"]["tcp_thread_reactor_shard_count"] == 2 assert loaded["test_spec_config"]["tcp_thread_bulk_lane_count"] == 4 assert loaded["test_spec_config"]["tcp_thread_control_lane_count"] == 3 + assert loaded["test_spec_config"]["replica_task_max_inflight"] == 16 assert ( loaded["test_spec_config"]["require_transfer_rpc_fast_path_ready_timeout_seconds"] == 45 ) assert config.protocol_rdma_device_names == "mlx5_0,mlx5_4" + expected_capacity = _owner_fluxonkv_base_config(tag="expected_capacity") + expected_capacity["contribute_to_cluster_pool_size"]["dram"] = 137438953472 + expected_capacity["test_spec_config"] = { + "owner_local_reserve_soft_wait_timeout_ms": 10, + "owner_local_reserve_hard_timeout_ms": 10_000, + "owner_local_reserve_expected_capacity": { + "value_len": 4_718_592, + "payload_capacity_bytes": 109_951_162_777, + }, + } + config = FluxonKvClientConfig(expected_capacity) + loaded = yaml.safe_load(config.to_fluxon_kv_client_config_yaml_str()) + assert loaded["test_spec_config"]["owner_local_reserve_soft_wait_timeout_ms"] == 10 + assert loaded["test_spec_config"]["owner_local_reserve_hard_timeout_ms"] == 10_000 + assert loaded["test_spec_config"]["owner_local_reserve_expected_capacity"] == { + "value_len": 4_718_592, + "payload_capacity_bytes": 109_951_162_777, + } + + invalid_reserve_timeout = copy.deepcopy(expected_capacity) + invalid_reserve_timeout["test_spec_config"][ + "owner_local_reserve_hard_timeout_ms" + ] = 10 + try: + FluxonKvClientConfig(invalid_reserve_timeout) + print( + "❌ FAIL: test_fluxonkv_test_spec_config - local-reserve hard timeout should exceed soft timeout" + ) + return + except ValueError: + pass + + invalid_expected_capacity = copy.deepcopy(expected_capacity) + invalid_expected_capacity["test_spec_config"][ + "owner_local_reserve_expected_capacity" + ]["value_len"] = 0 + try: + FluxonKvClientConfig(invalid_expected_capacity) + print( + "❌ FAIL: test_fluxonkv_test_spec_config - expected-capacity value_len=0 should be rejected" + ) + return + except ValueError: + pass + implicit_transport = copy.deepcopy(base) implicit_transport["test_spec_config"] = { "disable_observability": True, diff --git a/fluxon_rs/fluxon_commu/src/facade/p2p.rs b/fluxon_rs/fluxon_commu/src/facade/p2p.rs index 8bcc169..1d4306c 100644 --- a/fluxon_rs/fluxon_commu/src/facade/p2p.rs +++ b/fluxon_rs/fluxon_commu/src/facade/p2p.rs @@ -1297,6 +1297,8 @@ pub mod rpc { timeout: Option, transport_policy: RpcTransportPolicy, ) -> P2PResult> { + validate_explicit_rpc_timeout(timeout)?; + let mut failed_count = 0; let shutdown_poller = p2p.module_view().register_shutdown_poller(); @@ -1371,6 +1373,8 @@ pub mod rpc { timeout: Option, transport_policy: RpcTransportPolicy, ) -> P2PResult> { + validate_explicit_rpc_timeout(timeout)?; + regist_rpc_send::(p2p); { @@ -1381,31 +1385,12 @@ pub mod rpc { .await?; } - let timeout_duration = match timeout { - Some(duration) => { - let min_duration = Duration::from_secs(MIN_EXPLICIT_RPC_TIMEOUT_SECS); - if duration < min_duration { - return Err(P2pError::InvalidRpcTimeout { - timeout_ms: duration.as_secs() * 1_000 - + u64::from(duration.subsec_millis()), - min_timeout_ms: MIN_EXPLICIT_RPC_TIMEOUT_SECS * 1_000, - reason: format!( - "Explicit RPC timeout below {}s is forbidden.", - MIN_EXPLICIT_RPC_TIMEOUT_SECS - ), - }); - } - Some(duration) - } - None => None, - }; - let wire_encode_started_at = Instant::now(); let msg_id = req.msg_id(); let wire_body = req.into_wire_body()?; let wire_encode_us = duration_to_i64_us(wire_encode_started_at.elapsed()); let raw_output = p2p - .call_raw_observed(node, msg_id, wire_body, timeout_duration, transport_policy) + .call_raw_observed(node, msg_id, wire_body, timeout, transport_policy) .await?; let response_local_observe = raw_output.message.local_observe; let resp_decode_started_at = Instant::now(); diff --git a/fluxon_rs/fluxon_commu_contract/src/p2p.rs b/fluxon_rs/fluxon_commu_contract/src/p2p.rs index 673692b..c548ee4 100644 --- a/fluxon_rs/fluxon_commu_contract/src/p2p.rs +++ b/fluxon_rs/fluxon_commu_contract/src/p2p.rs @@ -9,15 +9,16 @@ pub mod surface; pub mod wire; pub use rpc::{ - MIN_EXPLICIT_RPC_TIMEOUT_SECS, MsgPack, MsgPackSerializePart, RPCReq, RpcCallObserveTrace, - RpcCallObservedOutput, USER_RPC_OBSERVE_TRACE_RAW_BYTES_INDEX, + MIN_EXPLICIT_RPC_TIMEOUT_MS, MIN_EXPLICIT_RPC_TIMEOUT_SECS, MsgPack, MsgPackSerializePart, + RPCReq, RpcCallObserveTrace, RpcCallObservedOutput, USER_RPC_OBSERVE_TRACE_RAW_BYTES_INDEX, USER_RPC_OWNER1_OBSERVE_TRACE_RAW_BYTES_INDEX, USER_RPC_REQ_MSG_ID, USER_RPC_REQUEST_OWNER1_OBSERVE_TRACE_RAW_BYTES_INDEX, USER_RPC_RESP_MSG_ID, UserRpcBytesAsyncHandler, UserRpcBytesError, UserRpcBytesFuture, UserRpcBytesHandler, UserRpcObserveTrace, UserRpcOwner1ObserveTrace, UserRpcTransportPathKind, current_cross_process_monotonic_us, decode_user_rpc_observe_trace, decode_user_rpc_owner1_observe_trace, encode_user_rpc_observe_trace, - encode_user_rpc_owner1_observe_trace, + encode_user_rpc_owner1_observe_trace, validate_explicit_rpc_timeout, + validate_explicit_rpc_timeout_ms, }; pub use surface::*; pub use wire::*; diff --git a/fluxon_rs/fluxon_commu_contract/src/p2p/rpc.rs b/fluxon_rs/fluxon_commu_contract/src/p2p/rpc.rs index b65ccd9..144034d 100644 --- a/fluxon_rs/fluxon_commu_contract/src/p2p/rpc.rs +++ b/fluxon_rs/fluxon_commu_contract/src/p2p/rpc.rs @@ -17,14 +17,66 @@ use prost::bytes::Bytes as ProstBytes; use std::fmt::Debug; use std::future::Future; use std::pin::Pin; +use std::time::Duration; pub const MIN_EXPLICIT_RPC_TIMEOUT_SECS: u64 = 10; +pub const MIN_EXPLICIT_RPC_TIMEOUT_MS: u64 = MIN_EXPLICIT_RPC_TIMEOUT_SECS * 1_000; pub const USER_RPC_REQ_MSG_ID: u32 = 7001; pub const USER_RPC_RESP_MSG_ID: u32 = 7002; pub const USER_RPC_REQUEST_OWNER1_OBSERVE_TRACE_RAW_BYTES_INDEX: usize = 1; pub const USER_RPC_OBSERVE_TRACE_RAW_BYTES_INDEX: usize = 1; pub const USER_RPC_OWNER1_OBSERVE_TRACE_RAW_BYTES_INDEX: usize = 2; +pub fn validate_explicit_rpc_timeout(timeout: Option) -> P2PResult<()> { + let Some(timeout) = timeout else { + return Ok(()); + }; + if timeout < Duration::from_millis(MIN_EXPLICIT_RPC_TIMEOUT_MS) { + return Err(P2pError::InvalidRpcTimeout { + timeout_ms: timeout.as_millis().min(u128::from(u64::MAX)) as u64, + min_timeout_ms: MIN_EXPLICIT_RPC_TIMEOUT_MS, + reason: format!( + "Explicit RPC timeout below {}s is forbidden.", + MIN_EXPLICIT_RPC_TIMEOUT_SECS + ), + }); + } + Ok(()) +} + +pub fn validate_explicit_rpc_timeout_ms(timeout_ms: u64) -> P2PResult<()> { + validate_explicit_rpc_timeout(Some(Duration::from_millis(timeout_ms))) +} + +#[cfg(test)] +mod explicit_rpc_timeout_tests { + use super::*; + + #[test] + fn accepts_default_and_minimum_explicit_timeout() { + assert!(validate_explicit_rpc_timeout(None).is_ok()); + assert!(validate_explicit_rpc_timeout_ms(MIN_EXPLICIT_RPC_TIMEOUT_MS).is_ok()); + } + + #[test] + fn rejects_subminimum_timeout_with_typed_error() { + let timeout_ms = MIN_EXPLICIT_RPC_TIMEOUT_MS - 1; + let err = validate_explicit_rpc_timeout_ms(timeout_ms).unwrap_err(); + assert_eq!(err.code(), 617); + match err { + P2pError::InvalidRpcTimeout { + timeout_ms: actual_timeout_ms, + min_timeout_ms, + .. + } => { + assert_eq!(actual_timeout_ms, timeout_ms); + assert_eq!(min_timeout_ms, MIN_EXPLICIT_RPC_TIMEOUT_MS); + } + other => panic!("expected InvalidRpcTimeout, got {other:?}"), + } + } +} + #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)] pub enum UserRpcTransportPathKind { #[default] diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/delete.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/delete.rs index 63db807..946f033 100755 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/delete.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/delete.rs @@ -89,8 +89,19 @@ async fn apply_delete_client_kv_meta_cache_item( let client_api = view.client_kv_api(); let client_inner = client_api.inner(); - if let Some((_removed_key, cached_info)) = - client_inner + let cached_info = { + let controls = client_inner.owner_key_control.lock(); + if controls + .get(&delete_item.key) + .is_some_and(|state| state.reclaim.is_some()) + { + tracing::debug!( + "skip legacy local-index delete while owner reclaim fence is active: key={}", + delete_item.key + ); + return; + } + let cached_info = client_inner .get_cached_info .remove_if(&delete_item.key, |_, v| { let res = if v.put_time_ms == delete_item.put_time_ms { @@ -112,14 +123,25 @@ async fn apply_delete_client_kv_meta_cache_item( } res }) - { + .map(|(_, cached_info)| cached_info); + let _ = client_inner + .local_snapshot_info + .remove_if(&delete_item.key, |_, snapshot| { + if snapshot.put_time_ms == delete_item.put_time_ms { + snapshot.put_version <= delete_item.put_version + } else { + snapshot.put_time_ms <= delete_item.put_time_ms + } + }); + cached_info + }; + if let Some(cached_info) = cached_info { + client_inner.owner_hot_invalidate_version( + &delete_item.key, + (cached_info.put_time_ms, cached_info.put_version), + ); client_inner.release_local_reserve_route_for_memory_info(cached_info.mem_holder.as_ref()); } - let _ = client_inner.remove_local_snapshot_if( - &delete_item.key, - delete_item.put_time_ms, - delete_item.put_version, - ); if let Err(err) = client_inner .external_invalidate_delete diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs index a10e354..28ba872 100755 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs @@ -1,11 +1,12 @@ use crate::client_kv_api::ClientKvApi; use crate::client_kv_api::msg_pack::{ - ExternalBatchGetCancelReq, ExternalBatchGetCancelResp, ExternalBatchGetItemResp, - ExternalBatchGetReq, ExternalBatchGetResp, ExternalBatchGetStartReq, ExternalBatchGetStartResp, - ExternalBatchGetTransferReq, ExternalBatchGetTransferResp, ExternalBatchIsExistReq, - ExternalBatchIsExistResp, ExternalBatchPutCommitItemResp, ExternalBatchPutCommitReq, - ExternalBatchPutCommitResp, ExternalBatchPutStartItemResp, ExternalBatchPutStartReq, - ExternalBatchPutStartResp, ExternalBatchPutTransferEndItemResp, ExternalBatchPutTransferEndReq, + ExternalBatchGetCancelPlan, ExternalBatchGetCancelReq, ExternalBatchGetCancelResp, + ExternalBatchGetItemResp, ExternalBatchGetReq, ExternalBatchGetResp, ExternalBatchGetStartReq, + ExternalBatchGetStartResp, ExternalBatchGetStartTransferPlan, ExternalBatchGetTransferReq, + ExternalBatchGetTransferResp, ExternalBatchIsExistReq, ExternalBatchIsExistResp, + ExternalBatchPutCommitItemResp, ExternalBatchPutCommitReq, ExternalBatchPutCommitResp, + ExternalBatchPutStartItemResp, ExternalBatchPutStartReq, ExternalBatchPutStartResp, + ExternalBatchPutTransferEndItemResp, ExternalBatchPutTransferEndReq, ExternalBatchPutTransferEndResp, ExternalDeleteReq, ExternalDeleteResp, ExternalGetReq, ExternalGetResp, ExternalIsExistReq, ExternalIsExistResp, ExternalObservabilitySnapshotReq, ExternalObservabilitySnapshotResp, ExternalPutCommitReq, ExternalPutCommitResp, @@ -15,8 +16,8 @@ use crate::client_kv_api::msg_pack::{ use crate::client_kv_api::{ self, ExternalGetStartDedupKey, ExternalGetStartEntry, ExternalGetStartOwnerItem, ExternalGetStartPrefixResult, ExternalGetStartSharedItemResult, ExternalGetStartSharedOp, - ExternalGetStartSharedPhase, ExternalGetStartTransferOutput, ExternalHoldingGetInfo, - ExternalPendingPutCtx, ReplicaTaskTarget, + ExternalGetStartSharedPhase, ExternalGetStartTransferOutput, ExternalPendingPutCtx, + ReplicaTaskTarget, }; use crate::client_seg_pool::{ResolveSideTransferLaneReq, parse_side_transfer_worker_lane_idx}; use crate::cluster_manager::NodeIDString; @@ -24,11 +25,12 @@ use crate::cluster_manager::{ META_KEY_SHARED_STORAGE_NODE_ID, META_KEY_SHARED_STORAGE_NODE_START_TIME, }; use crate::master_kv_router::msg_pack::{ - BatchPutDoneItemReq, BatchPutRevokeItemReq, BatchPutStartItemReq, PutDoneCommittedSlot, + BatchGetStartItemResp, BatchGetStartResp, BatchPutDoneItemReq, BatchPutRevokeItemReq, + BatchPutStartItemReq, PutDoneCommittedSlot, build_put_atomic_group_assignments, }; use crate::memholder::MemholderManagerTrait; use crate::memholder::NodeHolderKey; -use crate::memholder::{ExternalMemHolderInfo, UserMemHolder, UserMemHolderExposeKind}; +use crate::memholder::{UserMemHolder, UserMemHolderExposeKind}; use crate::p2p::msg_pack::MsgPack; use crate::rpcresp_kvresult_convert::FromError; use crate::rpcresp_kvresult_convert::ToResult; @@ -47,6 +49,7 @@ fn duration_to_i64_us(duration: std::time::Duration) -> i64 { const SIDE_TRANSFER_OWNER_RPC_TIMEOUT_SECS: u64 = 30; const SIDE_TRANSFER_TARGET_RESOLVE_TIMEOUT_SECS: u64 = 10; +const GET_TARGET_NO_SPACE_RESERVE_SHRINK_RETRY_LIMIT: usize = 8; #[derive(Clone)] struct LocalCommittedCachePublish { @@ -159,7 +162,12 @@ async fn commit_external_local_first_pending( ) .await; inner.install_precommit_local_visible_memory_info(key, memory_info.clone()); - inner.promote_precommit_local_reserve_resident_slot_if_same(key, put_id, memory_info)?; + inner.promote_precommit_local_reserve_resident_slot_if_same( + key, + put_id, + memory_info, + ctx.atomic_group.as_ref(), + )?; Ok(PutDoneCommittedSlot { grant_id: slot_ref.grant_id, slot_index: slot_ref.slot_index, @@ -176,18 +184,22 @@ fn spawn_external_local_first_publish( put_id: crate::master_kv_router::put::PutIDForAKey, lease_id: Option, committed_slot: PutDoneCommittedSlot, + make_replica_task: bool, + preferred_sub_cluster: Option, + atomic_group: Option, ) { let view = inner.view.clone_view(); let spawn_view = view.clone(); spawn_view.spawn("external_local_first_route_publish", async move { let inner = view.client_kv_api().inner(); - match inner + let publish_ok = match inner .batch_put_done(vec![BatchPutDoneItemReq { key: key.clone(), put_id, lease_id, committed_slot: Some(committed_slot), publish_local_cache: false, + atomic_group, }]) .await { @@ -203,6 +215,9 @@ fn spawn_external_local_first_publish( put_id.1, err ); + false + } else { + true } } else { tracing::warn!( @@ -211,6 +226,7 @@ fn spawn_external_local_first_publish( put_id.0, put_id.1 ); + false } } Err(err) => { @@ -221,6 +237,21 @@ fn spawn_external_local_first_publish( put_id.1, err ); + false + } + }; + if publish_ok && make_replica_task { + if let Err(err) = inner + .make_replica_append_task(&key, put_id, preferred_sub_cluster, true) + .await + { + tracing::warn!( + "external local-first enqueue replica append failed: key={} put_id=({},{}) err={}", + key, + put_id.0, + put_id.1, + err + ); } } }); @@ -259,6 +290,41 @@ pub(crate) fn normalize_external_get_start_group_lens( } } +fn normalize_external_put_start_group_lens( + items_len: usize, + atomic_group_lens: Option>, +) -> KvResult> { + let group_lens = atomic_group_lens.unwrap_or_else(|| vec![1; items_len]); + if items_len != 0 && group_lens.is_empty() { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: "external_batch_put_start atomic_group_lens must be non-empty".to_string(), + })); + } + if group_lens.iter().any(|group_len| *group_len == 0) { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: "external_batch_put_start atomic_group_lens entries must be > 0".to_string(), + })); + } + let sum = group_lens + .iter() + .try_fold(0usize, |sum, group_len| sum.checked_add(*group_len)) + .ok_or_else(|| { + KvError::Api(ApiError::InvalidArgument { + detail: "external_batch_put_start atomic_group_lens sum overflowed usize" + .to_string(), + }) + })?; + if sum != items_len { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "external_batch_put_start atomic_group_lens must sum to items length: sum={} items={}", + sum, items_len + ), + })); + } + Ok(group_lens) +} + fn external_get_start_error_kind_from_code(error_code: u32, error_json: &str) -> Option { if error_code == OK || error_code == codes_api::API_KEY_NOT_FOUND { None @@ -308,6 +374,195 @@ pub(crate) fn compute_external_get_start_transfer_prefix( } } +fn collect_external_get_start_missing( + keys: &[String], + item_slots: &[Option], +) -> (Vec, Vec) { + assert_eq!( + keys.len(), + item_slots.len(), + "external get_start local snapshot length must match keys" + ); + keys.iter() + .zip(item_slots.iter()) + .enumerate() + .filter_map(|(idx, (key, item))| item.is_none().then(|| (idx, key.clone()))) + .unzip() +} + +fn collect_all_local_external_get_start_infos( + items: &[ExternalGetStartOwnerItem], +) -> Option>> { + items + .iter() + .map(|item| match item { + ExternalGetStartOwnerItem::Local { memory_info } => Some(memory_info.clone()), + ExternalGetStartOwnerItem::Started { .. } => None, + }) + .collect() +} + +fn collect_get_target_no_space_indices(items: &[BatchGetStartItemResp]) -> Vec { + items + .iter() + .enumerate() + .filter_map(|(idx, item)| (item.error_code == codes_api::API_NO_SPACE).then_some(idx)) + .collect() +} + +async fn batch_get_start_with_reserve_pressure_retry( + inner: &client_kv_api::ClientKvApiInner, + keys: &[String], +) -> KvResult { + let mut response = inner.batch_get_start(keys.to_vec()).await?; + if response.items.len() != keys.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external_batch_get_start response length mismatch: expected={} got={}", + keys.len(), + response.items.len() + ), + })); + } + + for attempt in 1..=GET_TARGET_NO_SPACE_RESERVE_SHRINK_RETRY_LIMIT { + let retry_indices = collect_get_target_no_space_indices(&response.items); + if retry_indices.is_empty() { + break; + } + let no_space_before = retry_indices.len(); + if !crate::client_kv_api::local_reserve_rebalance::release_one_excess_reserve_grant_for_get_target_pressure(inner).await + { + break; + } + let retry_keys = retry_indices + .iter() + .map(|idx| keys[*idx].clone()) + .collect::>(); + let retry_response = inner.batch_get_start(retry_keys).await?; + if retry_response.items.len() != retry_indices.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external_batch_get_start NoSpace retry response length mismatch: expected={} got={} attempt={}", + retry_indices.len(), + retry_response.items.len(), + attempt + ), + })); + } + response.server_process_us = response + .server_process_us + .saturating_add(retry_response.server_process_us); + for (idx, item) in retry_indices + .into_iter() + .zip(retry_response.items.into_iter()) + { + response.items[idx] = item; + } + let no_space_after = collect_get_target_no_space_indices(&response.items).len(); + tracing::info!( + "external_batch_get_start retried local Get-target NoSpace after reserve shrink: attempt={} no_space_before={} no_space_after={}", + attempt, + no_space_before, + no_space_after + ); + } + Ok(response) +} + +#[cfg(test)] +mod external_get_start_batch_tests { + use super::{ + collect_external_get_start_missing, collect_get_target_no_space_indices, + compute_external_get_start_raw_prefix, compute_external_get_start_transfer_prefix, + normalize_external_put_start_group_lens, + }; + use crate::master_kv_router::msg_pack::BatchGetStartItemResp; + use crate::rpcresp_kvresult_convert::msg_and_error::{OK, codes_api}; + + #[test] + fn all_local_batch_has_no_master_fallback_and_keeps_full_atomic_prefix() { + let keys = vec!["a".to_string(), "b".to_string(), "c".to_string()]; + let local_slots = vec![Some(1_u8), Some(2), Some(3)]; + + let (missing_indices, missing_keys) = + collect_external_get_start_missing(&keys, &local_slots); + assert!(missing_indices.is_empty()); + assert!(missing_keys.is_empty()); + + let item_codes = vec![(OK, String::new()); keys.len()]; + let (raw_prefix, first_miss, first_error) = + compute_external_get_start_raw_prefix(&item_codes); + assert_eq!(raw_prefix, keys.len()); + assert_eq!(first_miss, None); + assert_eq!(first_error, None); + assert_eq!( + compute_external_get_start_transfer_prefix(raw_prefix, &[1, 2], true), + keys.len() + ); + } + + #[test] + fn mixed_batch_falls_back_only_for_missing_keys_and_preserves_group_boundary() { + let keys = vec![ + "a".to_string(), + "b".to_string(), + "c".to_string(), + "d".to_string(), + ]; + let local_slots = vec![Some(1_u8), Some(2), None, Some(4)]; + + let (missing_indices, missing_keys) = + collect_external_get_start_missing(&keys, &local_slots); + assert_eq!(missing_indices, vec![2]); + assert_eq!(missing_keys, vec!["c"]); + + let item_codes = vec![ + (OK, String::new()), + (OK, String::new()), + (codes_api::API_KEY_NOT_FOUND, String::new()), + (OK, String::new()), + ]; + let (raw_prefix, first_miss, first_error) = + compute_external_get_start_raw_prefix(&item_codes); + assert_eq!(raw_prefix, 2); + assert_eq!(first_miss, Some(2)); + assert_eq!(first_error, None); + assert_eq!( + compute_external_get_start_transfer_prefix(raw_prefix, &[2, 2], true), + 2 + ); + assert_eq!( + compute_external_get_start_transfer_prefix(raw_prefix, &[2, 2], false), + 0 + ); + } + + #[test] + fn put_groups_default_per_item_and_reject_malformed_partitions() { + assert_eq!( + normalize_external_put_start_group_lens(3, None).unwrap(), + vec![1, 1, 1] + ); + assert_eq!( + normalize_external_put_start_group_lens(3, Some(vec![2, 1])).unwrap(), + vec![2, 1] + ); + assert!(normalize_external_put_start_group_lens(3, Some(vec![1, 1])).is_err()); + assert!(normalize_external_put_start_group_lens(3, Some(vec![1, 0, 2])).is_err()); + } + + #[test] + fn get_target_pressure_retry_selects_only_no_space_items() { + let mut items = vec![BatchGetStartItemResp::default(); 4]; + items[0].error_code = OK; + items[1].error_code = codes_api::API_NO_SPACE; + items[2].error_code = codes_api::API_KEY_NOT_FOUND; + items[3].error_code = codes_api::API_NO_SPACE; + assert_eq!(collect_get_target_no_space_indices(&items), vec![1, 3]); + } +} + async fn finish_external_get_start_transfer( view: crate::client_kv_api::ClientKvApiView, transfer_items: Vec, @@ -577,31 +832,43 @@ async fn prepare_external_get_start_shared_op( Vec, Vec, )> { - let mut item_slots: Vec> = - (0..req.keys.len()).map(|_| None).collect(); - let mut missing_indices = Vec::new(); - let mut missing_keys = Vec::new(); - - for (idx, key) in req.keys.iter().enumerate() { - if let Some(memory_info) = inner.local_visible_mem_holder(key) { - item_slots[idx] = Some(ExternalGetStartOwnerItem::Local { memory_info }); - } else { - missing_indices.push(idx); - missing_keys.push(key.clone()); - } + let local_memory_infos = inner.local_visible_mem_holders(&req.keys); + if local_memory_infos.iter().all(Option::is_some) { + let key_count = req.keys.len(); + let transfer_items = local_memory_infos + .into_iter() + .map(|memory_info| ExternalGetStartOwnerItem::Local { + memory_info: memory_info.expect("all local-visible entries were checked"), + }) + .collect(); + tracing::debug!( + key_count, + req_node_id = %req.req_node_id, + "external_batch_get_start used all-local-visible batch fast path" + ); + return Ok(( + ExternalGetStartPrefixResult { + raw_prefix_hit_len: key_count, + transferable_len: key_count, + first_miss_index: None, + first_error_kind: None, + }, + req.keys.clone(), + transfer_items, + )); } + let mut item_slots: Vec> = local_memory_infos + .into_iter() + .map(|memory_info| { + memory_info.map(|memory_info| ExternalGetStartOwnerItem::Local { memory_info }) + }) + .collect(); + let (missing_indices, missing_keys) = + collect_external_get_start_missing(&req.keys, &item_slots); + if !missing_keys.is_empty() { - let start_resp = inner.batch_get_start(missing_keys.clone()).await?; - if start_resp.items.len() != missing_indices.len() { - return Err(KvError::Api(ApiError::Unknown { - detail: format!( - "external_batch_get_start response length mismatch: expected={} got={}", - missing_indices.len(), - start_resp.items.len() - ), - })); - } + let start_resp = batch_get_start_with_reserve_pressure_retry(inner, &missing_keys).await?; for ((idx, key), item) in missing_indices .into_iter() .zip(missing_keys.into_iter()) @@ -1037,24 +1304,8 @@ impl HandlerForExternalClient for ClientKvApi { }); } }; - let memory_info = memholder.memory_info(); - // Build holding info to record that this external client holds the memholder - let client_holding_info = ExternalHoldingGetInfo { - key: req.key.clone(), - req_node_id: req.req_node_id.clone(), - memory_info, - }; - - // Insert/update holding via owned manager - inner.external_get_holding.insert( - NodeHolderKey::new(req.req_node_id.clone(), memholder.holder_id()), - client_holding_info, - ); - let external_memholder_info = ExternalMemHolderInfo { - offset: memholder.get_offset(), - len: memholder.get_length() as u32, - holder_id: memholder.holder_id(), - }; + let external_memholder_info = + inner.install_external_get_holding(&req.req_node_id, memholder.memory_info()); Ok(ExternalGetResp { external_memholder_info: Some(external_memholder_info), error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, @@ -1075,23 +1326,14 @@ impl HandlerForExternalClient for ClientKvApi { for item_result in batch_results { match item_result { Ok(Some((memholder, _))) => { - let memory_info = memholder.memory_info(); - inner.external_get_holding.insert( - NodeHolderKey::new(req.req_node_id.clone(), memholder.holder_id()), - ExternalHoldingGetInfo { - key: memory_info.key.clone(), - req_node_id: req.req_node_id.clone(), - memory_info, - }, + let external_memholder_info = inner.install_external_get_holding( + &req.req_node_id, + memholder.memory_info(), ); items.push(ExternalBatchGetItemResp { error_code: OK, error_json: String::new(), - external_memholder_info: Some(ExternalMemHolderInfo { - offset: memholder.get_offset(), - len: memholder.get_length() as u32, - holder_id: memholder.holder_id(), - }), + external_memholder_info: Some(external_memholder_info), }); } Ok(None) => items.push(ExternalBatchGetItemResp { @@ -1156,6 +1398,18 @@ impl HandlerForExternalClient for ClientKvApi { if is_creator { match prepare_external_get_start_shared_op(inner, &req, &group_lens).await { Ok((prefix, transfer_keys, transfer_items)) => { + let inline_memory_infos = (transfer_items.len() == req.keys.len()) + .then(|| collect_all_local_external_get_start_infos(&transfer_items)) + .flatten(); + let inline_local = inline_memory_infos.is_some(); + if let Some(memory_infos) = inline_memory_infos { + shared_op + .inline_local_memory_infos + .set(memory_infos) + .unwrap_or_else(|_| { + panic!("external get_start inline plan initialized twice") + }); + } { let mut state = shared_op.state.lock(); state.phase = ExternalGetStartSharedPhase::Running { @@ -1165,23 +1419,25 @@ impl HandlerForExternalClient for ClientKvApi { } shared_op.notify.notify_waiters(); - let transfer_shared_op = shared_op.clone(); - let transfer_concurrency = shared_op.transfer_concurrency; - let spawn_view = inner.view.clone_view(); - let transfer_view = spawn_view.clone(); - spawn_view.spawn("external_get_start_transfer", async move { - let transfer_result = finish_external_get_start_transfer( - transfer_view, - transfer_items, - transfer_concurrency, - ) - .await; - publish_external_get_start_ready( - &transfer_shared_op, - transfer_keys, - transfer_result, - ); - }); + if !inline_local { + let transfer_shared_op = shared_op.clone(); + let transfer_concurrency = shared_op.transfer_concurrency; + let spawn_view = inner.view.clone_view(); + let transfer_view = spawn_view.clone(); + spawn_view.spawn("external_get_start_transfer", async move { + let transfer_result = finish_external_get_start_transfer( + transfer_view, + transfer_items, + transfer_concurrency, + ) + .await; + publish_external_get_start_ready( + &transfer_shared_op, + transfer_keys, + transfer_result, + ); + }); + } } Err(err) => { publish_external_get_start_failed(&shared_op, &err); @@ -1201,19 +1457,41 @@ impl HandlerForExternalClient for ClientKvApi { let handle = inner .next_external_get_start_handle .fetch_add(1, Ordering::Relaxed); - inner.external_get_start_registry.insert( - handle, - Arc::new(ExternalGetStartEntry { - req_node_id: req.req_node_id.clone(), - shared_op, - }), - ); + let transfer_plan = if let Some(memory_infos) = shared_op.inline_local_memory_infos.get() { + assert_eq!( + memory_infos.len(), + req.keys.len(), + "inline local get_start plan must cover the full request" + ); + let items = memory_infos + .iter() + .map(|memory_info| ExternalBatchGetItemResp { + error_code: OK, + error_json: String::new(), + external_memholder_info: Some( + inner.install_external_get_holding(&req.req_node_id, memory_info.clone()), + ), + }) + .collect(); + release_external_get_start_waiter(inner, &shared_op); + ExternalBatchGetStartTransferPlan::InlineLocal { items } + } else { + inner.external_get_start_registry.insert( + handle, + Arc::new(ExternalGetStartEntry { + req_node_id: req.req_node_id.clone(), + shared_op, + }), + ); + ExternalBatchGetStartTransferPlan::OwnerRpc + }; Ok(ExternalBatchGetStartResp { error_code: OK, error_json: String::new(), handle, raw_prefix_hit_len: prefix.raw_prefix_hit_len, + transfer_plan, }) } @@ -1258,26 +1536,14 @@ impl HandlerForExternalClient for ClientKvApi { for (key, item_result) in keys.iter().zip(shared_items.into_iter()) { match item_result { ExternalGetStartSharedItemResult::Hit { memholder } => { - let memory_info = memholder.memory_info(); - inner.external_get_holding.insert( - NodeHolderKey::new( - req.req_node_id.clone(), - memholder.holder_id(), - ), - ExternalHoldingGetInfo { - key: memory_info.key.clone(), - req_node_id: req.req_node_id.clone(), - memory_info, - }, + let external_memholder_info = inner.install_external_get_holding( + &req.req_node_id, + memholder.memory_info(), ); items.push(ExternalBatchGetItemResp { error_code: OK, error_json: String::new(), - external_memholder_info: Some(ExternalMemHolderInfo { - offset: memholder.get_offset(), - len: memholder.get_length() as u32, - holder_id: memholder.holder_id(), - }), + external_memholder_info: Some(external_memholder_info), }); } ExternalGetStartSharedItemResult::Miss => { @@ -1322,16 +1588,29 @@ impl HandlerForExternalClient for ClientKvApi { let inner = self.inner(); self.validate_requester_owner_status_updated(req.started_time)?; - if let Some((_handle, entry)) = inner.external_get_start_registry.remove(&req.handle) { - if entry.req_node_id != req.req_node_id { - tracing::warn!( - "external_batch_get_cancel req_node_id mismatch: handle={} expected={} got={}", - req.handle, - entry.req_node_id, - req.req_node_id - ); + match req.transfer_plan { + ExternalBatchGetCancelPlan::OwnerRpc => { + if let Some((_handle, entry)) = + inner.external_get_start_registry.remove(&req.handle) + { + if entry.req_node_id != req.req_node_id { + tracing::warn!( + "external_batch_get_cancel req_node_id mismatch: handle={} expected={} got={}", + req.handle, + entry.req_node_id, + req.req_node_id + ); + } + release_external_get_start_waiter(inner, &entry.shared_op); + } + } + ExternalBatchGetCancelPlan::InlineLocal { holder_ids } => { + for holder_id in holder_ids { + let _ = inner + .external_get_holding + .remove(&NodeHolderKey::new(req.req_node_id.clone(), holder_id)); + } } - release_external_get_start_waiter(inner, &entry.shared_op); } Ok(ExternalBatchGetCancelResp { error_code: OK, @@ -1429,6 +1708,7 @@ impl HandlerForExternalClient for ClientKvApi { replica_target, local_reserve_slot: None, local_reserve_slot_size: None, + atomic_group: None, }, ); if !is_local_target { @@ -1489,6 +1769,11 @@ impl HandlerForExternalClient for ClientKvApi { self.validate_requester_owner_status_updated(req.started_time)?; + let atomic_group_lens = normalize_external_put_start_group_lens( + req.items.len(), + req.atomic_group_lens.clone(), + )?; + let Some(first_item) = req.items.first() else { return Ok(ExternalBatchPutStartResp { items: Vec::new(), @@ -1537,9 +1822,28 @@ impl HandlerForExternalClient for ClientKvApi { } }; let self_node_id = inner.view.cluster_manager().get_self_info().id.clone(); + let put_ids = req + .items + .iter() + .map(|_| inner.next_external_local_first_put_id()) + .collect::>(); + let keys_and_put_ids = req + .items + .iter() + .map(|item| item.key.clone()) + .zip(put_ids.iter().copied()) + .collect::>(); + let atomic_groups = + build_put_atomic_group_assignments(&keys_and_put_ids, &atomic_group_lens) + .map_err(|detail| KvError::Api(ApiError::InvalidArgument { detail }))?; let mut items = Vec::with_capacity(req.items.len()); - for (req_item, slot_ref) in req.items.into_iter().zip(slot_lease.slots.into_iter()) { - let put_id = inner.next_external_local_first_put_id(); + for (idx, (req_item, slot_ref)) in req + .items + .into_iter() + .zip(slot_lease.slots.into_iter()) + .enumerate() + { + let put_id = put_ids[idx]; let src_offset = slot_ref.ptr.saturating_sub(slot_ref.base_addr); inner.external_pending_puts.insert( (req_item.key.clone(), put_id.0, put_id.1), @@ -1554,6 +1858,7 @@ impl HandlerForExternalClient for ClientKvApi { replica_target: None, local_reserve_slot: Some(slot_ref.clone()), local_reserve_slot_size: Some(slot_lease.slot_size), + atomic_group: atomic_groups[idx].clone(), }, ); tracing::debug!( @@ -1891,6 +2196,9 @@ impl HandlerForExternalClient for ClientKvApi { put_id, item.lease_id, committed_slot, + ctx.make_replica_task, + ctx.preferred_sub_cluster.clone(), + ctx.atomic_group.clone(), ); results[idx] = Some(ExternalBatchPutTransferEndItemResp { error_code: OK, @@ -2024,6 +2332,7 @@ impl HandlerForExternalClient for ClientKvApi { lease_id: pending.lease_id, committed_slot: None, publish_local_cache: true, + atomic_group: None, }) .collect(), ) @@ -2360,6 +2669,9 @@ impl HandlerForExternalClient for ClientKvApi { put_id, item.lease_id, committed_slot, + ctx.make_replica_task, + ctx.preferred_sub_cluster.clone(), + ctx.atomic_group.clone(), ); results[idx] = Some(ExternalBatchPutCommitItemResp { error_code: OK, @@ -2483,6 +2795,7 @@ impl HandlerForExternalClient for ClientKvApi { lease_id: pending.lease_id, committed_slot: None, publish_local_cache: true, + atomic_group: None, }) .collect(), ) diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs index 88cafa3..363c443 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs @@ -1,4 +1,4 @@ -use super::{ClientKvApiInner, GetCachedInfo, KvMetrics}; +use super::{ClientKvApiInner, KvMetrics}; use crate::cluster_manager::app_logic_ext::ClusterManagerAppLogicExt; use crate::memholder::{MemoryInfo, UserMemHolder, UserMemHolderExposeKind}; // no StageScope; timestamps-based metrics only @@ -266,16 +266,17 @@ impl ClientKvApiInner { peer_is_src_or_target: pending.peer_is_remote, }; if done_item.allocation_mode != GetAllocationMode::Temporary { - self.get_cached_info.insert( - pending.key.clone(), - GetCachedInfo { - put_time_ms: pending.start_item.put_id.0, - put_version: pending.start_item.put_id.1, - mem_holder: memory_info.clone(), - }, - ); - self.remember_local_snapshot(&pending.key, pending.start_item.put_id); - metrics.observe_cache_value_size(&client_id, node_role.as_str(), data_len as u64); + if self.install_get_cached_info_if_unfenced( + &pending.key, + pending.start_item.put_id, + memory_info.clone(), + ) { + metrics.observe_cache_value_size( + &client_id, + node_role.as_str(), + data_len as u64, + ); + } } let user_mem_holder = Arc::new(UserMemHolder::new( memory_info, @@ -549,16 +550,17 @@ impl ClientKvApiInner { peer_is_src_or_target: pending.peer_is_remote, }; if done_item.allocation_mode != GetAllocationMode::Temporary { - self.get_cached_info.insert( - pending.key.clone(), - GetCachedInfo { - put_time_ms: pending.start_item.put_id.0, - put_version: pending.start_item.put_id.1, - mem_holder: memory_info.clone(), - }, - ); - self.remember_local_snapshot(&pending.key, pending.start_item.put_id); - metrics.observe_cache_value_size(&client_id, node_role.as_str(), data_len as u64); + if self.install_get_cached_info_if_unfenced( + &pending.key, + pending.start_item.put_id, + memory_info.clone(), + ) { + metrics.observe_cache_value_size( + &client_id, + node_role.as_str(), + data_len as u64, + ); + } } let user_mem_holder = Arc::new(UserMemHolder::new( memory_info, @@ -933,16 +935,9 @@ impl ClientKvApiInner { }; if done_resp.allocation_mode != GetAllocationMode::Temporary { - self.get_cached_info.insert( - key.to_string(), - GetCachedInfo { - put_time_ms: put_id.0, - put_version: put_id.1, - mem_holder: memory_info.clone(), - }, - ); - self.remember_local_snapshot(key, put_id); - metrics.observe_cache_value_size(&client_id, node_role.as_str(), data_len as u64); + if self.install_get_cached_info_if_unfenced(key, put_id, memory_info.clone()) { + metrics.observe_cache_value_size(&client_id, node_role.as_str(), data_len as u64); + } } let user_mem_holder = Arc::new(UserMemHolder::new( memory_info, diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/local_reserve_rebalance.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/local_reserve_rebalance.rs index 016f735..cbe5467 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/local_reserve_rebalance.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/local_reserve_rebalance.rs @@ -2,6 +2,7 @@ use super::{ ClientKvApiInner, ClientKvApiView, OwnerLocalReserveClassState, OwnerLocalReservePoolState, }; use crate::OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES; +use crate::master_kv_router::msg_pack::ReserveLocalGrantOutcome; use limit_thirdparty::tokio; use std::time::{Duration, Instant}; @@ -9,56 +10,95 @@ const OWNER_LOCAL_RESERVE_REBALANCE_INTERVAL: Duration = Duration::from_millis(2 const OWNER_LOCAL_RESERVE_SHRINK_IDLE_COOLDOWN: Duration = Duration::from_secs(5); const OWNER_LOCAL_RESERVE_SHRINK_GROW_COOLDOWN: Duration = Duration::from_secs(1); const OWNER_LOCAL_RESERVE_DEFAULT_SOFT_WAIT_TIMEOUT: Duration = Duration::from_millis(10); -const OWNER_LOCAL_RESERVE_DEFAULT_HARD_TIMEOUT: Duration = Duration::from_secs(1); -const OWNER_LOCAL_RESERVE_GROW_FACTOR_NUM: usize = 2; +const OWNER_LOCAL_RESERVE_DEFAULT_HARD_TIMEOUT: Duration = Duration::from_secs(10); const OWNER_LOCAL_RESERVE_MIN_GRANTS_PER_CLASS: usize = 0; +const OWNER_LOCAL_RESERVE_REPORT_INTERVAL: Duration = Duration::from_secs(30); +const OWNER_LOCAL_RESERVE_FREE_SLOT_HEADROOM_GRANTS: usize = 4; #[derive(Debug, Clone, Copy)] -struct RebalanceClassSnapshot { +struct ExpectedCapacityLayout { + value_len: u64, + payload_capacity_bytes: u64, slot_size: u64, slots_per_grant: u32, - used_slots: usize, grant_count: usize, - pending_slot_demand: usize, } -fn owner_local_reserve_round_up_grants(bytes: u64) -> u64 { - let quantum = OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES; - if bytes == 0 { - return 0; - } - let rem = bytes % quantum; - if rem == 0 { - bytes - } else { - bytes.checked_add(quantum - rem).unwrap_or(u64::MAX) - } -} - -fn owner_local_reserve_target_bytes( +#[derive(Debug, Clone, Copy)] +struct RebalanceClassSnapshot { slot_size: u64, + slots_per_grant: u32, used_slots: usize, + free_slots: usize, + grant_count: usize, pending_slot_demand: usize, -) -> u64 { - let required_slots = used_slots.saturating_add(pending_slot_demand); - let required_bytes = (required_slots as u64).saturating_mul(slot_size); - let doubled_used = (used_slots as u64) - .saturating_mul(slot_size) - .saturating_mul(OWNER_LOCAL_RESERVE_GROW_FACTOR_NUM as u64); - required_bytes.max(doubled_used) + expected_grant_count: usize, } fn owner_local_reserve_target_grant_count( - slot_size: u64, + slots_per_grant: u32, used_slots: usize, pending_slot_demand: usize, + expected_grant_count: usize, ) -> usize { - let target_bytes = owner_local_reserve_target_bytes(slot_size, used_slots, pending_slot_demand); - let rounded = owner_local_reserve_round_up_grants(target_bytes); - if rounded == 0 { - return 0; - } - (rounded / OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES) as usize + assert!( + slots_per_grant > 0, + "local-reserve grant must contain slots" + ); + let required_slots = used_slots.saturating_add(pending_slot_demand); + let slots_per_grant = slots_per_grant as usize; + let demand_grants = + required_slots / slots_per_grant + usize::from(required_slots % slots_per_grant != 0); + demand_grants.max(expected_grant_count) +} + +fn owner_local_reserve_desired_free_slots(snapshot: RebalanceClassSnapshot) -> usize { + let configured_headroom = if snapshot.expected_grant_count == 0 { + 0 + } else { + (snapshot.slots_per_grant as usize) + .saturating_mul(OWNER_LOCAL_RESERVE_FREE_SLOT_HEADROOM_GRANTS) + }; + snapshot + .pending_slot_demand + .saturating_add(configured_headroom) +} + +fn configured_expected_capacity(inner: &ClientKvApiInner) -> Option { + let expected = inner + .test_spec_config + .owner_local_reserve_expected_capacity + .as_ref()?; + let slot_size = crate::owner_local_reserve_slot_size_bytes(expected.value_len) + .expect("owner local-reserve expected capacity must be config-validated"); + let slots_per_grant = crate::owner_local_reserve_slots_per_grant(slot_size) + .expect("validated local-reserve slot size must fit in a grant"); + let grant_count = usize::try_from( + crate::owner_local_reserve_expected_grant_count( + expected.value_len, + expected.payload_capacity_bytes, + ) + .expect("owner local-reserve expected capacity must be config-validated"), + ) + .expect("owner local-reserve expected grant count must fit usize"); + Some(ExpectedCapacityLayout { + value_len: expected.value_len, + payload_capacity_bytes: expected.payload_capacity_bytes, + slot_size, + slots_per_grant, + grant_count, + }) +} + +fn install_expected_capacity_class(inner: &ClientKvApiInner) -> Option { + let expected = configured_expected_capacity(inner)?; + let mut pool = inner.owner_local_reserve_pool.lock(); + let class_state = pool.classes.entry(expected.slot_size).or_insert_with(|| { + OwnerLocalReserveClassState::new(expected.slot_size, expected.slots_per_grant) + }); + assert_eq!(class_state.slots_per_grant, expected.slots_per_grant); + class_state.expected_grant_count = expected.grant_count; + Some(expected) } fn snapshot_rebalance_classes(pool: &OwnerLocalReservePoolState) -> Vec { @@ -68,8 +108,10 @@ fn snapshot_rebalance_classes(pool: &OwnerLocalReservePoolState) -> Vec (D } async fn try_refill_once(inner: &ClientKvApiInner, snapshot: RebalanceClassSnapshot) { - if snapshot.pending_slot_demand == 0 { - return; - } if snapshot.slot_size > OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES { tracing::error!( "owner local reserve refill rejected oversized slot_size={} quantum={} pending_slots={}", @@ -101,48 +140,103 @@ async fn try_refill_once(inner: &ClientKvApiInner, snapshot: RebalanceClassSnaps ); return; } + let desired_free_slots = owner_local_reserve_desired_free_slots(snapshot); let target_grants = owner_local_reserve_target_grant_count( - snapshot.slot_size, + snapshot.slots_per_grant, snapshot.used_slots, - snapshot.pending_slot_demand, + desired_free_slots, + snapshot.expected_grant_count, ); if snapshot.grant_count >= target_grants { return; } let additional_grants = target_grants - snapshot.grant_count; + let batch_started_at = Instant::now(); + let mut added_grants = 0usize; + let mut total_rpc_latency = Duration::ZERO; + let mut max_rpc_latency = Duration::ZERO; for _ in 0..additional_grants { - let grant = match inner.reserve_local_grant().await { - Ok(grant) => grant, + let missing_slots = desired_free_slots + .saturating_sub(snapshot.free_slots) + .max(1); + let required_free_slots = u32::try_from(missing_slots).unwrap_or(u32::MAX); + let reclaim_before_grow = snapshot.expected_grant_count != 0 + && snapshot.grant_count >= snapshot.expected_grant_count; + let rpc_started_at = Instant::now(); + let outcome = match inner + .reserve_local_grant(snapshot.slot_size, required_free_slots, reclaim_before_grow) + .await + { + Ok(outcome) => { + let rpc_latency = rpc_started_at.elapsed(); + total_rpc_latency = total_rpc_latency.saturating_add(rpc_latency); + max_rpc_latency = max_rpc_latency.max(rpc_latency); + outcome + } Err(err) => { + let rpc_latency = rpc_started_at.elapsed(); tracing::warn!( - "owner local reserve refill failed: slot_size={} pending_slots={} err={}", + "owner local reserve refill failed: slot_size={} pending_slots={} grants={} target_grants={} expected_grants={} added_grants={} rpc_latency_ms={} err={}", snapshot.slot_size, snapshot.pending_slot_demand, + snapshot.grant_count, + target_grants, + snapshot.expected_grant_count, + added_grants, + rpc_latency.as_millis(), err ); return; } }; - if grant.len != OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES { + let (grant_id, base_addr, addr, len) = match outcome { + ReserveLocalGrantOutcome::Granted { + grant_id, + node_id: _, + addr, + base_addr, + len, + } => (grant_id, base_addr, addr, len), + ReserveLocalGrantOutcome::Reclaimed { + slot_size, + reclaimed_slots, + } => { + assert_eq!(slot_size, snapshot.slot_size); + tracing::info!( + "owner local reserve reused reclaimed slots: slot_size={} reclaimed_slots={} pending_slots={}", + slot_size, + reclaimed_slots, + snapshot.pending_slot_demand + ); + inner + .owner_local_reserve_rebalance_notify() + .notify_waiters(); + return; + } + ReserveLocalGrantOutcome::None => { + unreachable!("reserve_local_grant filters empty successful outcomes") + } + }; + if len != OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES { tracing::warn!( "owner local reserve refill got unexpected grant size: requested={} got={}", OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES, - grant.len + len ); - if let Err(release_err) = inner.release_local_grant(grant.grant_id).await { + if let Err(release_err) = inner.release_local_grant(grant_id).await { tracing::warn!( "owner local reserve refill failed to release mismatched grant_id={} err={}", - grant.grant_id, + grant_id, release_err ); } return; } let detached_grant = super::OwnerLocalReserveGrantState::new( - grant.grant_id, - grant.base_addr, - grant.addr, - grant.len, + grant_id, + base_addr, + addr, + len, snapshot.slot_size, snapshot.slots_per_grant, ); @@ -154,60 +248,84 @@ async fn try_refill_once(inner: &ClientKvApiInner, snapshot: RebalanceClassSnaps class_state.last_grow_at = Some(Instant::now()); class_state.grants.push(detached_grant); } + added_grants += 1; inner .owner_local_reserve_rebalance_notify() .notify_waiters(); } + if added_grants != 0 { + let average_rpc_latency_ms = total_rpc_latency.as_secs_f64() * 1000.0 / added_grants as f64; + tracing::info!( + "owner local reserve refill batch completed: slot_size={} added_grants={} grants_after={} target_grants={} expected_grants={} pending_slots={} elapsed_ms={} rpc_avg_ms={:.3} rpc_max_ms={}", + snapshot.slot_size, + added_grants, + snapshot.grant_count.saturating_add(added_grants), + target_grants, + snapshot.expected_grant_count, + snapshot.pending_slot_demand, + batch_started_at.elapsed().as_millis(), + average_rpc_latency_ms, + max_rpc_latency.as_millis() + ); + } } -async fn try_shrink_once(inner: &ClientKvApiInner, snapshot: RebalanceClassSnapshot) { - let detached = { - let mut pool = inner.owner_local_reserve_pool.lock(); - let Some(class_state) = pool.classes.get_mut(&snapshot.slot_size) else { - return; - }; - if class_state.pending_slot_demand > 0 { - return; - } +fn detach_excess_fully_free_grant( + class_state: &mut OwnerLocalReserveClassState, + get_target_pressure: bool, +) -> Option<(usize, super::OwnerLocalReserveGrantState)> { + if !get_target_pressure { let grow_cooldown_ok = class_state .last_grow_at .map(|last_grow_at| last_grow_at.elapsed() >= OWNER_LOCAL_RESERVE_SHRINK_GROW_COOLDOWN) .unwrap_or(true); if !grow_cooldown_ok { - return; - } - let shrink_keep_grants = owner_local_reserve_target_grant_count( - class_state.slot_size, - class_state.used_slot_count(), - class_state.pending_slot_demand, - ) - .max(OWNER_LOCAL_RESERVE_MIN_GRANTS_PER_CLASS); - if class_state.grants.len() <= shrink_keep_grants { - return; + return None; } - let should_detach_tail = class_state + } + let shrink_keep_grants = owner_local_reserve_target_grant_count( + class_state.slots_per_grant, + class_state.used_slot_count(), + class_state.pending_slot_demand, + class_state.expected_grant_count, + ) + .max(OWNER_LOCAL_RESERVE_MIN_GRANTS_PER_CLASS); + if class_state.grants.len() <= shrink_keep_grants { + return None; + } + + let candidate_index = if get_target_pressure { + // A physical Get-target allocation can be blocked while reclaimed slots remain trapped in + // a detached 512-MiB reserve grant. Under explicit pressure, any fully-free excess grant is + // safe to return; restricting the actor to the tail would leave allocator space stranded. + class_state .grants - .last() - .map(|grant| { - grant.is_fully_free() - && grant - .fully_free_since - .map(|since| since.elapsed() >= OWNER_LOCAL_RESERVE_SHRINK_IDLE_COOLDOWN) - .unwrap_or(false) - }) - .unwrap_or(false); - if !should_detach_tail { + .iter() + .rposition(super::OwnerLocalReserveGrantState::is_fully_free) + } else { + let tail_index = class_state.grants.len().checked_sub(1)?; + class_state.grants.get(tail_index).and_then(|grant| { + (grant.is_fully_free() + && grant + .fully_free_since + .map(|since| since.elapsed() >= OWNER_LOCAL_RESERVE_SHRINK_IDLE_COOLDOWN) + .unwrap_or(false)) + .then_some(tail_index) + }) + }?; + Some((candidate_index, class_state.grants.remove(candidate_index))) +} + +async fn try_shrink_once(inner: &ClientKvApiInner, snapshot: RebalanceClassSnapshot) { + let detached = { + let mut pool = inner.owner_local_reserve_pool.lock(); + let Some(class_state) = pool.classes.get_mut(&snapshot.slot_size) else { return; - } - Some( - class_state - .grants - .pop() - .expect("tail grant must exist when shrinking local reserve"), - ) + }; + detach_excess_fully_free_grant(class_state, false) }; - let Some(grant) = detached else { + let Some((grant_index, grant)) = detached else { return; }; @@ -221,7 +339,223 @@ async fn try_shrink_once(inner: &ClientKvApiInner, snapshot: RebalanceClassSnaps let class_state = pool.classes.entry(snapshot.slot_size).or_insert_with(|| { OwnerLocalReserveClassState::new(snapshot.slot_size, snapshot.slots_per_grant) }); - class_state.grants.push(grant); + class_state + .grants + .insert(grant_index.min(class_state.grants.len()), grant); + } else { + tracing::info!( + "owner local reserve released excess grant: slot_size={} grant_id={} pending_slots={}", + snapshot.slot_size, + grant.grant_id, + snapshot.pending_slot_demand + ); + } +} + +/// Return one fully-free reserve grant immediately when an ordinary local Get-target allocation +/// reports physical NoSpace. This never shrinks below the configured/active reserve target and does +/// not evict a live slot; it only makes already-free physical capacity visible to the master +/// allocator without waiting for the periodic idle cooldown. +pub(crate) async fn release_one_excess_reserve_grant_for_get_target_pressure( + inner: &ClientKvApiInner, +) -> bool { + let detached = { + let mut pool = inner.owner_local_reserve_pool.lock(); + let mut detached = None; + for class_state in pool.classes.values_mut() { + if let Some((grant_index, grant)) = detach_excess_fully_free_grant(class_state, true) { + detached = Some(( + class_state.slot_size, + class_state.slots_per_grant, + class_state.pending_slot_demand, + grant_index, + grant, + )); + break; + } + } + detached + }; + let Some((slot_size, slots_per_grant, pending_slots, grant_index, grant)) = detached else { + return false; + }; + let grant_id = grant.grant_id; + + if let Err(err) = inner.release_local_grant(grant_id).await { + tracing::warn!( + "owner local reserve get-target pressure failed to release grant_id={} err={}", + grant_id, + err + ); + let mut pool = inner.owner_local_reserve_pool.lock(); + let class_state = pool + .classes + .entry(slot_size) + .or_insert_with(|| OwnerLocalReserveClassState::new(slot_size, slots_per_grant)); + class_state + .grants + .insert(grant_index.min(class_state.grants.len()), grant); + inner + .owner_local_reserve_rebalance_notify() + .notify_waiters(); + false + } else { + tracing::info!( + "owner local reserve released excess grant for get-target pressure: slot_size={} grant_id={} pending_slots={}", + slot_size, + grant_id, + pending_slots + ); + inner + .owner_local_reserve_rebalance_notify() + .notify_waiters(); + true + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::client_kv_api::OwnerLocalReserveGrantState; + + const SLOT_SIZE: u64 = 8 * 1024 * 1024; + + #[test] + fn target_grants_cover_used_and_pending_without_double_reserving() { + let slots_per_grant = crate::owner_local_reserve_slots_per_grant(SLOT_SIZE).unwrap(); + assert_eq!( + owner_local_reserve_target_grant_count(slots_per_grant, 128, 1, 0), + 3 + ); + assert_eq!( + owner_local_reserve_target_grant_count(slots_per_grant, 128, 0, 0), + 2 + ); + assert_eq!( + owner_local_reserve_target_grant_count(slots_per_grant, 0, 0, 0), + 0 + ); + } + + #[test] + fn exact_fit_target_accounts_for_unusable_grant_tail() { + const VALUE_LEN: u64 = 4_718_592; + const EXPECTED_PAYLOAD_BYTES: u64 = 109_951_162_777; + let slot_size = crate::owner_local_reserve_slot_size_bytes(VALUE_LEN).unwrap(); + let slots_per_grant = crate::owner_local_reserve_slots_per_grant(slot_size).unwrap(); + let expected_grants = + crate::owner_local_reserve_expected_grant_count(VALUE_LEN, EXPECTED_PAYLOAD_BYTES) + .unwrap(); + assert_eq!(slot_size, VALUE_LEN); + assert_eq!(slots_per_grant, 113); + assert_eq!(expected_grants, 207); + assert_eq!( + owner_local_reserve_target_grant_count(slots_per_grant, 0, 0, expected_grants as usize,), + 207 + ); + } + + #[test] + fn default_hard_timeout_covers_pressure_reclaim_transaction() { + assert_eq!( + OWNER_LOCAL_RESERVE_DEFAULT_HARD_TIMEOUT, + Duration::from_secs(10) + ); + assert!( + OWNER_LOCAL_RESERVE_DEFAULT_HARD_TIMEOUT > OWNER_LOCAL_RESERVE_SHRINK_IDLE_COOLDOWN + ); + } + + #[test] + fn configured_pool_refills_before_pending_claims_consume_headroom() { + let snapshot = RebalanceClassSnapshot { + slot_size: SLOT_SIZE, + slots_per_grant: 64, + used_slots: 64 * 228, + free_slots: 64 * 4, + grant_count: 232, + pending_slot_demand: 0, + expected_grant_count: 232, + }; + assert_eq!(owner_local_reserve_desired_free_slots(snapshot), 64 * 4); + assert_eq!( + owner_local_reserve_target_grant_count( + snapshot.slots_per_grant, + snapshot.used_slots, + owner_local_reserve_desired_free_slots(snapshot), + snapshot.expected_grant_count, + ), + 232 + ); + + let pressured = RebalanceClassSnapshot { + used_slots: snapshot.used_slots + 1, + free_slots: snapshot.free_slots - 1, + ..snapshot + }; + assert_eq!( + owner_local_reserve_target_grant_count( + pressured.slots_per_grant, + pressured.used_slots, + owner_local_reserve_desired_free_slots(pressured), + pressured.expected_grant_count, + ), + 233 + ); + } + + #[test] + fn get_target_pressure_can_detach_a_non_tail_fully_free_excess_grant() { + let mut class_state = OwnerLocalReserveClassState::new(SLOT_SIZE, 2); + class_state.expected_grant_count = 1; + for grant_id in 1..=3 { + class_state.grants.push(OwnerLocalReserveGrantState::new( + grant_id, + 0, + grant_id * 1024, + 1024, + SLOT_SIZE, + 2, + )); + } + class_state.grants[0] + .claim_prepared_slot() + .expect("first grant must have a slot"); + class_state.grants[2] + .claim_prepared_slot() + .expect("tail grant must have a slot"); + + assert!(detach_excess_fully_free_grant(&mut class_state, false).is_none()); + let (index, grant) = detach_excess_fully_free_grant(&mut class_state, true) + .expect("pressure shrink must find the free middle grant"); + assert_eq!(index, 1); + assert_eq!(grant.grant_id, 2); + assert_eq!(class_state.grants.len(), 2); + } + + #[test] + fn get_target_pressure_never_shrinks_below_active_or_expected_target() { + let mut class_state = OwnerLocalReserveClassState::new(SLOT_SIZE, 2); + class_state.expected_grant_count = 2; + for grant_id in 1..=2 { + class_state.grants.push(OwnerLocalReserveGrantState::new( + grant_id, + 0, + grant_id * 1024, + 1024, + SLOT_SIZE, + 2, + )); + } + assert!(detach_excess_fully_free_grant(&mut class_state, true).is_none()); + + class_state.expected_grant_count = 0; + for grant in &mut class_state.grants { + grant + .claim_prepared_slot() + .expect("each grant must have a slot"); + } + assert!(detach_excess_fully_free_grant(&mut class_state, true).is_none()); } } @@ -237,9 +571,51 @@ async fn owner_local_reserve_rebalance_once(view: &ClientKvApiView) { } } +fn report_owner_local_reserve_state(inner: &ClientKvApiInner) { + let snapshots = { + let pool = inner.owner_local_reserve_pool.lock(); + snapshot_rebalance_classes(&pool) + }; + for snapshot in snapshots { + let grant_count = u64::try_from(snapshot.grant_count).unwrap_or(u64::MAX); + let used_slots = u64::try_from(snapshot.used_slots).unwrap_or(u64::MAX); + let free_slots = u64::try_from(snapshot.free_slots).unwrap_or(u64::MAX); + let reserved_slots = grant_count.saturating_mul(u64::from(snapshot.slots_per_grant)); + tracing::info!( + "owner local reserve state: slot_size={} used_slots={} free_slots={} pending_slots={} grants={} expected_grants={} reserved_slots={} used_slot_bytes={} usable_slot_bytes={} physical_reserved_bytes={}", + snapshot.slot_size, + snapshot.used_slots, + snapshot.free_slots, + snapshot.pending_slot_demand, + snapshot.grant_count, + snapshot.expected_grant_count, + reserved_slots, + used_slots.saturating_mul(snapshot.slot_size), + used_slots + .saturating_add(free_slots) + .saturating_mul(snapshot.slot_size), + grant_count.saturating_mul(OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES), + ); + } +} + pub fn spawn_owner_local_reserve_rebalance_actor(view: ClientKvApiView) { let view_task = view.clone(); view.spawn("owner_local_reserve_rebalance_actor", async move { + let expected = install_expected_capacity_class(view_task.client_kv_api().inner()); + if let Some(expected) = expected { + tracing::info!( + "owner local reserve expected capacity configured: value_len={} payload_capacity_bytes={} slot_size={} slots_per_grant={} expected_grants={} physical_reserved_target_bytes={}", + expected.value_len, + expected.payload_capacity_bytes, + expected.slot_size, + expected.slots_per_grant, + expected.grant_count, + u64::try_from(expected.grant_count) + .unwrap_or(u64::MAX) + .saturating_mul(OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES), + ); + } let shutdown_poller = view_task.register_shutdown_poller(); let mut shutdown_waiter = view_task.register_shutdown_waiter(); let notify = view_task @@ -247,6 +623,7 @@ pub fn spawn_owner_local_reserve_rebalance_actor(view: ClientKvApiView) { .inner() .owner_local_reserve_rebalance_notify(); let mut tick = tokio::time::interval(OWNER_LOCAL_RESERVE_REBALANCE_INTERVAL); + let mut last_report_at = Instant::now(); loop { tokio::select! { @@ -265,6 +642,10 @@ pub fn spawn_owner_local_reserve_rebalance_actor(view: ClientKvApiView) { } owner_local_reserve_rebalance_once(&view_task).await; + if last_report_at.elapsed() >= OWNER_LOCAL_RESERVE_REPORT_INTERVAL { + report_owner_local_reserve_state(view_task.client_kv_api().inner()); + last_report_at = Instant::now(); + } } }); } diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs index 544d5e6..898172b 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs @@ -13,16 +13,18 @@ use crate::client_kv_api::msg_pack::{ ExternalPutStartReq, ExternalPutStartResp, ExternalPutTransferEndReq, ExternalPutTransferEndResp, SyncKvToFileReq, SyncKvToFileResp, TestPutPhaseTrace, }; +use crate::client_kv_api::reclaim::handle_batch_owner_reclaim; use crate::cluster_manager::{NodeID, NodeIDString}; use crate::config::TestSpecConfig; use crate::master_kv_router::msg_pack::{ - BatchDeleteAckReq, BatchDeleteClientKvMetaCacheReq, BatchGetDoneReq, BatchGetRevokeReq, - BatchGetStartItemResp, BatchGetStartReq, BatchIsExistReq, BatchPreparePutKeysReq, - BatchPutDoneReq, BatchPutRevokeReq, BatchPutStartReq, BatchReleasePutKeyReservationsReq, - CountPrefixReq, DeleteClientKvMetaCacheItem, + BatchDeleteAckReq, BatchDeleteClientKvMetaCacheReq, BatchEnqueueReplicaTaskReq, + BatchGetDoneReq, BatchGetRevokeReq, BatchGetStartItemResp, BatchGetStartReq, BatchIsExistReq, + BatchOwnerReclaimReq, BatchPreparePutKeysReq, BatchPutDoneReq, BatchPutRevokeReq, + BatchPutStartReq, BatchReleasePutKeyReservationsReq, CountPrefixReq, + DeleteClientKvMetaCacheItem, GroupedBatchPutDoneReq, }; use crate::master_lease_manager::msg_pack::{AllocateClientLeaseReq, ClientLeaseKeepaliveReq}; -use crate::memholder::{AllMemholderRefCount, MemoryInfo, UserMemHolder}; +use crate::memholder::{AllMemholderRefCount, ExternalMemHolderInfo, MemoryInfo, UserMemHolder}; use crate::memholder::{ EnsureMemholderMgmtDeleteHandle, MemholderManagerTrait, NodeHolderKey, OwnerDeleteAckItem, OwnerDeleteAckMemMgr, OwnerExternalMemMgr, @@ -49,11 +51,13 @@ use crate::{ }; use async_trait::async_trait; use crossbeam::queue::SegQueue; -use dashmap::DashMap; +use dashmap::{DashMap, DashSet}; use fluxon_framework::{LogicalModule, define_module}; use fluxon_framework_compiled::upgrade_view_guard::UpgradeViewGuard; use fluxon_util::map_lock::AMapLock; use limit_thirdparty::tokio; +use moka::notification::RemovalCause; +use moka::ops::compute::Op as MokaComputeOp; use parking_lot::{Mutex, RwLock}; use std::collections::HashMap; use std::collections::HashSet; @@ -64,6 +68,10 @@ use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; use tracing::warn; const REPLICA_TASK_QUEUE_CAPACITY: usize = 128; +// Queue only weak source references. This preserves a deep policy backlog without turning queued +// write-back work into non-reclaimable owner memory; the dispatcher pins a still-current source +// immediately before handing it to the bounded replica-task actor. +const OWNER_HOT_EVICTION_QUEUE_CAPACITY: usize = 4096; const OWNER_LOCAL_PUBLISH_QUEUE_CAPACITY: usize = 4096; const OWNER_LOCAL_PUBLISH_MAX_INFLIGHT: usize = 64; @@ -80,12 +88,37 @@ pub struct OwnerRuntimeObserveSnapshot { pub external_get_holding_entries: u64, pub external_get_holding_bytes: u64, pub external_pending_put_entries: u64, + pub hot_cache_capacity_bytes: u64, + pub hot_cache_entries: u64, + pub hot_cache_weighted_bytes: u64, + pub hot_size_evictions: u64, + pub hot_replica_enqueued: u64, + pub hot_replica_completed: u64, + pub hot_replica_already_satisfied: u64, + pub hot_replica_failed: u64, + pub hot_replica_obsolete: u64, + pub hot_replica_dispatch_failed: u64, + pub hot_replica_inflight: u64, + pub hot_eviction_skipped_stale: u64, + pub hot_eviction_skipped_reclaim: u64, + pub hot_eviction_skipped_duplicate: u64, + pub hot_group_registry_entries: u64, + pub hot_group_replica_triggered: u64, + pub hot_group_replica_triggers: u64, + pub hot_group_members_enqueued: u64, + pub hot_group_trigger_duplicates: u64, + pub hot_group_trigger_incomplete: u64, + pub grouped_put_done_batches: u64, + pub grouped_put_done_items: u64, + pub legacy_put_done_batches: u64, + pub legacy_put_done_items: u64, } pub use get::RemoteGetInfo; pub use put::{OwnerLocalPublishItem, OwnerLocalPublishJob, OwnerReservedPutItem}; pub mod external_api; mod local_reserve_rebalance; +mod reclaim; pub use external_api::HandlerForExternalClient; pub type TestObservePutPhaseSink = Arc>>; pub type ExternalGetStartTransferOutput = @@ -153,6 +186,8 @@ pub struct ExternalGetStartSharedState { pub struct ExternalGetStartSharedOp { pub dedup_key: ExternalGetStartDedupKey, pub transfer_concurrency: usize, + /// Set only when every requested page is already owner-local. + pub inline_local_memory_infos: OnceLock>>, pub state: Mutex, pub notify: Arc, } @@ -162,6 +197,7 @@ impl ExternalGetStartSharedOp { Self { dedup_key, transfer_concurrency, + inline_local_memory_infos: OnceLock::new(), state: Mutex::new(ExternalGetStartSharedState { waiter_count: 1, phase: ExternalGetStartSharedPhase::Starting, @@ -1079,6 +1115,8 @@ define_module!( #[derive(Clone, Debug)] pub struct ClientKvApiNewArg { pub test_spec_config: TestSpecConfig, + /// Logical hot-tier capacity only. This does not resize the owner segment. + pub owner_hot_cache_capacity_bytes: Option, } pub struct ClientKvApi(ClientKvApiInner); @@ -1101,24 +1139,646 @@ pub(crate) struct LocalSnapshotInfo { put_version: u32, } -impl GetCachedInfo { - fn version_matches(&self, put_time_ms: u64, put_version: u32) -> bool { - if self.put_time_ms == put_time_ms { - self.put_version <= put_version - } else { - self.put_time_ms <= put_time_ms +#[derive(Clone)] +struct OwnerHotCacheEntry { + put_id: crate::master_kv_router::put::PutIDForAKey, + memory_info: Weak, + weight_bytes: u32, +} + +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +struct OwnerHotReplicaIdentity { + key: String, + put_time_ms: u64, + put_version: u32, +} + +impl OwnerHotReplicaIdentity { + fn from_group_member(member: &crate::master_kv_router::msg_pack::PutAtomicGroupMember) -> Self { + Self { + key: member.key.clone(), + put_time_ms: member.put_id.0, + put_version: member.put_id.1, } } } -impl LocalSnapshotInfo { - fn version_matches(&self, put_time_ms: u64, put_version: u32) -> bool { - if self.put_time_ms == put_time_ms { - self.put_version <= put_version - } else { - self.put_time_ms <= put_time_ms +#[derive(Default)] +struct OwnerHotCacheCounters { + size_evictions: AtomicU64, + replica_enqueued: AtomicU64, + replica_completed: AtomicU64, + replica_already_satisfied: AtomicU64, + replica_failed: AtomicU64, + replica_obsolete: AtomicU64, + replica_dispatch_failed: AtomicU64, + skipped_stale: AtomicU64, + skipped_reclaim: AtomicU64, + skipped_duplicate: AtomicU64, + group_replica_triggers: AtomicU64, + group_members_enqueued: AtomicU64, + group_trigger_duplicates: AtomicU64, + group_trigger_incomplete: AtomicU64, + grouped_put_done_batches: AtomicU64, + grouped_put_done_items: AtomicU64, + legacy_put_done_batches: AtomicU64, + legacy_put_done_items: AtomicU64, +} + +const OWNER_HOT_REPLICA_OUTCOME_PENDING: u32 = 0; +const OWNER_HOT_REPLICA_OUTCOME_RECORDED: u32 = 1; + +pub(crate) struct OwnerHotReplicaGuard { + identity: OwnerHotReplicaIdentity, + inflight: Arc>, + counters: Arc, + group_trigger: Option, + group_replica_triggered: Arc>, + outcome: AtomicU32, +} + +impl OwnerHotReplicaGuard { + fn new( + identity: OwnerHotReplicaIdentity, + inflight: Arc>, + counters: Arc, + group_trigger: Option, + group_replica_triggered: Arc>, + ) -> Self { + Self { + identity, + inflight, + counters, + group_trigger, + group_replica_triggered, + outcome: AtomicU32::new(OWNER_HOT_REPLICA_OUTCOME_PENDING), + } + } + + fn release_group_trigger(&self) { + if let Some(group_trigger) = self.group_trigger.as_ref() { + self.group_replica_triggered.remove(group_trigger); + } + } + + pub(crate) fn mark_completed(&self) { + if self + .outcome + .compare_exchange( + OWNER_HOT_REPLICA_OUTCOME_PENDING, + OWNER_HOT_REPLICA_OUTCOME_RECORDED, + Ordering::Relaxed, + Ordering::Relaxed, + ) + .is_ok() + { + self.counters + .replica_completed + .fetch_add(1, Ordering::Relaxed); + } + } + + pub(crate) fn mark_already_satisfied(&self) { + if self + .outcome + .compare_exchange( + OWNER_HOT_REPLICA_OUTCOME_PENDING, + OWNER_HOT_REPLICA_OUTCOME_RECORDED, + Ordering::Relaxed, + Ordering::Relaxed, + ) + .is_ok() + { + self.counters + .replica_already_satisfied + .fetch_add(1, Ordering::Relaxed); + } + } + + pub(crate) fn mark_obsolete(&self) { + if self + .outcome + .compare_exchange( + OWNER_HOT_REPLICA_OUTCOME_PENDING, + OWNER_HOT_REPLICA_OUTCOME_RECORDED, + Ordering::Relaxed, + Ordering::Relaxed, + ) + .is_ok() + { + self.counters + .replica_obsolete + .fetch_add(1, Ordering::Relaxed); + self.release_group_trigger(); + } + } + + fn mark_dispatch_failed(&self) { + if self + .outcome + .compare_exchange( + OWNER_HOT_REPLICA_OUTCOME_PENDING, + OWNER_HOT_REPLICA_OUTCOME_RECORDED, + Ordering::Relaxed, + Ordering::Relaxed, + ) + .is_ok() + { + self.counters + .replica_dispatch_failed + .fetch_add(1, Ordering::Relaxed); + self.release_group_trigger(); + } + } +} + +impl Drop for OwnerHotReplicaGuard { + fn drop(&mut self) { + if self.outcome.load(Ordering::Relaxed) == OWNER_HOT_REPLICA_OUTCOME_PENDING { + self.counters.replica_failed.fetch_add(1, Ordering::Relaxed); + self.release_group_trigger(); + } + self.inflight.remove(&self.identity); + } +} + +pub(crate) struct OwnerHotEvictionEvent { + key: String, + put_id: crate::master_kv_router::put::PutIDForAKey, + memory_info: Weak, + guard: OwnerHotReplicaGuard, +} + +pub(crate) struct OwnerPreparedReclaim { + item: crate::master_kv_router::msg_pack::OwnerReclaimItem, + cached_info: GetCachedInfo, + local_snapshot: Option, +} + +pub(crate) enum OwnerReclaimRecord { + Prepared(OwnerPreparedReclaim), + Committed(crate::master_kv_router::msg_pack::OwnerReclaimItem), +} + +#[derive(Default)] +pub(crate) struct OwnerKeyControlState { + local_puts: u32, + reclaim: Option, +} + +fn resolve_local_visible_batch( + keys: &[String], + controls: &HashMap, + mut resolve_unfenced: impl FnMut(&str) -> Option, +) -> Vec> { + keys.iter() + .map(|key| { + if controls + .get(key) + .is_some_and(|state| state.reclaim.is_some()) + { + None + } else { + resolve_unfenced(key) + } + }) + .collect() +} + +fn allocate_external_holding_id(counter: &AtomicU64) -> u64 { + counter + .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |current| { + current.checked_add(1) + }) + .expect("external holding id space exhausted") +} + +fn owner_hot_weight_bytes(memory_info: &MemoryInfo) -> u32 { + let bytes = memory_info + .local_reserve_resident_slot_ref() + .map(|(slot_size, _, _)| slot_size) + .unwrap_or(memory_info.len as u64); + u32::try_from(bytes).unwrap_or(u32::MAX) +} + +fn clone_if_owner_hot_entry_matches( + current_put_id: crate::master_kv_router::put::PutIDForAKey, + current: &Arc, + entry_put_id: crate::master_kv_router::put::PutIDForAKey, + entry: &Weak, +) -> Option> { + (current_put_id == entry_put_id && Weak::ptr_eq(entry, &Arc::downgrade(current))) + .then(|| current.clone()) +} + +fn pin_current_owner_hot_source( + key: &str, + entry: &OwnerHotCacheEntry, + owner_key_control: &Mutex>, + get_cached_info: &DashMap, + counters: &OwnerHotCacheCounters, +) -> Option> { + let controls = owner_key_control.lock(); + if controls + .get(key) + .is_some_and(|state| state.reclaim.is_some()) + { + counters.skipped_reclaim.fetch_add(1, Ordering::Relaxed); + return None; + } + let Some(cached) = get_cached_info.get(key) else { + counters.skipped_stale.fetch_add(1, Ordering::Relaxed); + return None; + }; + let Some(pinned) = clone_if_owner_hot_entry_matches( + (cached.put_time_ms, cached.put_version), + &cached.mem_holder, + entry.put_id, + &entry.memory_info, + ) else { + counters.skipped_stale.fetch_add(1, Ordering::Relaxed); + return None; + }; + + // This clone is made under the same key fence used by reclaim. If reclaim + // wins first the source is absent/fenced; if this clone wins, reclaim sees + // the additional strong reference and returns Busy. + Some(pinned) +} + +fn owner_hot_group_anchor_identity( + group: &crate::master_kv_router::msg_pack::PutAtomicGroup, +) -> Option { + group + .members + .first() + .map(OwnerHotReplicaIdentity::from_group_member) +} + +fn register_owner_hot_atomic_group( + atomic_groups: &DashMap< + OwnerHotReplicaIdentity, + Arc, + >, + group: &crate::master_kv_router::msg_pack::PutAtomicGroup, +) { + let Some(anchor) = owner_hot_group_anchor_identity(group) else { + return; + }; + let existing = atomic_groups + .get(&anchor) + .map(|entry| entry.value().clone()); + let group = match existing { + Some(existing) if existing.as_ref() == group => existing, + Some(_) => { + tracing::warn!( + "owner hot atomic-group anchor reused with different membership: key={} put_id=({},{})", + anchor.key, + anchor.put_time_ms, + anchor.put_version + ); + Arc::new(group.clone()) + } + None => Arc::new(group.clone()), + }; + for member in &group.members { + atomic_groups.insert( + OwnerHotReplicaIdentity::from_group_member(member), + group.clone(), + ); + } +} + +fn forget_owner_hot_atomic_group( + atomic_groups: &DashMap< + OwnerHotReplicaIdentity, + Arc, + >, + group_replica_triggered: &DashSet, + identity: &OwnerHotReplicaIdentity, +) { + let group = atomic_groups + .get(identity) + .map(|entry| entry.value().clone()); + let Some(group) = group else { + return; + }; + if let Some(anchor) = owner_hot_group_anchor_identity(group.as_ref()) { + group_replica_triggered.remove(&anchor); + } + for member in &group.members { + atomic_groups.remove(&OwnerHotReplicaIdentity::from_group_member(member)); + } +} + +fn pin_current_owner_hot_group_sources( + group: &crate::master_kv_router::msg_pack::PutAtomicGroup, + owner_key_control: &Mutex>, + get_cached_info: &DashMap, + counters: &OwnerHotCacheCounters, +) -> Option)>> { + let controls = owner_key_control.lock(); + let mut sources = Vec::with_capacity(group.members.len()); + for member in &group.members { + if controls + .get(&member.key) + .is_some_and(|state| state.reclaim.is_some()) + { + counters.skipped_reclaim.fetch_add(1, Ordering::Relaxed); + return None; + } + let Some(cached) = get_cached_info.get(&member.key) else { + counters.skipped_stale.fetch_add(1, Ordering::Relaxed); + return None; + }; + if (cached.put_time_ms, cached.put_version) != member.put_id { + counters.skipped_stale.fetch_add(1, Ordering::Relaxed); + return None; } + sources.push(( + OwnerHotReplicaIdentity::from_group_member(member), + cached.mem_holder.clone(), + )); } + Some(sources) +} + +fn owner_hot_tp_cohort_key_rows( + identity: &OwnerHotReplicaIdentity, + group: Option<&crate::master_kv_router::msg_pack::PutAtomicGroup>, +) -> Result>>, ()> { + let member_keys = group + .map(|group| { + group + .members + .iter() + .map(|member| member.key.as_str()) + .collect::>() + }) + .unwrap_or_else(|| vec![identity.key.as_str()]); + let Some(first_key) = member_keys.first().copied() else { + return Err(()); + }; + let first_tp = crate::master_kv_router::infer_sglang_tp_key(first_key); + let Some(first_tp) = first_tp else { + return member_keys + .iter() + .all(|key| crate::master_kv_router::infer_sglang_tp_key(key).is_none()) + .then_some(None) + .ok_or(()); + }; + let mut logical_members = Vec::with_capacity(member_keys.len()); + for key in member_keys { + let Some(member_tp) = crate::master_kv_router::infer_sglang_tp_key(key) else { + return Err(()); + }; + if member_tp.rank != first_tp.rank || member_tp.size != first_tp.size { + return Err(()); + } + logical_members.push(member_tp.logical_prefix.to_string()); + } + if first_tp.size == 1 { + return Ok(None); + } + Ok(Some( + (0..first_tp.size) + .map(|rank| { + logical_members + .iter() + .map(|logical_prefix| format!("{logical_prefix}_{rank}_{}", first_tp.size)) + .collect::>() + }) + .collect(), + )) +} + +fn pin_current_owner_hot_tp_cohort_sources( + cohort_key_rows: &[Vec], + expect_atomic_group: bool, + owner_key_control: &Mutex>, + get_cached_info: &DashMap, + atomic_groups: &DashMap< + OwnerHotReplicaIdentity, + Arc, + >, + counters: &OwnerHotCacheCounters, +) -> Option)>> { + let controls = owner_key_control.lock(); + let mut cohort_sources = Vec::new(); + for rank_keys in cohort_key_rows { + if rank_keys.is_empty() { + return None; + } + let mut rank_sources = Vec::with_capacity(rank_keys.len()); + for key in rank_keys { + if controls + .get(key) + .is_some_and(|state| state.reclaim.is_some()) + { + counters.skipped_reclaim.fetch_add(1, Ordering::Relaxed); + return None; + } + let Some(cached) = get_cached_info.get(key) else { + counters.skipped_stale.fetch_add(1, Ordering::Relaxed); + return None; + }; + rank_sources.push(( + OwnerHotReplicaIdentity { + key: key.clone(), + put_time_ms: cached.put_time_ms, + put_version: cached.put_version, + }, + cached.mem_holder.clone(), + )); + } + + if expect_atomic_group { + let Some(rank_group) = atomic_groups + .get(&rank_sources[0].0) + .map(|entry| entry.value().clone()) + else { + return None; + }; + if rank_group.members.len() != rank_sources.len() + || rank_group.members.iter().zip(rank_sources.iter()).any( + |(member, (identity, _))| { + member.key != identity.key + || member.put_id != (identity.put_time_ms, identity.put_version) + }, + ) + { + return None; + } + for (identity, _) in &rank_sources { + if !atomic_groups + .get(identity) + .is_some_and(|entry| Arc::ptr_eq(entry.value(), &rank_group)) + { + return None; + } + } + } else if rank_sources.len() != 1 || atomic_groups.contains_key(&rank_sources[0].0) { + return None; + } + cohort_sources.extend(rank_sources); + } + Some(cohort_sources) +} + +fn try_enqueue_owner_hot_replica_event( + identity: OwnerHotReplicaIdentity, + memory_info: Arc, + group_trigger: Option, + inflight: &Arc>, + group_replica_triggered: &Arc>, + counters: &Arc, + eviction_tx: &tokio::sync::ampsc::Sender, +) -> bool { + if !inflight.insert(identity.clone()) { + counters.skipped_duplicate.fetch_add(1, Ordering::Relaxed); + return false; + } + let event = OwnerHotEvictionEvent { + key: identity.key.clone(), + put_id: (identity.put_time_ms, identity.put_version), + memory_info: Arc::downgrade(&memory_info), + guard: OwnerHotReplicaGuard::new( + identity, + inflight.clone(), + counters.clone(), + group_trigger, + group_replica_triggered.clone(), + ), + }; + match eviction_tx.try_send(event) { + Ok(()) => { + counters.replica_enqueued.fetch_add(1, Ordering::Relaxed); + true + } + Err(err) => { + let event = err.into_inner(); + tracing::warn!( + "owner hot-cache eviction actor is closed; replica event dropped: key={} put_id=({},{})", + event.key, + event.put_id.0, + event.put_id.1 + ); + event.guard.mark_dispatch_failed(); + false + } + } +} + +fn build_owner_hot_cache( + capacity_bytes: u64, + owner_key_control: Arc>>, + get_cached_info: Arc>, + inflight: Arc>, + atomic_groups: Arc< + DashMap>, + >, + group_replica_triggered: Arc>, + counters: Arc, + eviction_tx: tokio::sync::ampsc::Sender, +) -> moka::sync::Cache { + assert!( + capacity_bytes > 0, + "owner hot-cache capacity must be positive" + ); + moka::sync::Cache::builder() + .max_capacity(capacity_bytes) + .weigher(|_key: &String, entry: &OwnerHotCacheEntry| entry.weight_bytes) + .eviction_listener(move |key, entry, cause| { + if cause != RemovalCause::Size { + return; + } + counters.size_evictions.fetch_add(1, Ordering::Relaxed); + let Some(memory_info) = pin_current_owner_hot_source( + key.as_str(), + &entry, + owner_key_control.as_ref(), + get_cached_info.as_ref(), + counters.as_ref(), + ) else { + return; + }; + let identity = OwnerHotReplicaIdentity { + key: (*key).clone(), + put_time_ms: entry.put_id.0, + put_version: entry.put_id.1, + }; + let group = atomic_groups + .get(&identity) + .map(|entry| entry.value().clone()); + let cohort_sources = match owner_hot_tp_cohort_key_rows(&identity, group.as_deref()) { + Ok(Some(cohort_key_rows)) => pin_current_owner_hot_tp_cohort_sources( + &cohort_key_rows, + group.is_some(), + owner_key_control.as_ref(), + get_cached_info.as_ref(), + atomic_groups.as_ref(), + counters.as_ref(), + ), + Ok(None) => match group.as_deref() { + Some(group) => pin_current_owner_hot_group_sources( + group, + owner_key_control.as_ref(), + get_cached_info.as_ref(), + counters.as_ref(), + ), + None => Some(vec![(identity.clone(), memory_info)]), + }, + Err(()) => None, + }; + let Some(cohort_sources) = cohort_sources else { + counters + .group_trigger_incomplete + .fetch_add(1, Ordering::Relaxed); + return; + }; + if cohort_sources.len() > 1 { + counters + .group_replica_triggers + .fetch_add(1, Ordering::Relaxed); + let mut enqueued = 0u64; + for (member_identity, member_memory_info) in cohort_sources { + if try_enqueue_owner_hot_replica_event( + member_identity, + member_memory_info, + None, + &inflight, + &group_replica_triggered, + &counters, + &eviction_tx, + ) { + enqueued = enqueued.saturating_add(1); + } + } + counters + .group_members_enqueued + .fetch_add(enqueued, Ordering::Relaxed); + if enqueued == 0 { + counters + .group_trigger_duplicates + .fetch_add(1, Ordering::Relaxed); + } + return; + } + let (identity, memory_info) = cohort_sources + .into_iter() + .next() + .expect("owner hot cohort must contain its trigger source"); + let _ = try_enqueue_owner_hot_replica_event( + identity, + memory_info, + None, + &inflight, + &group_replica_triggered, + &counters, + &eviction_tx, + ); + }) + .build() } struct ClientKvApiViewHolder { @@ -1170,7 +1830,7 @@ pub struct ClientKvApiInner { pub get_remote_kv_lock: AMapLock, /// key -> value info on this node /// we can only remove value if it's put_time_ms and put_version match remote eviction command - get_cached_info: DashMap, + get_cached_info: Arc>, /// key -> locally readable resident slot before backend put_start/put_done finishes. precommit_local_visible_info: DashMap, /// key -> local replica version remembered from local put/get durable-replica success. @@ -1179,12 +1839,25 @@ pub struct ClientKvApiInner { local_snapshot_info: DashMap, /// KvOwner-managed resident staging grants for hostless put_start. owner_local_reserve_pool: Mutex, + /// Serialize reserve claims so a later waiter cannot steal slots reclaimed for the + /// waiter currently assembling a lease. Tokio's mutex provides FIFO acquisition order. + owner_local_reserve_claim_lock: limit_thirdparty::tokio::sync::AMutex<()>, /// Wake the background reserve actor after demand/free-slot changes. owner_local_reserve_rebalance_notify: Arc, /// Owner-local write-back put ids for external local-first path. external_local_first_put_id_counter: AtomicU32, - /// Owner-local inflight write guard for external local-first path. - external_local_first_inflight_key_counts: DashMap, + /// Atomic owner-side gate for local-first puts, local index access, and reclaim fencing. + owner_key_control: Arc>>, + /// A weak-value admission/recency tier. It never owns resident memory and + /// therefore cannot become a second physical-reclaim authority. + owner_hot_cache: Option>, + owner_hot_replica_inflight: Arc>, + owner_hot_atomic_groups: Arc< + DashMap>, + >, + owner_hot_group_replica_triggered: Arc>, + owner_hot_counters: Arc, + owner_hot_eviction_rx: Mutex>>, /// Shared delete actor input for owner -> external weak-index invalidation. pub external_invalidate_delete: EnsureMemholderMgmtDeleteHandle, @@ -1198,6 +1871,8 @@ pub struct ClientKvApiInner { pub external_get_start_registry: DashMap>, pub external_get_start_by_key: DashMap>, next_external_get_start_handle: AtomicU64, + /// External holding identities are independent from upstream and resident holder ids. + next_external_holding_id: AtomicU64, /// Weak handle to a shared refcount tracker for all UserMemHolder of this client. /// /// - A strong `Arc` is given to every `UserMemHolder` created by this client. @@ -1222,6 +1897,7 @@ pub struct ClientKvApiInner { rpc_caller_batch_put_start: RPCCaller, rpc_caller_batch_put_revoke: RPCCaller, rpc_caller_batch_put_done: RPCCaller, + rpc_caller_grouped_batch_put_done: RPCCaller, rpc_caller_batch_prepare_put_keys: RPCCaller, rpc_caller_batch_release_put_key_reservations: RPCCaller, rpc_caller_put_append_start: RPCCaller, @@ -1257,6 +1933,112 @@ impl ClientKvApiInner { &self.view } + fn owner_hot_register_atomic_group( + &self, + group: &crate::master_kv_router::msg_pack::PutAtomicGroup, + ) { + register_owner_hot_atomic_group(self.owner_hot_atomic_groups.as_ref(), group); + } + + fn owner_hot_forget_atomic_group_for_member(&self, identity: &OwnerHotReplicaIdentity) { + forget_owner_hot_atomic_group( + self.owner_hot_atomic_groups.as_ref(), + self.owner_hot_group_replica_triggered.as_ref(), + identity, + ); + } + + fn owner_hot_track_committed( + &self, + key: &str, + put_id: crate::master_kv_router::put::PutIDForAKey, + memory_info: &Arc, + atomic_group: Option<&crate::master_kv_router::msg_pack::PutAtomicGroup>, + ) { + let Some(cache) = self.owner_hot_cache.as_ref() else { + return; + }; + if !self.owner_hot_source_is_current(key, put_id, memory_info) { + return; + } + if let Some(group) = atomic_group { + self.owner_hot_register_atomic_group(group); + } + cache.insert( + key.to_string(), + OwnerHotCacheEntry { + put_id, + memory_info: Arc::downgrade(memory_info), + weight_bytes: owner_hot_weight_bytes(memory_info.as_ref()), + }, + ); + if !self.owner_hot_source_is_current(key, put_id, memory_info) { + self.owner_hot_invalidate_version(key, put_id); + } + } + + fn owner_hot_touch_or_promote( + &self, + key: &str, + put_id: crate::master_kv_router::put::PutIDForAKey, + memory_info: &Arc, + ) { + let Some(cache) = self.owner_hot_cache.as_ref() else { + return; + }; + if cache.get(key).is_some_and(|entry| { + entry.put_id == put_id && Weak::ptr_eq(&entry.memory_info, &Arc::downgrade(memory_info)) + }) { + return; + } + self.owner_hot_track_committed(key, put_id, memory_info, None); + } + + pub(crate) fn owner_hot_source_is_current( + &self, + key: &str, + put_id: crate::master_kv_router::put::PutIDForAKey, + memory_info: &Arc, + ) -> bool { + let controls = self.owner_key_control.lock(); + if controls + .get(key) + .is_some_and(|state| state.reclaim.is_some()) + { + return false; + } + self.get_cached_info.get(key).is_some_and(|cached| { + cached.put_time_ms == put_id.0 + && cached.put_version == put_id.1 + && Arc::ptr_eq(&cached.mem_holder, memory_info) + }) + } + + pub(crate) fn owner_hot_invalidate_version( + &self, + key: &str, + put_id: crate::master_kv_router::put::PutIDForAKey, + ) { + let Some(cache) = self.owner_hot_cache.as_ref() else { + return; + }; + let _ = cache.entry(key.to_string()).and_compute_with(|entry| { + if entry + .as_ref() + .is_some_and(|entry| entry.value().put_id == put_id) + { + MokaComputeOp::Remove + } else { + MokaComputeOp::Nop + } + }); + self.owner_hot_forget_atomic_group_for_member(&OwnerHotReplicaIdentity { + key: key.to_string(), + put_time_ms: put_id.0, + put_version: put_id.1, + }); + } + pub(crate) fn release_local_reserve_route_for_memory_info(&self, memory_info: &MemoryInfo) { let Some((slot_size, grant_id, slot_index)) = memory_info.local_reserve_resident_slot_ref() else { @@ -1322,32 +2104,51 @@ impl ClientKvApiInner { reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, ) -> KvResult<()> { - if reject_if_exist_same_key && self.has_local_snapshot(key) { + let mut controls = self.owner_key_control.lock(); + if controls + .get(key) + .is_some_and(|state| state.reclaim.is_some()) + { + return Err(KvError::Api(ApiError::KeyBeingWritten { + key: key.to_string(), + })); + } + if reject_if_exist_same_key + && (self.precommit_local_visible_info.contains_key(key) + || self.get_cached_info.contains_key(key) + || self.local_snapshot_info.contains_key(key)) + { return Err(KvError::Api(ApiError::KeyAlreadyExists { key: key.to_string(), })); } - let mut entry = self - .external_local_first_inflight_key_counts - .entry(key.to_string()) - .or_insert(0); - if reject_if_inflight_same_key && *entry > 0 { + let state = controls.entry(key.to_string()).or_default(); + if reject_if_inflight_same_key && state.local_puts > 0 { return Err(KvError::Api(ApiError::KeyBeingWritten { key: key.to_string(), })); } - *entry += 1; + state.local_puts = state + .local_puts + .checked_add(1) + .expect("owner local-first put counter overflow"); Ok(()) } pub(crate) fn release_external_local_first_put_key(&self, key: &str) { - if let Some(mut entry) = self.external_local_first_inflight_key_counts.get_mut(key) { - if *entry <= 1 { - drop(entry); - self.external_local_first_inflight_key_counts.remove(key); - } else { - *entry -= 1; - } + let mut controls = self.owner_key_control.lock(); + let remove = { + let state = controls + .get_mut(key) + .expect("owner local-first put state missing on release"); + state.local_puts = state + .local_puts + .checked_sub(1) + .expect("owner local-first put counter underflow"); + state.local_puts == 0 && state.reclaim.is_none() + }; + if remove { + controls.remove(key); } } @@ -1356,6 +2157,19 @@ impl ClientKvApiInner { key: &str, put_id: crate::master_kv_router::put::PutIDForAKey, ) { + let controls = self.owner_key_control.lock(); + if controls + .get(key) + .is_some_and(|state| state.reclaim.is_some()) + { + tracing::debug!( + "skip local snapshot publication behind owner reclaim fence: key={} put_id=({},{})", + key, + put_id.0, + put_id.1 + ); + return; + } self.local_snapshot_info.insert( key.to_string(), LocalSnapshotInfo { @@ -1366,23 +2180,67 @@ impl ClientKvApiInner { } pub(crate) fn has_local_snapshot(&self, key: &str) -> bool { + let controls = self.owner_key_control.lock(); + if controls + .get(key) + .is_some_and(|state| state.reclaim.is_some()) + { + return false; + } self.precommit_local_visible_info.contains_key(key) || self.get_cached_info.contains_key(key) || self.local_snapshot_info.contains_key(key) } - pub(crate) fn remove_local_snapshot_if( + pub(crate) fn local_visible_mem_holder(&self, key: &str) -> Option> { + let (memory_info, hot_put_id) = { + let controls = self.owner_key_control.lock(); + if controls + .get(key) + .is_some_and(|state| state.reclaim.is_some()) + { + return None; + } + let memory_info = self.local_visible_mem_holder_unfenced(key); + let hot_put_id = memory_info.as_ref().and_then(|memory_info| { + self.get_cached_info + .get(key) + .filter(|cached| Arc::ptr_eq(&cached.mem_holder, memory_info)) + .map(|cached| (cached.put_time_ms, cached.put_version)) + }); + (memory_info, hot_put_id) + }; + if let Some(put_id) = hot_put_id { + self.owner_hot_touch_or_promote( + key, + put_id, + memory_info + .as_ref() + .expect("hot touch requires a local memory holder"), + ); + } + memory_info + } + + pub(crate) fn local_committed_mem_holder_for_put_id( &self, key: &str, - put_time_ms: u64, - put_version: u32, - ) -> bool { - self.local_snapshot_info - .remove_if(key, |_, v| v.version_matches(put_time_ms, put_version)) - .is_some() + put_id: crate::master_kv_router::put::PutIDForAKey, + ) -> Option> { + let controls = self.owner_key_control.lock(); + if controls + .get(key) + .is_some_and(|state| state.reclaim.is_some()) + { + return None; + } + self.get_cached_info.get(key).and_then(|info| { + (info.put_time_ms == put_id.0 && info.put_version == put_id.1) + .then(|| info.mem_holder.clone()) + }) } - pub(crate) fn local_visible_mem_holder(&self, key: &str) -> Option> { + fn local_visible_mem_holder_unfenced(&self, key: &str) -> Option> { if let Some(info) = self.precommit_local_visible_info.get(key) { return Some(info.mem_holder.clone()); } @@ -1391,6 +2249,66 @@ impl ClientKvApiInner { .map(|info| info.mem_holder.clone()) } + pub(crate) fn local_visible_mem_holders( + &self, + keys: &[String], + ) -> Vec>> { + // A hostless get_start commonly checks hundreds of pages from one + // local prefix. Take one coherent reclaim-fence snapshot instead of + // locking owner_key_control once per page. The MemoryInfo Arcs keep + // any selected backing alive if reclaim begins after this snapshot. + let resolved = { + let controls = self.owner_key_control.lock(); + resolve_local_visible_batch(keys, &controls, |key| { + let memory_info = self.local_visible_mem_holder_unfenced(key)?; + let hot_put_id = self + .get_cached_info + .get(key) + .filter(|cached| Arc::ptr_eq(&cached.mem_holder, &memory_info)) + .map(|cached| (cached.put_time_ms, cached.put_version)); + Some((memory_info, hot_put_id)) + }) + }; + resolved + .into_iter() + .zip(keys) + .map(|(resolved, key)| { + let (memory_info, hot_put_id) = resolved?; + if let Some(put_id) = hot_put_id { + self.owner_hot_touch_or_promote(key, put_id, &memory_info); + } + Some(memory_info) + }) + .collect() + } + + pub(crate) fn install_external_get_holding( + &self, + req_node_id: &str, + memory_info: Arc, + ) -> ExternalMemHolderInfo { + let external_holder_id = allocate_external_holding_id(&self.next_external_holding_id); + let key = NodeHolderKey::new(req_node_id.to_string(), external_holder_id); + let external_memholder_info = ExternalMemHolderInfo { + offset: memory_info.offset, + len: memory_info.len, + holder_id: external_holder_id, + }; + let previous = self.external_get_holding.inner().insert( + key, + ExternalHoldingGetInfo { + key: memory_info.key.clone(), + req_node_id: req_node_id.to_string(), + memory_info, + }, + ); + assert!( + previous.is_none(), + "fresh external holding id unexpectedly replaced a live holding" + ); + external_memholder_info + } + pub async fn build_local_reserve_resident_memory_info( &self, key: &str, @@ -1436,26 +2354,94 @@ impl ClientKvApiInner { ) .await, ); - let replaced = self.get_cached_info.insert( - key.to_string(), - GetCachedInfo { - put_time_ms: put_id.0, - put_version: put_id.1, - mem_holder: memory_info, - }, - ); - if let Some(previous) = replaced { - self.release_local_reserve_route_for_memory_info(previous.mem_holder.as_ref()); + { + let controls = self.owner_key_control.lock(); + if controls + .get(key) + .is_some_and(|state| state.reclaim.is_some()) + { + return Err(KvError::Api(ApiError::KeyBeingWritten { + key: key.to_string(), + })); + } + let replaced = self.get_cached_info.insert( + key.to_string(), + GetCachedInfo { + put_time_ms: put_id.0, + put_version: put_id.1, + mem_holder: memory_info.clone(), + }, + ); + if let Some(previous) = replaced { + self.release_local_reserve_route_for_memory_info(previous.mem_holder.as_ref()); + } + self.local_snapshot_info.insert( + key.to_string(), + LocalSnapshotInfo { + put_time_ms: put_id.0, + put_version: put_id.1, + }, + ); } - self.remember_local_snapshot(key, put_id); + self.owner_hot_track_committed(key, put_id, &memory_info, None); Ok(()) } + pub(crate) fn install_get_cached_info_if_unfenced( + &self, + key: &str, + put_id: crate::master_kv_router::put::PutIDForAKey, + memory_info: Arc, + ) -> bool { + { + let controls = self.owner_key_control.lock(); + if controls + .get(key) + .is_some_and(|state| state.reclaim.is_some()) + { + tracing::debug!( + "skip get cache publication behind owner reclaim fence: key={} put_id=({},{})", + key, + put_id.0, + put_id.1 + ); + return false; + } + let replaced = self.get_cached_info.insert( + key.to_string(), + GetCachedInfo { + put_time_ms: put_id.0, + put_version: put_id.1, + mem_holder: memory_info.clone(), + }, + ); + if let Some(previous) = replaced { + self.release_local_reserve_route_for_memory_info(previous.mem_holder.as_ref()); + } + self.local_snapshot_info.insert( + key.to_string(), + LocalSnapshotInfo { + put_time_ms: put_id.0, + put_version: put_id.1, + }, + ); + } + self.owner_hot_track_committed(key, put_id, &memory_info, None); + true + } + pub fn install_precommit_local_visible_memory_info( &self, key: &str, memory_info: Arc, ) { + let controls = self.owner_key_control.lock(); + assert!( + !controls + .get(key) + .is_some_and(|state| state.reclaim.is_some()), + "precommit local index publication must not cross an owner reclaim fence" + ); let (slot_size, grant_id, slot_index) = memory_info .local_reserve_resident_slot_ref() .expect("resident memory_info must carry local reserve slot ref"); @@ -1480,6 +2466,7 @@ impl ClientKvApiInner { key: &str, expected_mem_holder: &Arc, ) -> bool { + let _controls = self.owner_key_control.lock(); self.precommit_local_visible_info .remove_if(key, |_, info| { Arc::ptr_eq(&info.mem_holder, expected_mem_holder) @@ -1492,50 +2479,69 @@ impl ClientKvApiInner { key: &str, put_id: crate::master_kv_router::put::PutIDForAKey, memory_info: Arc, + atomic_group: Option<&crate::master_kv_router::msg_pack::PutAtomicGroup>, ) -> KvResult<()> { - let is_same_pending = self - .precommit_local_visible_info - .get(key) - .map(|info| Arc::ptr_eq(&info.mem_holder, &memory_info)) - .unwrap_or(false); - if !is_same_pending { - return Err(KvError::Api(ApiError::Unknown { - detail: format!( - "precommit local visible cache missing while promoting key={}", - key - ), - })); - } - let (slot_size, grant_id, slot_index) = memory_info - .local_reserve_resident_slot_ref() - .expect("resident memory_info must carry local reserve slot ref"); - self.owner_promote_local_reserve_pending_slot_to_committed( - slot_size, grant_id, slot_index, - )?; - let removed = self - .precommit_local_visible_info - .remove_if(key, |_, info| Arc::ptr_eq(&info.mem_holder, &memory_info)) - .is_some(); - if !removed { - return Err(KvError::Api(ApiError::Unknown { - detail: format!( - "precommit local visible cache disappeared while promoting key={}", - key - ), - })); - } - let replaced = self.get_cached_info.insert( - key.to_string(), - GetCachedInfo { - put_time_ms: put_id.0, - put_version: put_id.1, - mem_holder: memory_info, - }, - ); - if let Some(previous) = replaced { - self.release_local_reserve_route_for_memory_info(previous.mem_holder.as_ref()); + { + let controls = self.owner_key_control.lock(); + if controls + .get(key) + .is_some_and(|state| state.reclaim.is_some()) + { + return Err(KvError::Api(ApiError::KeyBeingWritten { + key: key.to_string(), + })); + } + let is_same_pending = self + .precommit_local_visible_info + .get(key) + .map(|info| Arc::ptr_eq(&info.mem_holder, &memory_info)) + .unwrap_or(false); + if !is_same_pending { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "precommit local visible cache missing while promoting key={}", + key + ), + })); + } + let (slot_size, grant_id, slot_index) = memory_info + .local_reserve_resident_slot_ref() + .expect("resident memory_info must carry local reserve slot ref"); + self.owner_promote_local_reserve_pending_slot_to_committed( + slot_size, grant_id, slot_index, + )?; + let removed = self + .precommit_local_visible_info + .remove_if(key, |_, info| Arc::ptr_eq(&info.mem_holder, &memory_info)) + .is_some(); + if !removed { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "precommit local visible cache disappeared while promoting key={}", + key + ), + })); + } + let replaced = self.get_cached_info.insert( + key.to_string(), + GetCachedInfo { + put_time_ms: put_id.0, + put_version: put_id.1, + mem_holder: memory_info.clone(), + }, + ); + if let Some(previous) = replaced { + self.release_local_reserve_route_for_memory_info(previous.mem_holder.as_ref()); + } + self.local_snapshot_info.insert( + key.to_string(), + LocalSnapshotInfo { + put_time_ms: put_id.0, + put_version: put_id.1, + }, + ); } - self.remember_local_snapshot(key, put_id); + self.owner_hot_track_committed(key, put_id, &memory_info, atomic_group); Ok(()) } } @@ -1552,6 +2558,7 @@ pub struct ExternalPendingPutCtx { pub replica_target: Option, pub local_reserve_slot: Option, pub local_reserve_slot_size: Option, + pub atomic_group: Option, } #[derive(Debug, Clone)] @@ -1562,13 +2569,14 @@ pub(crate) struct ReplicaTaskTarget { pub len: u64, } -#[derive(Clone)] pub(crate) struct ReplicaTaskJob { pub key: String, pub put_id: crate::master_kv_router::put::PutIDForAKey, pub holder: Arc, pub target: Option, pub preferred_sub_cluster: Option, + pub hot_replica_guard: Option, + pub protect_source_on_remote_complete: bool, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -1821,6 +2829,7 @@ pub(crate) struct OwnerLocalReserveClassState { pub grants: Vec, pub last_grow_at: Option, pub pending_slot_demand: usize, + pub expected_grant_count: usize, } impl OwnerLocalReserveClassState { @@ -1831,6 +2840,7 @@ impl OwnerLocalReserveClassState { grants: Vec::new(), last_grow_at: None, pending_slot_demand: 0, + expected_grant_count: 0, } } @@ -1850,6 +2860,297 @@ impl OwnerLocalReserveClassState { } } +#[cfg(test)] +mod owner_reclaim_slot_tests { + use super::{ + GetCachedInfo, OwnerHotCacheCounters, OwnerHotCacheEntry, OwnerHotReplicaGuard, + OwnerHotReplicaIdentity, OwnerKeyControlState, OwnerLocalReserveGrantState, + OwnerReclaimRecord, allocate_external_holding_id, build_owner_hot_cache, + clone_if_owner_hot_entry_matches, forget_owner_hot_atomic_group, + owner_hot_tp_cohort_key_rows, register_owner_hot_atomic_group, resolve_local_visible_batch, + }; + use crate::master_kv_router::msg_pack::{ + OwnerReclaimItem, PutAtomicGroup, PutAtomicGroupMember, + }; + use dashmap::{DashMap, DashSet}; + use parking_lot::Mutex; + use std::collections::HashMap; + use std::sync::atomic::{AtomicU64, Ordering}; + use std::sync::{Arc, Weak}; + + #[test] + fn external_holding_ids_are_nonzero_and_unique_for_resident_pages() { + let counter = AtomicU64::new(1); + let first = allocate_external_holding_id(&counter); + let second = allocate_external_holding_id(&counter); + assert_eq!(first, 1); + assert_eq!(second, 2); + assert_ne!(first, second); + } + + #[test] + fn hot_source_pin_requires_the_same_version_and_allocation() { + let current = Arc::new(7u64); + let current_weak = Arc::downgrade(¤t); + let other = Arc::new(7u64); + let other_weak = Arc::downgrade(&other); + + let pinned = clone_if_owner_hot_entry_matches((10, 2), ¤t, (10, 2), ¤t_weak) + .expect("matching source should be pinned"); + assert!(Arc::ptr_eq(&pinned, ¤t)); + assert_eq!(Arc::strong_count(¤t), 2); + drop(pinned); + + assert!( + clone_if_owner_hot_entry_matches((10, 2), ¤t, (10, 3), ¤t_weak).is_none() + ); + assert!( + clone_if_owner_hot_entry_matches((10, 2), ¤t, (10, 2), &other_weak).is_none() + ); + } + + #[test] + fn hot_replica_guard_keeps_dedup_until_terminal_outcome() { + let identity = OwnerHotReplicaIdentity { + key: "hot-key".to_string(), + put_time_ms: 10, + put_version: 2, + }; + let inflight = Arc::new(DashSet::new()); + assert!(inflight.insert(identity.clone())); + let counters = Arc::new(OwnerHotCacheCounters::default()); + let group_replica_triggered = Arc::new(DashSet::new()); + let guard = OwnerHotReplicaGuard::new( + identity.clone(), + inflight.clone(), + counters.clone(), + None, + group_replica_triggered, + ); + assert!(inflight.contains(&identity)); + + guard.mark_completed(); + drop(guard); + assert!(!inflight.contains(&identity)); + assert_eq!(counters.replica_completed.load(Ordering::Relaxed), 1); + assert_eq!(counters.replica_failed.load(Ordering::Relaxed), 0); + } + + #[test] + fn hot_atomic_group_registry_interns_members_and_forgets_as_one_unit() { + let group = PutAtomicGroup { + members: vec![ + PutAtomicGroupMember { + key: "group-a".to_string(), + put_id: (10, 1), + }, + PutAtomicGroupMember { + key: "group-b".to_string(), + put_id: (10, 2), + }, + ], + }; + let atomic_groups = DashMap::new(); + register_owner_hot_atomic_group(&atomic_groups, &group); + register_owner_hot_atomic_group(&atomic_groups, &group); + assert_eq!(atomic_groups.len(), 2); + + let first = OwnerHotReplicaIdentity::from_group_member(&group.members[0]); + let second = OwnerHotReplicaIdentity::from_group_member(&group.members[1]); + let first_group = atomic_groups.get(&first).unwrap().value().clone(); + let second_group = atomic_groups.get(&second).unwrap().value().clone(); + assert!(Arc::ptr_eq(&first_group, &second_group)); + + let triggered = DashSet::new(); + assert!(triggered.insert(first.clone())); + forget_owner_hot_atomic_group(&atomic_groups, &triggered, &second); + assert!(atomic_groups.is_empty()); + assert!(!triggered.contains(&first)); + } + + #[test] + fn owner_hot_tp_cohort_expands_the_same_group_boundary_across_ranks() { + let identity = OwnerHotReplicaIdentity { + key: "page0_model_0_2".to_string(), + put_time_ms: 10, + put_version: 1, + }; + let rank0_group = PutAtomicGroup { + members: vec![ + PutAtomicGroupMember { + key: "page0_model_0_2".to_string(), + put_id: (10, 1), + }, + PutAtomicGroupMember { + key: "page1_model_0_2".to_string(), + put_id: (10, 2), + }, + ], + }; + assert_eq!( + owner_hot_tp_cohort_key_rows(&identity, Some(&rank0_group)), + Ok(Some(vec![ + vec!["page0_model_0_2".to_string(), "page1_model_0_2".to_string(),], + vec!["page0_model_1_2".to_string(), "page1_model_1_2".to_string(),], + ])) + ); + + let mixed_rank_group = PutAtomicGroup { + members: vec![ + rank0_group.members[0].clone(), + PutAtomicGroupMember { + key: "page1_model_1_2".to_string(), + put_id: (11, 2), + }, + ], + }; + assert_eq!( + owner_hot_tp_cohort_key_rows(&identity, Some(&mixed_rank_group)), + Err(()) + ); + } + + #[test] + fn hot_group_trigger_is_persistent_on_success_and_retryable_on_failure() { + let member = OwnerHotReplicaIdentity { + key: "member".to_string(), + put_time_ms: 10, + put_version: 2, + }; + let group_trigger = OwnerHotReplicaIdentity { + key: "anchor".to_string(), + put_time_ms: 10, + put_version: 1, + }; + let inflight = Arc::new(DashSet::new()); + let triggered = Arc::new(DashSet::new()); + let counters = Arc::new(OwnerHotCacheCounters::default()); + + assert!(inflight.insert(member.clone())); + assert!(triggered.insert(group_trigger.clone())); + let failed_guard = OwnerHotReplicaGuard::new( + member.clone(), + inflight.clone(), + counters.clone(), + Some(group_trigger.clone()), + triggered.clone(), + ); + drop(failed_guard); + assert!(!inflight.contains(&member)); + assert!(!triggered.contains(&group_trigger)); + assert_eq!(counters.replica_failed.load(Ordering::Relaxed), 1); + + assert!(inflight.insert(member.clone())); + assert!(triggered.insert(group_trigger.clone())); + let completed_guard = OwnerHotReplicaGuard::new( + member.clone(), + inflight.clone(), + counters.clone(), + Some(group_trigger.clone()), + triggered.clone(), + ); + completed_guard.mark_completed(); + drop(completed_guard); + assert!(!inflight.contains(&member)); + assert!(triggered.contains(&group_trigger)); + assert_eq!(counters.replica_completed.load(Ordering::Relaxed), 1); + } + + #[test] + fn hot_cache_only_dispatches_size_removals_and_keeps_capacity() { + let controls = Arc::new(Mutex::new(HashMap::new())); + let cached = Arc::new(DashMap::::new()); + let inflight = Arc::new(DashSet::new()); + let atomic_groups = Arc::new(DashMap::new()); + let group_replica_triggered = Arc::new(DashSet::new()); + let counters = Arc::new(OwnerHotCacheCounters::default()); + let (tx, mut rx) = limit_thirdparty::tokio::sync::ampsc::channel(8); + let cache = build_owner_hot_cache( + 10, + controls, + cached, + inflight, + atomic_groups, + group_replica_triggered, + counters.clone(), + tx, + ); + let entry = |put_version| OwnerHotCacheEntry { + put_id: (10, put_version), + memory_info: Weak::new(), + weight_bytes: 6, + }; + + cache.insert("explicit".to_string(), entry(0)); + cache.run_pending_tasks(); + cache.invalidate("explicit"); + cache.run_pending_tasks(); + assert_eq!(counters.size_evictions.load(Ordering::Relaxed), 0); + + cache.insert("size-a".to_string(), entry(1)); + cache.insert("size-b".to_string(), entry(2)); + cache.run_pending_tasks(); + assert!(counters.size_evictions.load(Ordering::Relaxed) >= 1); + assert_eq!(cache.policy().max_capacity(), Some(10)); + assert!( + rx.try_recv().is_err(), + "stale weak entries must not dispatch" + ); + } + + #[test] + fn batch_local_visibility_skips_reclaim_fenced_keys() { + let keys = vec![ + "local-a".to_string(), + "fenced".to_string(), + "local-b".to_string(), + ]; + let mut controls = HashMap::new(); + controls.insert( + "fenced".to_string(), + OwnerKeyControlState { + local_puts: 0, + reclaim: Some(OwnerReclaimRecord::Committed(OwnerReclaimItem { + key: "fenced".to_string(), + ..OwnerReclaimItem::default() + })), + }, + ); + let mut resolved_keys = Vec::new(); + + let visible = resolve_local_visible_batch(&keys, &controls, |key| { + resolved_keys.push(key.to_string()); + Some(key.to_string()) + }); + + assert_eq!( + visible, + vec![ + Some("local-a".to_string()), + None, + Some("local-b".to_string()) + ] + ); + assert_eq!(resolved_keys, vec!["local-a", "local-b"]); + } + + #[test] + fn committed_slot_becomes_free_only_after_route_and_holder_are_released() { + let mut grant = OwnerLocalReserveGrantState::new(7, 0, 0, 16, 8, 2); + let slot = grant.claim_prepared_slot().expect("slot should be free"); + grant.mark_prepared_slot_pending_visible(slot.slot_index); + grant.retain_resident_slot_holder(slot.slot_index); + grant.promote_pending_visible_slot_to_committed(slot.slot_index); + + grant.release_committed_slot_route(slot.slot_index); + assert_eq!(grant.free_slots.len(), 1); + + grant.release_resident_slot_holder(slot.slot_index); + assert_eq!(grant.free_slots.len(), 2); + assert!(grant.is_fully_free()); + } +} + #[derive(Debug, Default)] pub(crate) struct OwnerLocalReservePoolState { pub classes: HashMap, @@ -2048,10 +3349,99 @@ impl ClientKvApiInner { external_get_holding_bytes = external_get_holding_bytes.saturating_add(entry.value().memory_info.len as u64); } + let (hot_cache_capacity_bytes, hot_cache_entries, hot_cache_weighted_bytes) = self + .owner_hot_cache + .as_ref() + .map(|cache| { + ( + cache.policy().max_capacity().unwrap_or(0), + cache.entry_count(), + cache.weighted_size(), + ) + }) + .unwrap_or_default(); OwnerRuntimeObserveSnapshot { external_get_holding_entries: self.external_get_holding.total() as u64, external_get_holding_bytes, external_pending_put_entries: self.external_pending_puts.entry_count(), + hot_cache_capacity_bytes, + hot_cache_entries, + hot_cache_weighted_bytes, + hot_size_evictions: self + .owner_hot_counters + .size_evictions + .load(Ordering::Relaxed), + hot_replica_enqueued: self + .owner_hot_counters + .replica_enqueued + .load(Ordering::Relaxed), + hot_replica_completed: self + .owner_hot_counters + .replica_completed + .load(Ordering::Relaxed), + hot_replica_already_satisfied: self + .owner_hot_counters + .replica_already_satisfied + .load(Ordering::Relaxed), + hot_replica_failed: self + .owner_hot_counters + .replica_failed + .load(Ordering::Relaxed), + hot_replica_obsolete: self + .owner_hot_counters + .replica_obsolete + .load(Ordering::Relaxed), + hot_replica_dispatch_failed: self + .owner_hot_counters + .replica_dispatch_failed + .load(Ordering::Relaxed), + hot_replica_inflight: self.owner_hot_replica_inflight.len() as u64, + hot_eviction_skipped_stale: self + .owner_hot_counters + .skipped_stale + .load(Ordering::Relaxed), + hot_eviction_skipped_reclaim: self + .owner_hot_counters + .skipped_reclaim + .load(Ordering::Relaxed), + hot_eviction_skipped_duplicate: self + .owner_hot_counters + .skipped_duplicate + .load(Ordering::Relaxed), + hot_group_registry_entries: self.owner_hot_atomic_groups.len() as u64, + hot_group_replica_triggered: self.owner_hot_group_replica_triggered.len() as u64, + hot_group_replica_triggers: self + .owner_hot_counters + .group_replica_triggers + .load(Ordering::Relaxed), + hot_group_members_enqueued: self + .owner_hot_counters + .group_members_enqueued + .load(Ordering::Relaxed), + hot_group_trigger_duplicates: self + .owner_hot_counters + .group_trigger_duplicates + .load(Ordering::Relaxed), + hot_group_trigger_incomplete: self + .owner_hot_counters + .group_trigger_incomplete + .load(Ordering::Relaxed), + grouped_put_done_batches: self + .owner_hot_counters + .grouped_put_done_batches + .load(Ordering::Relaxed), + grouped_put_done_items: self + .owner_hot_counters + .grouped_put_done_items + .load(Ordering::Relaxed), + legacy_put_done_batches: self + .owner_hot_counters + .legacy_put_done_batches + .load(Ordering::Relaxed), + legacy_put_done_items: self + .owner_hot_counters + .legacy_put_done_items + .load(Ordering::Relaxed), } } @@ -2560,6 +3950,35 @@ impl ClientKvApi { metrics.set_kv_external_pending_put_entries( snapshot.external_pending_put_entries, ); + if snapshot.hot_cache_capacity_bytes > 0 { + tracing::info!( + capacity_bytes = snapshot.hot_cache_capacity_bytes, + entries = snapshot.hot_cache_entries, + weighted_bytes = snapshot.hot_cache_weighted_bytes, + size_evictions = snapshot.hot_size_evictions, + replica_enqueued = snapshot.hot_replica_enqueued, + replica_completed = snapshot.hot_replica_completed, + replica_already_satisfied = snapshot.hot_replica_already_satisfied, + replica_failed = snapshot.hot_replica_failed, + replica_obsolete = snapshot.hot_replica_obsolete, + replica_dispatch_failed = snapshot.hot_replica_dispatch_failed, + replica_inflight = snapshot.hot_replica_inflight, + skipped_stale = snapshot.hot_eviction_skipped_stale, + skipped_reclaim = snapshot.hot_eviction_skipped_reclaim, + skipped_duplicate = snapshot.hot_eviction_skipped_duplicate, + group_registry_entries = snapshot.hot_group_registry_entries, + group_replica_triggered = snapshot.hot_group_replica_triggered, + group_replica_triggers = snapshot.hot_group_replica_triggers, + group_members_enqueued = snapshot.hot_group_members_enqueued, + group_trigger_duplicates = snapshot.hot_group_trigger_duplicates, + group_trigger_incomplete = snapshot.hot_group_trigger_incomplete, + grouped_put_done_batches = snapshot.grouped_put_done_batches, + grouped_put_done_items = snapshot.grouped_put_done_items, + legacy_put_done_batches = snapshot.legacy_put_done_batches, + legacy_put_done_items = snapshot.legacy_put_done_items, + "owner hot replica policy snapshot" + ); + } } } } @@ -2572,26 +3991,57 @@ impl ClientKvApi { pub async fn construct(arg: ClientKvApiNewArg) -> Result { tracing::info!("Constructing ClientKvApi in Client mode (PreView)"); + let ClientKvApiNewArg { + test_spec_config, + owner_hot_cache_capacity_bytes, + } = arg; let (replica_task_tx, replica_task_rx) = tokio::sync::ampsc::channel(REPLICA_TASK_QUEUE_CAPACITY); let (owner_local_publish_tx, owner_local_publish_rx) = tokio::sync::ampsc::channel(OWNER_LOCAL_PUBLISH_QUEUE_CAPACITY); + let (owner_hot_eviction_tx, owner_hot_eviction_rx) = + tokio::sync::ampsc::channel(OWNER_HOT_EVICTION_QUEUE_CAPACITY); + let get_cached_info = Arc::new(DashMap::new()); + let owner_key_control = Arc::new(Mutex::new(HashMap::new())); + let owner_hot_replica_inflight = Arc::new(DashSet::new()); + let owner_hot_atomic_groups = Arc::new(DashMap::new()); + let owner_hot_group_replica_triggered = Arc::new(DashSet::new()); + let owner_hot_counters = Arc::new(OwnerHotCacheCounters::default()); + let owner_hot_cache = owner_hot_cache_capacity_bytes.map(|capacity_bytes| { + build_owner_hot_cache( + capacity_bytes, + owner_key_control.clone(), + get_cached_info.clone(), + owner_hot_replica_inflight.clone(), + owner_hot_atomic_groups.clone(), + owner_hot_group_replica_triggered.clone(), + owner_hot_counters.clone(), + owner_hot_eviction_tx, + ) + }); let inner = ClientKvApiInner { view: ClientKvApiViewHolder::new(), - test_spec_config: arg.test_spec_config, + test_spec_config, metrics: OnceLock::new(), all_memholder_refcount: OnceLock::new(), get_remote_kv_lock: AMapLock::new(Duration::from_secs(60)), - get_cached_info: DashMap::new(), + get_cached_info, precommit_local_visible_info: DashMap::new(), local_snapshot_info: DashMap::new(), owner_local_reserve_pool: Mutex::new(OwnerLocalReservePoolState::default()), + owner_local_reserve_claim_lock: limit_thirdparty::tokio::sync::AMutex::new(()), owner_local_reserve_rebalance_notify: Arc::new( limit_thirdparty::tokio::sync::Notify::new(), ), external_local_first_put_id_counter: AtomicU32::new(0), - external_local_first_inflight_key_counts: DashMap::new(), + owner_key_control, + owner_hot_cache, + owner_hot_replica_inflight, + owner_hot_atomic_groups, + owner_hot_group_replica_triggered, + owner_hot_counters, + owner_hot_eviction_rx: Mutex::new(Some(owner_hot_eviction_rx)), external_invalidate_delete: EnsureMemholderMgmtDeleteHandle::new( OwnerExternalMemMgr::DELETE_SUBMIT_QUEUE_CAPACITY, ), @@ -2603,6 +4053,7 @@ impl ClientKvApi { external_get_start_registry: DashMap::new(), external_get_start_by_key: DashMap::new(), next_external_get_start_handle: AtomicU64::new(1), + next_external_holding_id: AtomicU64::new(1), external_pending_puts: moka::sync::Cache::builder() .time_to_live(Duration::from_secs(30 * 60)) .segments(16) @@ -2621,6 +4072,7 @@ impl ClientKvApi { rpc_caller_batch_put_start: RPCCaller::new(), rpc_caller_batch_put_revoke: RPCCaller::new(), rpc_caller_batch_put_done: RPCCaller::new(), + rpc_caller_grouped_batch_put_done: RPCCaller::new(), rpc_caller_batch_prepare_put_keys: RPCCaller::new(), rpc_caller_batch_release_put_key_reservations: RPCCaller::new(), rpc_caller_put_append_start: RPCCaller::new(), @@ -2678,6 +4130,9 @@ impl ClientKvApi { inner .rpc_caller_batch_put_done .regist(inner.view.p2p_module()); + inner + .rpc_caller_grouped_batch_put_done + .regist(inner.view.p2p_module()); inner .rpc_caller_batch_prepare_put_keys .regist(inner.view.p2p_module()); @@ -2997,6 +4452,39 @@ impl ClientKvApi { }); // client rpc handler register + let view = inner.view.clone_view(); + RPCHandler::::new().regist( + inner.view.p2p_module(), + move |resp, msg| { + let view = view.clone(); + let view_task = view.clone(); + view.spawn("rpc_batch_enqueue_replica_tasks", async move { + let ack = put::handle_batch_enqueue_replica_tasks(&view_task, msg).await; + if let Err(e) = resp.send_resp(ack).await { + warn!("Failed to send BatchEnqueueReplicaTaskResp: {:?}", e); + } + }); + Ok(()) + }, + ); + + let view = inner.view.clone_view(); + RPCHandler::::new().regist( + inner.view.p2p_module(), + move |resp, msg| { + let req_node_id = resp.node_id().clone(); + let view = view.clone(); + let view_task = view.clone(); + view.spawn("rpc_batch_owner_reclaim", async move { + let ack = handle_batch_owner_reclaim(&view_task, msg, req_node_id).await; + if let Err(e) = resp.send_resp(ack).await { + warn!("Failed to send BatchOwnerReclaimResp: {:?}", e); + } + }); + Ok(()) + }, + ); + let view = inner.view.clone_view(); RPCHandler::::new().regist( inner.view.p2p_module(), @@ -3032,10 +4520,27 @@ impl ClientKvApi { delete::spawn_owner_delete_ack_batch(inner.view.clone_view(), delete_ack_batch_rx); if let Some(replica_task_rx) = inner.replica_task_rx.lock().take() { - put::spawn_replica_task_actor(inner.view.clone_view(), replica_task_rx); + put::spawn_replica_task_actor( + inner.view.clone_view(), + replica_task_rx, + inner + .test_spec_config + .replica_task_max_inflight + .unwrap_or(1) as usize, + ); } else { tracing::warn!("replica_task_rx already taken for ClientKvApi"); } + if inner.owner_hot_cache.is_some() { + if let Some(owner_hot_eviction_rx) = inner.owner_hot_eviction_rx.lock().take() { + put::spawn_owner_hot_replica_dispatcher( + inner.view.clone_view(), + owner_hot_eviction_rx, + ); + } else { + tracing::warn!("owner_hot_eviction_rx already taken for ClientKvApi"); + } + } if let Some(owner_local_publish_rx) = inner.owner_local_publish_rx.lock().take() { put::spawn_owner_local_publish_dispatcher( inner.view.clone_view(), diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs index c9c2475..fe83d34 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs @@ -150,6 +150,7 @@ pub struct ExternalBatchGetStartResp { pub error_json: String, pub handle: u64, pub raw_prefix_hit_len: usize, + pub transfer_plan: ExternalBatchGetStartTransferPlan, } impl MsgPackSerializePart for ExternalBatchGetStartResp { fn msg_id(&self) -> u32 { @@ -157,6 +158,15 @@ impl MsgPackSerializePart for ExternalBatchGetStartResp { } } +#[derive(Default, Debug, Clone, Encode, Decode)] +pub enum ExternalBatchGetStartTransferPlan { + #[default] + OwnerRpc, + InlineLocal { + items: Vec, + }, +} + #[derive(Default, Debug, Clone, Encode, Decode)] pub struct ExternalBatchGetTransferReq { pub handle: u64, @@ -191,12 +201,22 @@ pub struct ExternalBatchGetCancelReq { pub req_node_id: String, /// Owner node_start_time observed by external when request starts pub started_time: i64, + pub transfer_plan: ExternalBatchGetCancelPlan, } impl MsgPackSerializePart for ExternalBatchGetCancelReq { fn msg_id(&self) -> u32 { 4034 } } + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub enum ExternalBatchGetCancelPlan { + #[default] + OwnerRpc, + InlineLocal { + holder_ids: Vec, + }, +} impl RPCReq for ExternalBatchGetCancelReq { type Resp = ExternalBatchGetCancelResp; } @@ -212,6 +232,65 @@ impl MsgPackSerializePart for ExternalBatchGetCancelResp { } } +#[cfg(test)] +mod external_batch_get_plan_wire_tests { + use super::{ + ExternalBatchGetCancelPlan, ExternalBatchGetCancelReq, ExternalBatchGetItemResp, + ExternalBatchGetStartResp, ExternalBatchGetStartTransferPlan, + }; + use crate::memholder::ExternalMemHolderInfo; + use crate::rpcresp_kvresult_convert::msg_and_error::OK; + + #[test] + fn inline_start_and_cancel_plans_round_trip() { + let start = ExternalBatchGetStartResp { + error_code: OK, + error_json: String::new(), + handle: 19, + raw_prefix_hit_len: 2, + transfer_plan: ExternalBatchGetStartTransferPlan::InlineLocal { + items: vec![ExternalBatchGetItemResp { + error_code: OK, + error_json: String::new(), + external_memholder_info: Some(ExternalMemHolderInfo { + offset: 4096, + len: 8192, + holder_id: 23, + }), + }], + }, + }; + let decoded_start: ExternalBatchGetStartResp = + bitcode::decode(&bitcode::encode(&start)).expect("decode inline start plan"); + assert_eq!(decoded_start.handle, 19); + assert!(matches!( + decoded_start.transfer_plan, + ExternalBatchGetStartTransferPlan::InlineLocal { items } + if items.len() == 1 + && items[0] + .external_memholder_info + .as_ref() + .is_some_and(|info| info.holder_id == 23) + )); + + let cancel = ExternalBatchGetCancelReq { + handle: 19, + req_node_id: "external-a".to_string(), + started_time: 29, + transfer_plan: ExternalBatchGetCancelPlan::InlineLocal { + holder_ids: vec![23, 24], + }, + }; + let decoded_cancel: ExternalBatchGetCancelReq = + bitcode::decode(&bitcode::encode(&cancel)).expect("decode inline cancel plan"); + assert!(matches!( + decoded_cancel.transfer_plan, + ExternalBatchGetCancelPlan::InlineLocal { holder_ids } + if holder_ids == vec![23, 24] + )); + } +} + #[derive(Default, Debug, Clone, Encode, Decode)] pub struct ExternalBatchPutStartItemReq { pub key: String, @@ -225,6 +304,8 @@ pub struct ExternalBatchPutStartItemReq { #[derive(Default, Debug, Clone, Encode, Decode)] pub struct ExternalBatchPutStartReq { pub items: Vec, + /// Positive lengths partitioning `items`; omitted means one group per item. + pub atomic_group_lens: Option>, /// Owner node_start_time observed by external when request starts pub started_time: i64, } diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs index fd309b3..1171c65 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs @@ -1,6 +1,7 @@ use super::{ - ClientKvApiInner, OwnerLocalReserveClassState, OwnerLocalReserveGrantState, - OwnerLocalReservePoolState, OwnerLocalReserveSlotLease, ReplicaTaskJob, ReplicaTaskTarget, + ClientKvApiInner, OwnerHotEvictionEvent, OwnerLocalReserveClassState, + OwnerLocalReserveGrantState, OwnerLocalReservePoolState, OwnerLocalReserveSlotLease, + OwnerLocalReserveSlotRef, ReplicaTaskJob, ReplicaTaskTarget, local_reserve_rebalance::{owner_local_reserve_timeout_config, wait_owner_local_reserve_ready}, }; use crate::OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES; @@ -15,13 +16,16 @@ use crate::observe_kvope::{ use crate::{ client_kv_api::ClientKvApiView, master_kv_router::msg_pack::{ - BatchPreparePutKeyItemReq, BatchPreparePutKeysReq, BatchPreparePutKeysResp, - BatchPutDoneItemReq, BatchPutDoneReq, BatchPutDoneResp, BatchPutRevokeItemReq, - BatchPutRevokeReq, BatchPutRevokeResp, BatchPutStartItemReq, BatchPutStartReq, - BatchPutStartResp, BatchReleasePutKeyReservationsReq, BatchReleasePutKeyReservationsResp, - PutAppendDoneReq, PutAppendDoneResp, PutAppendRevokeReq, PutAppendStartReq, - PutAppendStartResp, PutDoneCommittedSlot, PutDoneReq, PutRevokeReq, PutStartReq, - PutStartResp, ReleaseLocalGrantReq, ReserveLocalGrantReq, ReserveLocalGrantResp, + BatchEnqueueReplicaTaskReq, BatchEnqueueReplicaTaskResp, BatchPreparePutKeyItemReq, + BatchPreparePutKeysReq, BatchPreparePutKeysResp, BatchPutDoneItemReq, BatchPutDoneReq, + BatchPutDoneResp, BatchPutRevokeItemReq, BatchPutRevokeReq, BatchPutRevokeResp, + BatchPutStartItemReq, BatchPutStartReq, BatchPutStartResp, + BatchReleasePutKeyReservationsReq, BatchReleasePutKeyReservationsResp, + EnqueueReplicaTaskItemResp, GroupedBatchPutDoneItemReq, GroupedBatchPutDoneReq, + GroupedBatchPutDoneResp, PutAppendDoneReq, PutAppendDoneResp, PutAppendRevokeReq, + PutAppendStartReq, PutAppendStartResp, PutAtomicGroup, PutDoneCommittedSlot, PutDoneReq, + PutRevokeReq, PutStartReq, PutStartResp, ReleaseLocalGrantReq, ReserveLocalGrantOutcome, + ReserveLocalGrantReq, }, memholder::{UserMemHolder, UserMemHolderExposeKind}, p2p::msg_pack::MsgPack, @@ -30,40 +34,30 @@ use crate::{ }; use chrono::Utc; use fluxon_commu::TransferBreakdown; +use fluxon_util::semaphore_map::SemaphoreMap; use limit_thirdparty::tokio; -use std::sync::Arc; -use std::time::Instant; +use std::sync::{Arc, atomic::Ordering}; +use std::time::{Duration, Instant}; use tracing::info; fn duration_to_i64_us(duration: std::time::Duration) -> i64 { duration.as_micros().min(i64::MAX as u128) as i64 } -const OWNER_LOCAL_RESERVE_MIN_SLOT_SIZE_BYTES: u64 = 4 * 1024; fn owner_local_reserve_slot_size(value_len: u64) -> KvResult { - let normalized = value_len.max(OWNER_LOCAL_RESERVE_MIN_SLOT_SIZE_BYTES); - let slot_size = normalized.checked_next_power_of_two().ok_or_else(|| { + crate::owner_local_reserve_slot_size_bytes(value_len).ok_or_else(|| { KvError::Api(ApiError::InvalidArgument { detail: format!( - "value_len={} exceeds resident local reserve slot size range", - value_len + "value_len={} cannot be represented by a resident local-reserve slot no larger than {} bytes", + value_len, OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES ), }) - })?; - if slot_size > OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES { - return Err(KvError::Api(ApiError::InvalidArgument { - detail: format!( - "value_len={} requires slot_size={} larger than local reserve grant quantum={}", - value_len, slot_size, OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES - ), - })); - } - Ok(slot_size) + }) } fn owner_local_reserve_slots_per_grant(slot_size: u64) -> u32 { - let slots = (OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES / slot_size).max(1); - slots.min(u32::MAX as u64) as u32 + crate::owner_local_reserve_slots_per_grant(slot_size) + .expect("validated local-reserve slot size must fit in a grant") } fn owner_local_reserve_install_grant( @@ -94,34 +88,319 @@ fn owner_local_reserve_try_claim( value_len: u64, key_count: usize, ) -> Option { - let class_state = pool + let free_slots = pool .classes .entry(slot_size) - .or_insert_with(|| OwnerLocalReserveClassState::new(slot_size, slots_per_grant)); - if class_state.free_slot_count() < key_count { + .or_insert_with(|| OwnerLocalReserveClassState::new(slot_size, slots_per_grant)) + .free_slot_count(); + if free_slots < key_count { return None; } - let mut slots = Vec::with_capacity(key_count); + let slots = owner_local_reserve_claim_available(pool, slot_size, slots_per_grant, key_count); + assert_eq!( + slots.len(), + key_count, + "free_slot_count check and claim path diverged" + ); + Some(OwnerLocalReserveSlotLease { + value_len, + slot_size, + slots, + }) +} + +fn owner_local_reserve_claim_available( + pool: &mut OwnerLocalReservePoolState, + slot_size: u64, + slots_per_grant: u32, + max_slots: usize, +) -> Vec { + let class_state = pool + .classes + .entry(slot_size) + .or_insert_with(|| OwnerLocalReserveClassState::new(slot_size, slots_per_grant)); + let claim_count = class_state.free_slot_count().min(max_slots); + let mut slots = Vec::with_capacity(claim_count); for grant in class_state.grants.iter_mut() { - while slots.len() < key_count { + while slots.len() < claim_count { match grant.claim_prepared_slot() { Some(slot) => slots.push(slot), None => break, } } - if slots.len() == key_count { + if slots.len() == claim_count { break; } } - assert!( - slots.len() == key_count, + assert_eq!( + slots.len(), + claim_count, "free_slot_count check and claim path diverged" ); - Some(OwnerLocalReserveSlotLease { - value_len, - slot_size, - slots, - }) + slots +} + +struct OwnerLocalReservePendingDemandGuard<'a> { + inner: &'a ClientKvApiInner, + slot_size: u64, + slots_per_grant: u32, + pending_slots: usize, +} + +impl<'a> OwnerLocalReservePendingDemandGuard<'a> { + fn new( + inner: &'a ClientKvApiInner, + slot_size: u64, + slots_per_grant: u32, + pending_slots: usize, + ) -> Self { + inner.owner_local_reserve_register_pending_demand( + slot_size, + slots_per_grant, + pending_slots, + ); + Self { + inner, + slot_size, + slots_per_grant, + pending_slots, + } + } + + fn consume(&mut self) { + if self.pending_slots == 0 { + return; + } + self.inner.owner_local_reserve_consume_pending_demand( + self.slot_size, + self.slots_per_grant, + self.pending_slots, + ); + self.pending_slots = 0; + self.inner + .owner_local_reserve_rebalance_notify() + .notify_waiters(); + } + + fn disarm_after_locked_consume(&mut self) { + assert!( + self.pending_slots > 0, + "pending-demand guard was already consumed" + ); + self.pending_slots = 0; + self.inner + .owner_local_reserve_rebalance_notify() + .notify_waiters(); + } +} + +impl Drop for OwnerLocalReservePendingDemandGuard<'_> { + fn drop(&mut self) { + self.consume(); + } +} + +#[cfg(test)] +mod local_reserve_claim_tests { + use super::{ + OwnerLocalReserveGrantState, OwnerLocalReservePoolState, + owner_local_reserve_claim_available, owner_local_reserve_install_grant, + owner_local_reserve_slot_size, owner_local_reserve_slots_per_grant, + }; + use crate::client_kv_api::{ClientKvApi, ClientKvApiNewArg}; + use crate::config::TestSpecConfig; + use std::sync::Arc; + use std::time::Duration; + + #[test] + fn slot_size_uses_page_aligned_exact_fit() { + const SGLANG_KV_PAGE_BYTES: u64 = 4_718_592; + + let slot_size = owner_local_reserve_slot_size(SGLANG_KV_PAGE_BYTES).unwrap(); + assert_eq!(slot_size, SGLANG_KV_PAGE_BYTES); + assert_eq!(owner_local_reserve_slots_per_grant(slot_size), 113); + assert_eq!(owner_local_reserve_slot_size(4_097).unwrap(), 8_192); + } + + #[test] + fn partial_claim_keeps_progress_for_large_waiters() { + let mut pool = OwnerLocalReservePoolState::default(); + owner_local_reserve_install_grant( + &mut pool, + 8, + 4, + OwnerLocalReserveGrantState::new(1, 1000, 1000, 32, 8, 4), + ); + + let first = owner_local_reserve_claim_available(&mut pool, 8, 4, 3); + assert_eq!(first.len(), 3); + assert_eq!(pool.classes.get(&8).unwrap().free_slot_count(), 1); + + let second = owner_local_reserve_claim_available(&mut pool, 8, 4, 3); + assert_eq!(second.len(), 1); + assert_eq!(pool.classes.get(&8).unwrap().free_slot_count(), 0); + } + + #[limit_thirdparty::tokio::test] + async fn later_waiter_cannot_steal_slot_before_current_claim_turn_completes() { + const SLOT_SIZE: u64 = 4 * 1024; + const SLOTS_PER_GRANT: u32 = 4; + + let api = Arc::new( + ClientKvApi::construct(ClientKvApiNewArg { + test_spec_config: TestSpecConfig::default(), + owner_hot_cache_capacity_bytes: None, + }) + .await + .expect("construct test ClientKvApi"), + ); + { + let mut pool = api.inner().owner_local_reserve_pool.lock(); + owner_local_reserve_install_grant( + &mut pool, + SLOT_SIZE, + SLOTS_PER_GRANT, + OwnerLocalReserveGrantState::new( + 1, + 1000, + 1000, + SLOT_SIZE * u64::from(SLOTS_PER_GRANT), + SLOT_SIZE, + SLOTS_PER_GRANT, + ), + ); + } + + // Model a five-slot waiter that has made partial progress while owning the claim turn. + let current_claim_turn = api.inner().owner_local_reserve_claim_lock.lock().await; + let first_partial = { + let mut pool = api.inner().owner_local_reserve_pool.lock(); + owner_local_reserve_claim_available(&mut pool, SLOT_SIZE, SLOTS_PER_GRANT, 3) + }; + assert_eq!(first_partial.len(), 3); + + // A later one-slot request must queue even though one slot is currently free. + let later_api = Arc::clone(&api); + let mut later_waiter = tokio::spawn(async move { + later_api + .inner() + .owner_claim_local_reserve_slot_lease(SLOT_SIZE, 1) + .await + }); + assert!( + limit_thirdparty::tokio::time::timeout(Duration::from_millis(25), &mut later_waiter,) + .await + .is_err(), + "later waiter bypassed the active claim turn" + ); + assert_eq!( + api.inner() + .owner_local_reserve_pool + .lock() + .classes + .get(&SLOT_SIZE) + .unwrap() + .free_slot_count(), + 1, + "later waiter stole the current waiter's remaining free slot" + ); + + // Refill lets the current waiter reach all five slots before handing off the turn. + let first_remainder = { + let mut pool = api.inner().owner_local_reserve_pool.lock(); + owner_local_reserve_install_grant( + &mut pool, + SLOT_SIZE, + SLOTS_PER_GRANT, + OwnerLocalReserveGrantState::new( + 2, + 2000, + 2000, + SLOT_SIZE * u64::from(SLOTS_PER_GRANT), + SLOT_SIZE, + SLOTS_PER_GRANT, + ), + ); + owner_local_reserve_claim_available(&mut pool, SLOT_SIZE, SLOTS_PER_GRANT, 2) + }; + assert_eq!(first_partial.len() + first_remainder.len(), 5); + drop(current_claim_turn); + + let later_lease = + limit_thirdparty::tokio::time::timeout(Duration::from_secs(1), later_waiter) + .await + .expect("later waiter did not receive the next claim turn") + .expect("later waiter task panicked") + .expect("later waiter failed to claim a free slot"); + assert_eq!(later_lease.slots.len(), 1); + } + + #[limit_thirdparty::tokio::test] + async fn queued_claims_publish_aggregate_demand_and_cancel_cleanly() { + const SLOT_SIZE: u64 = 4 * 1024; + const SLOTS_PER_GRANT: u32 = 4; + + let api = Arc::new( + ClientKvApi::construct(ClientKvApiNewArg { + test_spec_config: TestSpecConfig::default(), + owner_hot_cache_capacity_bytes: None, + }) + .await + .expect("construct test ClientKvApi"), + ); + let claim_turn = api.inner().owner_local_reserve_claim_lock.lock().await; + + let first_api = Arc::clone(&api); + let first = tokio::spawn(async move { + first_api + .inner() + .owner_claim_local_reserve_slot_lease(SLOT_SIZE, 3) + .await + }); + let second_api = Arc::clone(&api); + let second = tokio::spawn(async move { + second_api + .inner() + .owner_claim_local_reserve_slot_lease(SLOT_SIZE, 2) + .await + }); + + limit_thirdparty::tokio::time::timeout(Duration::from_secs(1), async { + loop { + let pending = api + .inner() + .owner_local_reserve_pool + .lock() + .classes + .get(&SLOT_SIZE) + .map(|class| class.pending_slot_demand) + .unwrap_or_default(); + if pending == 5 { + break; + } + limit_thirdparty::tokio::task::yield_now().await; + } + }) + .await + .expect("queued claims did not publish aggregate demand"); + + first.abort(); + second.abort(); + let _ = first.await; + let _ = second.await; + assert_eq!( + api.inner() + .owner_local_reserve_pool + .lock() + .classes + .get(&SLOT_SIZE) + .unwrap() + .pending_slot_demand, + 0, + "cancelled queued claims leaked pending demand" + ); + drop(claim_turn); + } } #[derive(Debug, Clone)] @@ -149,6 +428,7 @@ pub struct OwnerLocalPublishItem { pub committed_slot: PutDoneCommittedSlot, pub make_replica_task: bool, pub preferred_sub_cluster: Option, + pub atomic_group: Option, } #[derive(Debug, Clone)] @@ -168,6 +448,49 @@ pub struct PutEndWithLocalCachePublish { pub local_cache_holder_id: Option, } +fn owner_local_reserve_timeout_error( + inner: &ClientKvApiInner, + stage: &'static str, + slot_size: u64, + key_count: usize, + soft_wait_timeout: std::time::Duration, + hard_wait_timeout: std::time::Duration, + request_started_at: Instant, +) -> KvError { + let (used_slots, free_slots, pending_slots, grants, expected_grants) = { + let pool = inner.owner_local_reserve_pool.lock(); + pool.classes + .get(&slot_size) + .map(|class_state| { + ( + class_state.used_slot_count(), + class_state.free_slot_count(), + class_state.pending_slot_demand, + class_state.grant_count(), + class_state.expected_grant_count, + ) + }) + .unwrap_or((0, 0, 0, 0, 0)) + }; + KvError::Api(ApiError::Unknown { + detail: format!( + "owner local reserve refill timeout: stage={} slot_size={} key_count={} remaining_slots={} used_slots={} free_slots={} pending_slots={} grants={} expected_grants={} waited_ms={} soft_wait_timeout_ms={} hard_timeout_ms={}", + stage, + slot_size, + key_count, + key_count.saturating_sub(free_slots), + used_slots, + free_slots, + pending_slots, + grants, + expected_grants, + request_started_at.elapsed().as_millis(), + soft_wait_timeout.as_millis(), + hard_wait_timeout.as_millis() + ), + }) +} + impl ClientKvApiInner { pub async fn owner_claim_local_reserve_slot_lease( &self, @@ -177,93 +500,100 @@ impl ClientKvApiInner { let slot_size = owner_local_reserve_slot_size(value_len)?; let slots_per_grant = owner_local_reserve_slots_per_grant(slot_size); let (soft_wait_timeout, hard_wait_timeout) = owner_local_reserve_timeout_config(self); - let hard_deadline = Instant::now() + let request_started_at = Instant::now(); + let hard_deadline = request_started_at .checked_add(hard_wait_timeout) .ok_or_else(|| { KvError::Api(ApiError::Unknown { detail: "owner local reserve hard timeout overflow".to_string(), }) })?; - let mut pending_demand_registered = false; - let claim_result = { - let mut pool = self.owner_local_reserve_pool.lock(); - let class_state = pool - .classes - .entry(slot_size) - .or_insert_with(|| OwnerLocalReserveClassState::new(slot_size, slots_per_grant)); - if class_state.free_slot_count() >= key_count { - Some(owner_local_reserve_try_claim( - &mut pool, - slot_size, - slots_per_grant, - value_len, - key_count, - )) - } else { - None - } - }; - if let Some(Some(lease)) = claim_result { - return Ok(lease); - } - self.owner_local_reserve_register_pending_demand(slot_size, slots_per_grant, key_count); - pending_demand_registered = true; + // Publish demand before waiting for the FIFO turn so one refill can cover all queued + // claimants. The guard also removes demand if the caller is cancelled while queued. + let mut pending_demand = + OwnerLocalReservePendingDemandGuard::new(self, slot_size, slots_per_grant, key_count); self.owner_local_reserve_rebalance_notify().notify_waiters(); - if !wait_owner_local_reserve_ready( - self, - slot_size, - slots_per_grant, - key_count, - soft_wait_timeout, - hard_deadline, + + let Some(remaining_for_turn) = hard_deadline.checked_duration_since(Instant::now()) else { + return Err(owner_local_reserve_timeout_error( + self, + "claim_turn", + slot_size, + key_count, + soft_wait_timeout, + hard_wait_timeout, + request_started_at, + )); + }; + let _claim_turn = match tokio::time::timeout( + remaining_for_turn, + self.owner_local_reserve_claim_lock.lock(), ) .await { - let soft_wait_timeout_ms = soft_wait_timeout.as_millis(); - let hard_wait_timeout_ms = hard_wait_timeout.as_millis(); - if pending_demand_registered { - self.owner_local_reserve_consume_pending_demand( + Ok(claim_turn) => claim_turn, + Err(_) => { + return Err(owner_local_reserve_timeout_error( + self, + "claim_turn", slot_size, - slots_per_grant, key_count, - ); + soft_wait_timeout, + hard_wait_timeout, + request_started_at, + )); } - return Err(KvError::Api(ApiError::Unknown { - detail: format!( - "owner local reserve refill timeout: slot_size={} key_count={} soft_wait_timeout_ms={} hard_timeout_ms={}", - slot_size, key_count, soft_wait_timeout_ms, hard_wait_timeout_ms - ), - })); - } - let claim_result = { - let mut pool = self.owner_local_reserve_pool.lock(); - let class_state = pool - .classes - .entry(slot_size) - .or_insert_with(|| OwnerLocalReserveClassState::new(slot_size, slots_per_grant)); - if class_state.free_slot_count() >= key_count { - Some(owner_local_reserve_try_claim( + }; + + loop { + let claim = { + let mut pool = self.owner_local_reserve_pool.lock(); + let claim = owner_local_reserve_try_claim( &mut pool, slot_size, slots_per_grant, value_len, key_count, - )) - } else { - None + ); + if claim.is_some() { + let class_state = pool + .classes + .get_mut(&slot_size) + .expect("claimed local-reserve class must exist"); + class_state.pending_slot_demand = class_state + .pending_slot_demand + .checked_sub(key_count) + .expect("claimed local-reserve demand underflow"); + } + claim + }; + if let Some(lease) = claim { + pending_demand.disarm_after_locked_consume(); + return Ok(lease); + } + self.owner_local_reserve_rebalance_notify().notify_waiters(); + if !wait_owner_local_reserve_ready( + self, + slot_size, + slots_per_grant, + key_count, + soft_wait_timeout, + hard_deadline, + ) + .await + { + break; } - }; - if let Some(Some(lease)) = claim_result { - self.owner_local_reserve_consume_pending_demand(slot_size, slots_per_grant, key_count); - return Ok(lease); } - self.owner_local_reserve_consume_pending_demand(slot_size, slots_per_grant, key_count); - Err(KvError::Api(ApiError::Unknown { - detail: format!( - "owner local reserve ready check returned without available slots: slot_size={} key_count={}", - slot_size, key_count - ), - })) + Err(owner_local_reserve_timeout_error( + self, + "refill", + slot_size, + key_count, + soft_wait_timeout, + hard_wait_timeout, + request_started_at, + )) } pub async fn owner_release_local_reserve_slot_lease( @@ -627,6 +957,7 @@ impl ClientKvApiInner { lease_id: pending.item.lease_id, committed_slot: None, publish_local_cache: false, + atomic_group: None, }) .collect::>(); let done_resp = self.batch_put_done(done_req_items).await?; @@ -846,6 +1177,7 @@ impl ClientKvApiInner { lease_id: pending.lease_id, committed_slot: None, publish_local_cache: false, + atomic_group: None, }) .collect::>(); let done_resp = self.batch_put_done(done_req_items).await?; @@ -908,9 +1240,9 @@ impl ClientKvApiInner { put_id: PutIDForAKey, target: ReplicaTaskTarget, ) -> KvResult<()> { - let Some(memory_info) = self.local_visible_mem_holder(key) else { + let Some(memory_info) = self.local_committed_mem_holder_for_put_id(key, put_id) else { tracing::warn!( - "replica task source holder is unavailable after local commit; dropping replica task: key={} put_id=({},{})", + "replica task source holder is unavailable or version-mismatched after local commit; dropping replica task: key={} put_id=({},{})", key, put_id.0, put_id.1 @@ -924,17 +1256,25 @@ impl ClientKvApiInner { UserMemHolderExposeKind::SegPtr, )); - match self.replica_task_tx.try_send(ReplicaTaskJob { - key: key.to_string(), - put_id, - holder, - target: Some(target), - preferred_sub_cluster: None, - }) { + // A full queue must apply backpressure. Dropping a promised replica task leaves a + // local-only committed slot that reserve reclaim cannot safely release. + match self + .replica_task_tx + .send(ReplicaTaskJob { + key: key.to_string(), + put_id, + holder, + target: Some(target), + preferred_sub_cluster: None, + hot_replica_guard: None, + protect_source_on_remote_complete: true, + }) + .await + { Ok(()) => Ok(()), Err(err) => { tracing::warn!( - "replica task actor enqueue failed; dropping replica task: key={} put_id=({},{}) err={}", + "replica task actor queue closed; local-only commit remains valid: key={} put_id=({},{}) err={}", key, put_id.0, put_id.1, @@ -950,15 +1290,16 @@ impl ClientKvApiInner { key: &str, put_id: PutIDForAKey, preferred_sub_cluster: Option, - ) -> KvResult<()> { - let Some(memory_info) = self.local_visible_mem_holder(key) else { + protect_source_on_remote_complete: bool, + ) -> KvResult { + let Some(memory_info) = self.local_committed_mem_holder_for_put_id(key, put_id) else { tracing::warn!( - "replica append task source holder is unavailable after local publish; dropping replica task: key={} put_id=({},{})", + "replica append task source holder is unavailable or version-mismatched after local publish; dropping replica task: key={} put_id=({},{})", key, put_id.0, put_id.1 ); - return Ok(()); + return Ok(false); }; let holder = Arc::new(UserMemHolder::new( @@ -967,23 +1308,30 @@ impl ClientKvApiInner { UserMemHolderExposeKind::SegPtr, )); - match self.replica_task_tx.try_send(ReplicaTaskJob { - key: key.to_string(), - put_id, - holder, - target: None, - preferred_sub_cluster, - }) { - Ok(()) => Ok(()), + // Preserve append tasks under burst load for the same reclaim-safety reason above. + match self + .replica_task_tx + .send(ReplicaTaskJob { + key: key.to_string(), + put_id, + holder, + target: None, + preferred_sub_cluster, + hot_replica_guard: None, + protect_source_on_remote_complete, + }) + .await + { + Ok(()) => Ok(true), Err(err) => { tracing::warn!( - "replica append task actor enqueue failed; dropping replica task: key={} put_id=({},{}) err={}", + "replica append task actor queue closed; local-only commit remains valid: key={} put_id=({},{}) err={}", key, put_id.0, put_id.1, err ); - Ok(()) + Ok(false) } } } @@ -1460,14 +1808,23 @@ impl ClientKvApiInner { .await } - pub async fn reserve_local_grant(&self) -> KvResult { + pub async fn reserve_local_grant( + &self, + slot_size: u64, + required_free_slots: u32, + reclaim_before_grow: bool, + ) -> KvResult { if !self.view.register_shutdown_poller().is_running() { return Err(KvError::Api(ApiError::SystemShutdown { detail: "ClientKvApi is shutting down; rejecting reserve_local_grant".to_string(), })); } let req = MsgPack { - serialize_part: ReserveLocalGrantReq::default(), + serialize_part: ReserveLocalGrantReq { + slot_size, + required_free_slots, + reclaim_before_grow, + }, raw_bytes: Vec::new(), }; let master_node_id = self @@ -1490,7 +1847,12 @@ impl ClientKvApiInner { resp.serialize_part.error_code, resp.serialize_part.error_json.clone(), )?; - Ok(resp.serialize_part) + match resp.serialize_part.outcome { + ReserveLocalGrantOutcome::None => Err(KvError::Api(ApiError::Unknown { + detail: "reserve_local_grant returned success without an outcome".to_string(), + })), + outcome => Ok(outcome), + } } pub async fn release_local_grant(&self, grant_id: u64) -> KvResult<()> { @@ -1571,6 +1933,8 @@ impl ClientKvApiInner { put_id: PutIDForAKey, len: u32, preferred_sub_cluster: Option<&str>, + demote_source_on_remote_complete: bool, + protect_source_on_remote_complete: bool, ) -> KvResult { if !self.view.register_shutdown_poller().is_running() { return Err(KvError::Api(ApiError::SystemShutdown { @@ -1583,6 +1947,8 @@ impl ClientKvApiInner { put_id, len: len as u64, preferred_sub_cluster: preferred_sub_cluster.map(|s| s.to_string()), + demote_source_on_remote_complete, + protect_source_on_remote_complete, }, raw_bytes: Vec::new(), }; @@ -1897,6 +2263,56 @@ impl ClientKvApiInner { Ok(resp.serialize_part) } + pub async fn grouped_batch_put_done( + &self, + items: Vec, + atomic_group_lens: Vec, + ) -> KvResult { + if items.is_empty() { + return Ok(GroupedBatchPutDoneResp { + items: Vec::new(), + error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + }); + } + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting grouped_batch_put_done" + .to_string(), + })); + } + let req = MsgPack { + serialize_part: GroupedBatchPutDoneReq { + items, + atomic_group_lens, + }, + raw_bytes: Vec::new(), + }; + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let resp = self + .rpc_caller_grouped_batch_put_done + .call_with_transport_policy( + self.view.p2p_module(), + master_node_id.into(), + req, + Some(std::time::Duration::from_secs(60)), + RpcTransportPolicy::ForceTransport, + 0, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + Ok(resp.serialize_part) + } + /// 完成 Put 操作,提交数据(inner,无监控) pub async fn put_end_inner( &self, @@ -1916,6 +2332,7 @@ impl ClientKvApiInner { lease_id, committed_slot: None, publish_local_cache: false, + atomic_group: None, }, raw_bytes: Vec::new(), }; @@ -1971,6 +2388,7 @@ impl ClientKvApiInner { lease_id, committed_slot: None, publish_local_cache, + atomic_group: None, }, raw_bytes: Vec::new(), }; @@ -2068,145 +2486,402 @@ impl ClientKvApiInner { } } -pub fn spawn_replica_task_actor( +const OWNER_HOT_APPEND_START_MAX_ATTEMPTS: usize = 3; + +fn replica_append_demotes_source_on_remote_complete(is_owner_hot: bool) -> bool { + // Owner-hot eviction is an exclusive tier transition after the remote cohort is recoverable. + // Ordinary replica and tier-1 append tasks remain inclusive. + is_owner_hot +} + +#[cfg(test)] +mod owner_hot_replica_policy_tests { + use super::{ + OwnerLocalPublishItem, complete_owner_local_publish_group_lens, + replica_append_demotes_source_on_remote_complete, + }; + use crate::master_kv_router::msg_pack::{ + PutAtomicGroup, PutAtomicGroupMember, PutDoneCommittedSlot, + }; + + #[test] + fn owner_hot_replication_is_exclusive_after_remote_completion() { + assert!(replica_append_demotes_source_on_remote_complete(true)); + assert!(!replica_append_demotes_source_on_remote_complete(false)); + } + + fn publish_item( + key: &str, + put_id: (u64, u32), + atomic_group: Option, + ) -> OwnerLocalPublishItem { + OwnerLocalPublishItem { + key: key.to_string(), + put_id, + value_len: 1, + lease_id: None, + committed_slot: PutDoneCommittedSlot::default(), + make_replica_task: false, + preferred_sub_cluster: None, + atomic_group, + } + } + + #[test] + fn grouped_publish_partition_requires_a_complete_ordered_group() { + let group = PutAtomicGroup { + members: vec![ + PutAtomicGroupMember { + key: "a".to_string(), + put_id: (1, 0), + }, + PutAtomicGroupMember { + key: "b".to_string(), + put_id: (1, 1), + }, + PutAtomicGroupMember { + key: "c".to_string(), + put_id: (1, 2), + }, + ], + }; + let complete = vec![ + publish_item("a", (1, 0), Some(group.clone())), + publish_item("b", (1, 1), Some(group.clone())), + publish_item("c", (1, 2), Some(group.clone())), + publish_item("single", (2, 0), None), + ]; + assert_eq!( + complete_owner_local_publish_group_lens(&complete), + Some(vec![3, 1]) + ); + + let partial = vec![ + publish_item("a", (1, 0), Some(group.clone())), + publish_item("b", (1, 1), Some(group)), + ]; + assert_eq!(complete_owner_local_publish_group_lens(&partial), None); + } +} + +async fn start_replica_append_with_retry( + inner: &ClientKvApiInner, + job: &ReplicaTaskJob, + len: u32, +) -> KvResult { + let max_attempts = if job.hot_replica_guard.is_some() { + OWNER_HOT_APPEND_START_MAX_ATTEMPTS + } else { + 1 + }; + let mut attempt = 1usize; + loop { + match inner + .put_append_start( + &job.key, + job.put_id, + len, + job.preferred_sub_cluster.as_deref(), + replica_append_demotes_source_on_remote_complete(job.hot_replica_guard.is_some()), + job.protect_source_on_remote_complete, + ) + .await + { + Ok(resp) => return Ok(resp), + Err(err) + if attempt < max_attempts + && matches!(err, KvError::Api(ApiError::KeyBeingWritten { .. })) => + { + tracing::warn!( + "owner hot replica append start failed; retrying: key={} put_id=({},{}) attempt={}/{} err={}", + job.key, + job.put_id.0, + job.put_id.1, + attempt, + max_attempts, + err + ); + let delay_ms = 25u64.saturating_mul(1u64 << (attempt - 1)); + tokio::time::sleep(Duration::from_millis(delay_ms)).await; + attempt += 1; + } + Err(err) => return Err(err), + } + } +} + +pub fn spawn_owner_hot_replica_dispatcher( view: ClientKvApiView, - mut rx: tokio::sync::ampsc::Receiver, + mut rx: tokio::sync::ampsc::Receiver, ) { let view_task = view.clone(); - let _ = view.spawn("replica_task_actor", async move { + let _ = view.spawn("owner_hot_replica_dispatcher", async move { let mut shutdown_waiter = view_task.register_shutdown_waiter(); loop { - let job = tokio::select! { + let event = tokio::select! { _ = shutdown_waiter.wait() => { - tracing::info!("replica_task_actor stopping due to shutdown signal"); + tracing::info!("owner_hot_replica_dispatcher stopping due to shutdown signal"); break; } - job = rx.recv() => { - match job { - Some(job) => job, + event = rx.recv() => { + match event { + Some(event) => event, None => break, } } }; let inner = view_task.client_kv_api().inner(); - let src_offset = job.holder.memory_info().offset; - let len = job.holder.get_length() as u64; - let target = if let Some(target) = job.target.clone() { - target - } else { - let len_u32 = match u32::try_from(len) { - Ok(len_u32) => len_u32, - Err(_) => { - tracing::warn!( - "replica append task length does not fit u32: key={} put_id=({},{}) len={}", - job.key, - job.put_id.0, - job.put_id.1, - len - ); - continue; - } - }; - let append_start = match inner - .put_append_start( - &job.key, - job.put_id, - len_u32, - job.preferred_sub_cluster.as_deref(), - ) - .await - { - Ok(resp) => resp, - Err(err) => { - tracing::warn!( - "replica append task start failed: key={} put_id=({},{}) err={}", - job.key, - job.put_id.0, - job.put_id.1, - err - ); - continue; - } - }; - if !append_start.scheduled { - tracing::debug!( - "replica append task not scheduled: key={} put_id=({},{})", - job.key, - job.put_id.0, - job.put_id.1 - ); - continue; - } - ReplicaTaskTarget { - node_id: append_start.node_id, - target_offset: append_start.target_addr - append_start.target_base_addr, - target_base_addr: append_start.target_base_addr, - len: append_start.len, - } + let Some(memory_info) = event.memory_info.upgrade() else { + event.guard.mark_obsolete(); + continue; }; - if len != target.len { + if !inner.owner_hot_source_is_current( + &event.key, + event.put_id, + &memory_info, + ) { + event.guard.mark_obsolete(); + continue; + } + let holder = Arc::new(UserMemHolder::new( + memory_info, + inner.get_or_init_all_memholder_refcount(), + UserMemHolderExposeKind::SegPtr, + )); + let key = event.key.clone(); + let put_id = event.put_id; + if let Err(err) = inner + .replica_task_tx + .send(ReplicaTaskJob { + key: event.key, + put_id: event.put_id, + holder, + target: None, + preferred_sub_cluster: None, + hot_replica_guard: Some(event.guard), + protect_source_on_remote_complete: false, + }) + .await + { + tracing::warn!( + "replica task actor queue closed for owner hot eviction: key={} put_id=({},{}) err={}", + key, + put_id.0, + put_id.1, + err + ); + } + } + }); +} + +async fn process_replica_task(view_task: ClientKvApiView, job: ReplicaTaskJob) { + let inner = view_task.client_kv_api().inner(); + let src_offset = job.holder.memory_info().offset; + let len = job.holder.get_length() as u64; + let target = if let Some(target) = job.target.clone() { + target + } else { + let len_u32 = match u32::try_from(len) { + Ok(len_u32) => len_u32, + Err(_) => { tracing::warn!( - "replica task length mismatch: key={} put_id=({},{}) src_len={} target_len={}", + "replica append task length does not fit u32: key={} put_id=({},{}) len={}", job.key, job.put_id.0, job.put_id.1, - len, - target.len - ); - spawn_replica_task_revoke( - view_task.clone(), - job.key, - job.put_id, - "length mismatch", + len ); - continue; + return; } - if let Err(err) = inner - .put_transfer( - &job.key, - job.put_id, - src_offset, - target.target_offset, - len, - Some(target.node_id.clone()), - Some(target.target_base_addr), - ) - .await - { + }; + let append_start = match start_replica_append_with_retry(inner, &job, len_u32).await { + Ok(resp) => resp, + Err(err) => { tracing::warn!( - "replica task transfer failed: key={} put_id=({},{}) err={}", + "replica append task start failed: key={} put_id=({},{}) err={}", job.key, job.put_id.0, job.put_id.1, err ); - spawn_replica_task_revoke(view_task.clone(), job.key, job.put_id, "transfer error"); - continue; + return; } - match inner.put_append_done(&job.key, job.put_id).await { - Ok(resp) => { - tracing::debug!( - "replica task append done: key={} put_id=({},{}) appended={}", - job.key, - job.put_id.0, - job.put_id.1, - resp.appended - ); + }; + if !append_start.scheduled { + tracing::debug!( + "replica append task not scheduled: key={} put_id=({},{})", + job.key, + job.put_id.0, + job.put_id.1 + ); + if let Some(guard) = job.hot_replica_guard.as_ref() { + guard.mark_already_satisfied(); + } + return; + } + ReplicaTaskTarget { + node_id: append_start.node_id, + target_offset: append_start.target_addr - append_start.target_base_addr, + target_base_addr: append_start.target_base_addr, + len: append_start.len, + } + }; + if len != target.len { + tracing::warn!( + "replica task length mismatch: key={} put_id=({},{}) src_len={} target_len={}", + job.key, + job.put_id.0, + job.put_id.1, + len, + target.len + ); + spawn_replica_task_revoke(view_task.clone(), job.key, job.put_id, "length mismatch"); + return; + } + if let Err(err) = inner + .put_transfer( + &job.key, + job.put_id, + src_offset, + target.target_offset, + len, + Some(target.node_id.clone()), + Some(target.target_base_addr), + ) + .await + { + tracing::warn!( + "replica task transfer failed: key={} put_id=({},{}) err={}", + job.key, + job.put_id.0, + job.put_id.1, + err + ); + spawn_replica_task_revoke(view_task.clone(), job.key, job.put_id, "transfer error"); + return; + } + // Append-done may reclaim the source synchronously. Release the transfer-only holder first so + // this task does not make its own reclaim look busy. + drop(job.holder); + match inner.put_append_done(&job.key, job.put_id).await { + Ok(resp) => { + tracing::debug!( + "replica task append done: key={} put_id=({},{}) appended={}", + job.key, + job.put_id.0, + job.put_id.1, + resp.appended + ); + if let Some(guard) = job.hot_replica_guard.as_ref() { + if resp.appended { + guard.mark_completed(); + } else { + guard.mark_already_satisfied(); + } + } + } + Err(err) => { + tracing::warn!( + "replica task append done failed: key={} put_id=({},{}) err={}", + job.key, + job.put_id.0, + job.put_id.1, + err + ); + } + } +} + +pub fn spawn_replica_task_actor( + view: ClientKvApiView, + mut rx: tokio::sync::ampsc::Receiver, + max_inflight: usize, +) { + let view_task = view.clone(); + let _ = view.spawn("replica_task_actor", async move { + let max_inflight = max_inflight.max(1); + let semaphore = Arc::new(::tokio::sync::Semaphore::new(max_inflight)); + let per_key = Arc::new(SemaphoreMap::new(1, Duration::from_secs(10 * 60))); + tracing::info!( + max_inflight, + "replica task actor started with bounded cross-key concurrency" + ); + let mut shutdown_waiter = view_task.register_shutdown_waiter(); + loop { + let job = tokio::select! { + _ = shutdown_waiter.wait() => { + tracing::info!("replica_task_actor stopping due to shutdown signal"); + break; } + job = rx.recv() => { + match job { + Some(job) => job, + None => break, + } + } + }; + let permit = match semaphore.clone().acquire_owned().await { + Ok(permit) => permit, Err(err) => { tracing::warn!( - "replica task append done failed: key={} put_id=({},{}) err={}", - job.key, - job.put_id.0, - job.put_id.1, + "replica task actor semaphore closed; dropping queued work: err={}", err ); + break; } - } + }; + let spawn_view = view_task.clone(); + let worker_view = view_task.clone(); + let worker_per_key = per_key.clone(); + spawn_view.spawn("replica_task_worker", async move { + let _permit = permit; + let _key_permit = worker_per_key.acquire(job.key.clone()).await; + process_replica_task(worker_view, job).await; + }); } }); } +pub async fn handle_batch_enqueue_replica_tasks( + view: &ClientKvApiView, + req: MsgPack, +) -> MsgPack { + let inner = view.client_kv_api().inner(); + let mut items = Vec::with_capacity(req.serialize_part.items.len()); + for item in req.serialize_part.items { + let accepted = match inner + .make_replica_append_task(&item.key, item.put_id, None, false) + .await + { + Ok(accepted) => accepted, + Err(err) => { + tracing::warn!( + "tier1 write-back enqueue failed: key={} put_id=({},{}) err={}", + item.key, + item.put_id.0, + item.put_id.1, + err + ); + false + } + }; + items.push(EnqueueReplicaTaskItemResp { + key: item.key, + put_id: item.put_id, + accepted, + }); + } + MsgPack { + serialize_part: BatchEnqueueReplicaTaskResp { + items, + error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, + error_json: String::new(), + }, + raw_bytes: Vec::new(), + } +} + pub fn spawn_owner_local_publish_dispatcher( view: ClientKvApiView, mut rx: tokio::sync::ampsc::Receiver, @@ -2251,6 +2926,42 @@ pub fn spawn_owner_local_publish_dispatcher( }); } +/// Returns the linear group partition only when every multi-key group is present, +/// contiguous, and in the caller-declared member order. A partial batch must use +/// the legacy per-item descriptors so the V2 wire format never changes semantics. +fn complete_owner_local_publish_group_lens(items: &[OwnerLocalPublishItem]) -> Option> { + let mut offset = 0usize; + let mut group_lens = Vec::new(); + while offset < items.len() { + let item = &items[offset]; + let Some(group) = item.atomic_group.as_ref() else { + group_lens.push(1); + offset += 1; + continue; + }; + let group_len = group.members.len(); + if group_len < 2 { + return None; + } + let end = offset.checked_add(group_len)?; + let group_items = items.get(offset..end)?; + if group_items + .iter() + .zip(group.members.iter()) + .any(|(group_item, member)| { + group_item.key != member.key + || group_item.put_id != member.put_id + || group_item.atomic_group.as_ref() != Some(group) + }) + { + return None; + } + group_lens.push(group_len); + offset = end; + } + Some(group_lens) +} + async fn publish_owner_local_job(view: ClientKvApiView, job: OwnerLocalPublishJob) { let inner = view.client_kv_api().inner(); if job.items.is_empty() { @@ -2258,21 +2969,58 @@ async fn publish_owner_local_job(view: ClientKvApiView, job: OwnerLocalPublishJo return; } - let done_req_items = job - .items - .iter() - .map(|item| BatchPutDoneItemReq { - key: item.key.clone(), - put_id: item.put_id, - lease_id: item.lease_id, - committed_slot: Some(item.committed_slot.clone()), - publish_local_cache: false, - }) - .collect::>(); + let group_lens = complete_owner_local_publish_group_lens(&job.items); + let done_items = if let Some(atomic_group_lens) = group_lens { + inner + .owner_hot_counters + .grouped_put_done_batches + .fetch_add(1, Ordering::Relaxed); + inner + .owner_hot_counters + .grouped_put_done_items + .fetch_add(job.items.len() as u64, Ordering::Relaxed); + let items = job + .items + .iter() + .map(|item| GroupedBatchPutDoneItemReq { + key: item.key.clone(), + put_id: item.put_id, + lease_id: item.lease_id, + committed_slot: Some(item.committed_slot.clone()), + publish_local_cache: false, + }) + .collect::>(); + inner + .grouped_batch_put_done(items, atomic_group_lens) + .await + .map(|resp| resp.items) + } else { + inner + .owner_hot_counters + .legacy_put_done_batches + .fetch_add(1, Ordering::Relaxed); + inner + .owner_hot_counters + .legacy_put_done_items + .fetch_add(job.items.len() as u64, Ordering::Relaxed); + let items = job + .items + .iter() + .map(|item| BatchPutDoneItemReq { + key: item.key.clone(), + put_id: item.put_id, + lease_id: item.lease_id, + committed_slot: Some(item.committed_slot.clone()), + publish_local_cache: false, + atomic_group: item.atomic_group.clone(), + }) + .collect::>(); + inner.batch_put_done(items).await.map(|resp| resp.items) + }; - match inner.batch_put_done(done_req_items).await { - Ok(done_resp) if done_resp.items.len() == job.items.len() => { - for (item, done_item) in job.items.iter().zip(done_resp.items.into_iter()) { + match done_items { + Ok(done_items) if done_items.len() == job.items.len() => { + for (item, done_item) in job.items.iter().zip(done_items.into_iter()) { if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( done_item.error_code, done_item.error_json.clone(), @@ -2292,6 +3040,7 @@ async fn publish_owner_local_job(view: ClientKvApiView, job: OwnerLocalPublishJo &item.key, item.put_id, item.preferred_sub_cluster.clone(), + true, ) .await { @@ -2306,11 +3055,11 @@ async fn publish_owner_local_job(view: ClientKvApiView, job: OwnerLocalPublishJo } } } - Ok(done_resp) => { + Ok(done_items) => { tracing::warn!( "owner local publish response length mismatch: expected={} got={}", job.items.len(), - done_resp.items.len() + done_items.len() ); } Err(err) => { diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs new file mode 100644 index 0000000..2c33a58 --- /dev/null +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs @@ -0,0 +1,429 @@ +use super::{ClientKvApiInner, ClientKvApiView, OwnerPreparedReclaim, OwnerReclaimRecord}; +use crate::cluster_manager::{NodeID, NodeRole}; +use crate::master_kv_router::msg_pack::{ + BatchOwnerReclaimReq, BatchOwnerReclaimResp, OwnerReclaimBacking, OwnerReclaimItem, + OwnerReclaimItemResp, OwnerReclaimItemState, OwnerReclaimPhase, +}; +use crate::p2p::msg_pack::MsgPack; +use crate::rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, OK}; +use std::{collections::HashMap, sync::Arc}; + +fn item_resp( + item: &OwnerReclaimItem, + state: OwnerReclaimItemState, + detail: impl Into, +) -> OwnerReclaimItemResp { + OwnerReclaimItemResp { + key: item.key.clone(), + epoch: item.epoch, + state, + detail: detail.into(), + } +} + +fn record_item(record: &OwnerReclaimRecord) -> &OwnerReclaimItem { + match record { + OwnerReclaimRecord::Prepared(prepared) => &prepared.item, + OwnerReclaimRecord::Committed(item) => item, + } +} + +fn memory_matches_reclaim_backing( + memory_info: &crate::memholder::MemoryInfo, + backing: &OwnerReclaimBacking, +) -> bool { + match backing { + OwnerReclaimBacking::Allocation => memory_info.local_reserve_resident_slot_ref().is_none(), + OwnerReclaimBacking::UnindexedAllocation => false, + OwnerReclaimBacking::CommittedSlot { + grant_id, + slot_index, + slot_size, + } => memory_info.local_reserve_resident_slot_ref().is_some_and( + |(actual_slot_size, actual_grant_id, actual_slot_index)| { + actual_slot_size == *slot_size + && actual_grant_id == *grant_id + && actual_slot_index == *slot_index + }, + ), + } +} + +fn prepare_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclaimItemResp { + let mut controls = inner.owner_key_control.lock(); + if let Some(state) = controls.get(&item.key) { + if state.local_puts != 0 { + return item_resp( + item, + OwnerReclaimItemState::Busy, + "owner local put is inflight", + ); + } + if let Some(record) = state.reclaim.as_ref() { + if record_item(record) == item { + return item_resp( + item, + match record { + OwnerReclaimRecord::Prepared(_) => OwnerReclaimItemState::Prepared, + OwnerReclaimRecord::Committed(_) => OwnerReclaimItemState::Committed, + }, + "reclaim phase already applied", + ); + } + return item_resp( + item, + OwnerReclaimItemState::Busy, + "another reclaim epoch owns the key fence", + ); + } + } + if inner.precommit_local_visible_info.contains_key(&item.key) { + return item_resp( + item, + OwnerReclaimItemState::Busy, + "owner precommit local index is still visible", + ); + } + if inner + .external_pending_puts + .iter() + .any(|(pending_key, _)| pending_key.0 == item.key) + { + return item_resp( + item, + OwnerReclaimItemState::Busy, + "owner external put context is still pending", + ); + } + + let Some((_key, cached_info)) = inner.get_cached_info.remove_if(&item.key, |_, cached| { + cached.put_time_ms == item.put_id.0 + && cached.put_version == item.put_id.1 + && memory_matches_reclaim_backing(cached.mem_holder.as_ref(), &item.backing) + }) else { + return item_resp( + item, + OwnerReclaimItemState::Stale, + "matching local backing index is absent", + ); + }; + + // The index entry is now hidden while the same control lock keeps all new local readers out. + // Any reader that cloned the memory just before the fence is visible in the Arc count. + if Arc::strong_count(&cached_info.mem_holder) != 1 { + let replaced = inner.get_cached_info.insert(item.key.clone(), cached_info); + assert!( + replaced.is_none(), + "owner reclaim rollback must restore an empty local index slot" + ); + return item_resp( + item, + OwnerReclaimItemState::Busy, + "owner local memory still has active holders", + ); + } + + let local_snapshot = inner + .local_snapshot_info + .remove_if(&item.key, |_, snapshot| { + snapshot.put_time_ms == item.put_id.0 && snapshot.put_version == item.put_id.1 + }) + .map(|(_, snapshot)| snapshot); + let state = controls.entry(item.key.clone()).or_default(); + assert!(state.reclaim.is_none() && state.local_puts == 0); + state.reclaim = Some(OwnerReclaimRecord::Prepared(OwnerPreparedReclaim { + item: item.clone(), + cached_info, + local_snapshot, + })); + item_resp( + item, + OwnerReclaimItemState::Prepared, + "owner local index fenced", + ) +} + +fn release_prepared_backing_now(inner: &ClientKvApiInner, prepared: OwnerPreparedReclaim) { + let mut memory_info = Arc::try_unwrap(prepared.cached_info.mem_holder).unwrap_or_else(|_| { + panic!( + "owner reclaim prepared memory unexpectedly gained a holder: key={} epoch={}", + prepared.item.key, prepared.item.epoch + ) + }); + match &prepared.item.backing { + OwnerReclaimBacking::Allocation => { + assert!( + memory_info.local_reserve_resident_slot_ref().is_none(), + "allocation reclaim must not carry a local-reserve slot" + ); + } + OwnerReclaimBacking::UnindexedAllocation => { + unreachable!("unindexed allocations must be reclaimed entirely on the master") + } + OwnerReclaimBacking::CommittedSlot { + grant_id, + slot_index, + slot_size, + } => { + let (actual_slot_size, actual_grant_id, actual_slot_index) = memory_info + .take_local_reserve_resident_slot_ref() + .expect("committed-slot reclaim must carry a local-reserve slot"); + assert_eq!(actual_slot_size, *slot_size); + assert_eq!(actual_grant_id, *grant_id); + assert_eq!(actual_slot_index, *slot_index); + + inner + .owner_release_local_reserve_committed_slot_route( + actual_slot_size, + actual_grant_id, + actual_slot_index, + ) + .expect("owner reclaim committed route release must succeed"); + inner + .owner_release_local_reserve_resident_slot_holder( + actual_slot_size, + actual_grant_id, + actual_slot_index, + ) + .expect("owner reclaim resident holder release must succeed"); + } + } + drop(memory_info); +} + +fn commit_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclaimItemResp { + let mut controls = inner.owner_key_control.lock(); + let Some(state) = controls.get_mut(&item.key) else { + return item_resp( + item, + OwnerReclaimItemState::Stale, + "owner reclaim fence is absent", + ); + }; + let Some(record) = state.reclaim.take() else { + return item_resp( + item, + OwnerReclaimItemState::Stale, + "owner reclaim fence is absent", + ); + }; + let prepared = match record { + OwnerReclaimRecord::Prepared(prepared) if prepared.item == *item => prepared, + OwnerReclaimRecord::Committed(committed) if committed == *item => { + state.reclaim = Some(OwnerReclaimRecord::Committed(committed)); + return item_resp( + item, + OwnerReclaimItemState::Committed, + "owner reclaim commit already applied", + ); + } + other => { + state.reclaim = Some(other); + return item_resp( + item, + OwnerReclaimItemState::Stale, + "owner reclaim epoch or slot identity changed", + ); + } + }; + + // Keep the owner fence installed by holding the control lock until the slot is fully free. + release_prepared_backing_now(inner, prepared); + assert!(state.reclaim.is_none() && state.local_puts == 0); + state.reclaim = Some(OwnerReclaimRecord::Committed(item.clone())); + drop(controls); + inner.owner_hot_invalidate_version(&item.key, item.put_id); + item_resp( + item, + OwnerReclaimItemState::Committed, + "owner committed slot released", + ) +} + +fn abort_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclaimItemResp { + let mut controls = inner.owner_key_control.lock(); + let Some(state) = controls.get_mut(&item.key) else { + return item_resp( + item, + OwnerReclaimItemState::Aborted, + "owner reclaim was already absent", + ); + }; + let Some(record) = state.reclaim.take() else { + return item_resp( + item, + OwnerReclaimItemState::Aborted, + "owner reclaim was already absent", + ); + }; + match record { + OwnerReclaimRecord::Prepared(prepared) if prepared.item == *item => { + let replaced = inner + .get_cached_info + .insert(item.key.clone(), prepared.cached_info); + assert!( + replaced.is_none(), + "owner reclaim abort must restore an empty local index slot" + ); + if let Some(snapshot) = prepared.local_snapshot { + let replaced = inner.local_snapshot_info.insert(item.key.clone(), snapshot); + assert!( + replaced.is_none(), + "owner reclaim abort must restore an empty local snapshot slot" + ); + } + if state.local_puts == 0 { + controls.remove(&item.key); + } + item_resp( + item, + OwnerReclaimItemState::Aborted, + "owner local index fence rolled back", + ) + } + OwnerReclaimRecord::Committed(committed) if committed == *item => { + state.reclaim = Some(OwnerReclaimRecord::Committed(committed)); + item_resp( + item, + OwnerReclaimItemState::Committed, + "owner slot was already committed and cannot be restored", + ) + } + other => { + state.reclaim = Some(other); + item_resp( + item, + OwnerReclaimItemState::Stale, + "owner reclaim epoch or slot identity changed", + ) + } + } +} + +fn finalize_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclaimItemResp { + let mut controls = inner.owner_key_control.lock(); + let Some(state) = controls.get_mut(&item.key) else { + return item_resp( + item, + OwnerReclaimItemState::Finalized, + "owner reclaim was already finalized", + ); + }; + match state.reclaim.take() { + Some(OwnerReclaimRecord::Committed(committed)) if committed == *item => { + if state.local_puts == 0 { + controls.remove(&item.key); + } + item_resp( + item, + OwnerReclaimItemState::Finalized, + "owner reclaim fence cleared", + ) + } + Some(other) => { + state.reclaim = Some(other); + item_resp( + item, + OwnerReclaimItemState::Busy, + "owner reclaim is not committed for this epoch", + ) + } + None => item_resp( + item, + OwnerReclaimItemState::Finalized, + "owner reclaim was already finalized", + ), + } +} + +pub async fn handle_batch_owner_reclaim( + view: &ClientKvApiView, + req: MsgPack, + req_node_id: NodeID, +) -> MsgPack { + let requester_is_master = view + .cluster_manager() + .get_member_info_cached(req_node_id.as_ref()) + .is_some_and(|member| matches!(member.node_role(), NodeRole::Master)); + if !requester_is_master { + let err = KvError::Api(ApiError::InvalidArgument { + detail: format!( + "batch owner reclaim requester is not the current master: requester={}", + req_node_id + ), + }); + return MsgPack { + serialize_part: BatchOwnerReclaimResp { + items: Vec::new(), + error_code: err.code(), + error_json: err.to_json(), + }, + raw_bytes: Vec::new(), + }; + } + let inner = view.client_kv_api().inner(); + let phase = req.serialize_part.phase; + let items = req + .serialize_part + .items + .iter() + .map(|item| match phase { + OwnerReclaimPhase::Prepare => prepare_one(inner, item), + OwnerReclaimPhase::Commit => commit_one(inner, item), + OwnerReclaimPhase::Abort => abort_one(inner, item), + OwnerReclaimPhase::Finalize => finalize_one(inner, item), + }) + .collect::>(); + let prepared = items + .iter() + .filter(|item| item.state == OwnerReclaimItemState::Prepared) + .count(); + let committed = items + .iter() + .filter(|item| item.state == OwnerReclaimItemState::Committed) + .count(); + let finalized = items + .iter() + .filter(|item| item.state == OwnerReclaimItemState::Finalized) + .count(); + let busy_or_stale = items + .iter() + .filter(|item| { + matches!( + item.state, + OwnerReclaimItemState::Busy | OwnerReclaimItemState::Stale + ) + }) + .count(); + let mut rejection_reason_counts = HashMap::::new(); + for item in &items { + if matches!( + item.state, + OwnerReclaimItemState::Busy | OwnerReclaimItemState::Stale + ) { + *rejection_reason_counts + .entry(item.detail.clone()) + .or_default() += 1; + } + } + let mut rejection_reason_counts = rejection_reason_counts.into_iter().collect::>(); + rejection_reason_counts.sort_by(|a, b| a.0.cmp(&b.0)); + tracing::info!( + "owner reclaim phase completed: phase={:?} items={} prepared={} committed={} finalized={} busy_or_stale={} rejection_reasons={:?}", + phase, + items.len(), + prepared, + committed, + finalized, + busy_or_stale, + rejection_reason_counts + ); + MsgPack { + serialize_part: BatchOwnerReclaimResp { + items, + error_code: OK, + error_json: String::new(), + }, + raw_bytes: Vec::new(), + } +} diff --git a/fluxon_rs/fluxon_kv/src/config.rs b/fluxon_rs/fluxon_kv/src/config.rs index bf676ee..8e88dc5 100644 --- a/fluxon_rs/fluxon_kv/src/config.rs +++ b/fluxon_rs/fluxon_kv/src/config.rs @@ -97,12 +97,21 @@ pub enum SideTransferRole { Worker, } +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[serde(deny_unknown_fields)] +pub struct OwnerLocalReserveExpectedCapacity { + pub value_len: u64, + pub payload_capacity_bytes: u64, +} + const TEST_SPEC_TCP_THREAD_REACTOR_SHARD_COUNT_MIN: u8 = 1; const TEST_SPEC_TCP_THREAD_REACTOR_SHARD_COUNT_MAX: u8 = 16; const TEST_SPEC_TCP_THREAD_BULK_LANE_COUNT_MIN: u8 = 1; const TEST_SPEC_TCP_THREAD_BULK_LANE_COUNT_MAX: u8 = 8; const TEST_SPEC_TCP_THREAD_CONTROL_LANE_COUNT_MIN: u8 = 1; const TEST_SPEC_TCP_THREAD_CONTROL_LANE_COUNT_MAX: u8 = 8; +const TEST_SPEC_REPLICA_TASK_MAX_INFLIGHT_MIN: u16 = 1; +const TEST_SPEC_REPLICA_TASK_MAX_INFLIGHT_MAX: u16 = 64; fn default_iceoryx_owner_client_busy_poll() -> bool { true @@ -137,6 +146,8 @@ pub struct TestSpecConfig { pub owner_local_reserve_soft_wait_timeout_ms: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub owner_local_reserve_hard_timeout_ms: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub owner_local_reserve_expected_capacity: Option, #[serde(skip_serializing_if = "Option::is_none")] pub transport_mode: Option, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -147,6 +158,10 @@ pub struct TestSpecConfig { pub tcp_thread_control_lane_count: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub user_rpc_sync_handler_thread_count: Option, + /// Maximum number of replica append pipelines in flight on an owner. Different keys may run + /// concurrently; each key remains strictly serialized by the replica dispatcher. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub replica_task_max_inflight: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub rdma_device_names: Option>, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -177,11 +192,13 @@ impl Default for TestSpecConfig { skip_put_end_commit: false, owner_local_reserve_soft_wait_timeout_ms: None, owner_local_reserve_hard_timeout_ms: None, + owner_local_reserve_expected_capacity: None, transport_mode: None, tcp_thread_reactor_shard_count: None, tcp_thread_bulk_lane_count: None, tcp_thread_control_lane_count: None, user_rpc_sync_handler_thread_count: None, + replica_task_max_inflight: None, rdma_device_names: None, require_transfer_rpc_fast_path_ready_timeout_seconds: None, enable_side_transfer: false, @@ -304,10 +321,12 @@ fn validate_required_transfer_rpc_fast_path_ready_timeout( } fn validate_owner_local_reserve_timeouts(test_spec_config: &TestSpecConfig) -> KvResult<()> { - let Some(soft_wait_timeout_ms) = test_spec_config.owner_local_reserve_soft_wait_timeout_ms - else { - return Ok(()); - }; + let soft_wait_timeout_ms = test_spec_config + .owner_local_reserve_soft_wait_timeout_ms + .unwrap_or(10); + let hard_timeout_ms = test_spec_config + .owner_local_reserve_hard_timeout_ms + .unwrap_or(10_000); if soft_wait_timeout_ms == 0 { return Err(ConfigError::InvalidClientConfig { detail: "test_spec_config.owner_local_reserve_soft_wait_timeout_ms must be > 0" @@ -315,26 +334,60 @@ fn validate_owner_local_reserve_timeouts(test_spec_config: &TestSpecConfig) -> K } .into_kverror()); } - - if let Some(hard_timeout_ms) = test_spec_config.owner_local_reserve_hard_timeout_ms { - if hard_timeout_ms == 0 { - return Err(ConfigError::InvalidClientConfig { - detail: "test_spec_config.owner_local_reserve_hard_timeout_ms must be > 0" - .to_string(), - } - .into_kverror()); + if hard_timeout_ms == 0 { + return Err(ConfigError::InvalidClientConfig { + detail: "test_spec_config.owner_local_reserve_hard_timeout_ms must be > 0".to_string(), } - if hard_timeout_ms <= soft_wait_timeout_ms { - return Err(ConfigError::InvalidClientConfig { - detail: "test_spec_config.owner_local_reserve_hard_timeout_ms must be greater than owner_local_reserve_soft_wait_timeout_ms".to_string(), - } - .into_kverror()); + .into_kverror()); + } + if hard_timeout_ms <= soft_wait_timeout_ms { + return Err(ConfigError::InvalidClientConfig { + detail: "test_spec_config.owner_local_reserve_hard_timeout_ms must be greater than owner_local_reserve_soft_wait_timeout_ms".to_string(), } + .into_kverror()); } Ok(()) } +fn validate_owner_local_reserve_expected_capacity( + test_spec_config: &TestSpecConfig, +) -> KvResult<()> { + let Some(expected) = &test_spec_config.owner_local_reserve_expected_capacity else { + return Ok(()); + }; + if expected.value_len == 0 { + return Err(ConfigError::InvalidClientConfig { + detail: "test_spec_config.owner_local_reserve_expected_capacity.value_len must be > 0" + .to_string(), + } + .into_kverror()); + } + if expected.payload_capacity_bytes == 0 { + return Err(ConfigError::InvalidClientConfig { + detail: "test_spec_config.owner_local_reserve_expected_capacity.payload_capacity_bytes must be > 0" + .to_string(), + } + .into_kverror()); + } + if crate::owner_local_reserve_expected_grant_count( + expected.value_len, + expected.payload_capacity_bytes, + ) + .is_none() + { + return Err(ConfigError::InvalidClientConfig { + detail: format!( + "test_spec_config.owner_local_reserve_expected_capacity.value_len={} cannot be represented by a local-reserve slot no larger than {} bytes", + expected.value_len, + crate::OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES + ), + } + .into_kverror()); + } + Ok(()) +} + fn apply_test_spec_rdma_device_names_to_protocol( mut protocol: ProtocolConfig, normalized_rdma_device_names: Option<&Vec>, @@ -391,6 +444,21 @@ fn validate_test_spec_tcp_thread_tuning(test_spec_config: &TestSpecConfig) -> Kv .into_kverror()); } } + if let Some(value) = test_spec_config.replica_task_max_inflight { + if !(TEST_SPEC_REPLICA_TASK_MAX_INFLIGHT_MIN..=TEST_SPEC_REPLICA_TASK_MAX_INFLIGHT_MAX) + .contains(&value) + { + return Err(ConfigError::InvalidTestConfig { + detail: format!( + "test_spec_config.replica_task_max_inflight must be in [{}, {}], got {}", + TEST_SPEC_REPLICA_TASK_MAX_INFLIGHT_MIN, + TEST_SPEC_REPLICA_TASK_MAX_INFLIGHT_MAX, + value + ), + } + .into_kverror()); + } + } Ok(()) } @@ -482,6 +550,11 @@ pub const DEFAULT_OTLP_LOG_TABLE_NAME: &str = "fluxon_logs"; pub const DEFAULT_OTLP_LOG_FLUSH_INTERVAL_MS: u64 = 2000; pub const DEFAULT_OTLP_LOG_MAX_BATCH_LINES: usize = 2000; pub const DEFAULT_OTLP_LOG_MAX_QUEUE_LINES: usize = 20000; +pub const DEFAULT_REPLICA_CACHE_CAPACITY_RATIO: f64 = 0.95; + +fn default_replica_cache_capacity_ratio() -> f64 { + DEFAULT_REPLICA_CACHE_CAPACITY_RATIO +} #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] @@ -767,6 +840,12 @@ pub struct MasterConfigYaml { pub master_ui: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub replica_task_placement: Option, + #[serde(default = "default_replica_cache_capacity_ratio")] + pub replica_cache_capacity_ratio: f64, + /// Optional inclusive hot-tier capacity. Entries evicted from this tier remain in the + /// resident replica cache and are proactively copied to a remote-only owner. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub replica_writeback_tier1_capacity_ratio: Option, #[serde(default)] pub test_spec_config: TestSpecConfig, } @@ -787,6 +866,8 @@ pub struct MasterConfig { pub log_dir: String, pub master_ui: Option, pub replica_task_placement: ReplicaTaskPlacementConfig, + pub replica_cache_capacity_ratio: f64, + pub replica_writeback_tier1_capacity_ratio: Option, pub test_spec_config: TestSpecConfig, } @@ -837,6 +918,10 @@ pub struct ClientConfigYaml { pub contribute_to_cluster_pool_size: Option, #[serde(skip_serializing_if = "Option::is_none")] pub pprof_duration_seconds: Option, + /// Optional owner-local hot working-set threshold. Size eviction from this + /// logical tier schedules an asynchronous remote replica write-back. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub replica_writeback_hot_capacity_ratio: Option, pub fluxonkv_spec: FluxonKvSpecYaml, #[serde(default)] pub test_spec_config: TestSpecConfig, @@ -959,6 +1044,7 @@ pub struct ClientConfig { pub contribute_to_cluster_pool_size: ContributeToClusterPoolSize, pub protocol: ProtocolConfig, pub pprof_duration_seconds: Option, + pub replica_writeback_hot_capacity_ratio: Option, pub redis_compat_listen_addr: Option, pub fluxonkv_spec: FluxonKvSpec, pub share_mem_path: String, // Mandatory shared bundle path @@ -1142,6 +1228,7 @@ impl ClientConfigYaml { materialize_default_test_spec_transport_mode(&mut test_spec_config); validate_required_transfer_rpc_fast_path_ready_timeout(&test_spec_config)?; validate_owner_local_reserve_timeouts(&test_spec_config)?; + validate_owner_local_reserve_expected_capacity(&test_spec_config)?; validate_test_spec_tcp_thread_tuning(&test_spec_config)?; // Role selection contract: @@ -1204,6 +1291,58 @@ impl ClientConfigYaml { } } + if let Some(hot_ratio) = self.replica_writeback_hot_capacity_ratio { + if !hot_ratio.is_finite() || hot_ratio <= 0.0 || hot_ratio >= 1.0 { + return Err(ConfigError::InvalidClientConfig { + detail: "replica_writeback_hot_capacity_ratio must be finite and in (0, 1)" + .to_string(), + } + .into_kverror()); + } + if is_external { + return Err(ConfigError::InvalidClientConfig { + detail: "replica_writeback_hot_capacity_ratio is only valid on owner configs" + .to_string(), + } + .into_kverror()); + } + } + + if let Some(expected) = &test_spec_config.owner_local_reserve_expected_capacity { + if is_external { + return Err(ConfigError::InvalidClientConfig { + detail: "test_spec_config.owner_local_reserve_expected_capacity is only valid on owner configs" + .to_string(), + } + .into_kverror()); + } + let expected_grants = crate::owner_local_reserve_expected_grant_count( + expected.value_len, + expected.payload_capacity_bytes, + ) + .expect("owner local-reserve expected capacity was validated"); + let physical_reserve_bytes = expected_grants + .checked_mul(crate::OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES) + .ok_or_else(|| { + ConfigError::InvalidClientConfig { + detail: "test_spec_config.owner_local_reserve_expected_capacity physical reserve size overflows u64" + .to_string(), + } + .into_kverror() + })?; + if physical_reserve_bytes > contribute_to_cluster_pool_size.dram { + return Err(ConfigError::InvalidClientConfig { + detail: format!( + "test_spec_config.owner_local_reserve_expected_capacity requires {} physical bytes across {} grants, exceeding owner dram contribution {}", + physical_reserve_bytes, + expected_grants, + contribute_to_cluster_pool_size.dram + ), + } + .into_kverror()); + } + } + let is_side_transfer_worker = matches!( test_spec_config.side_transfer_role, Some(SideTransferRole::Worker) @@ -1442,6 +1581,7 @@ impl ClientConfigYaml { contribute_to_cluster_pool_size, protocol, pprof_duration_seconds, + replica_writeback_hot_capacity_ratio: self.replica_writeback_hot_capacity_ratio, redis_compat_listen_addr, fluxonkv_spec, share_mem_path, @@ -1725,6 +1865,36 @@ impl MasterConfigYaml { Some(cfg) => cfg.verify()?, None => ReplicaTaskPlacementConfig::default(), }; + if !self.replica_cache_capacity_ratio.is_finite() + || self.replica_cache_capacity_ratio <= 0.0 + || self.replica_cache_capacity_ratio > 1.0 + { + return Err(ConfigError::InvalidClientConfig { + detail: "replica_cache_capacity_ratio must be finite and in (0, 1]".to_string(), + } + .into_kverror()); + } + if let Some(tier1_ratio) = self.replica_writeback_tier1_capacity_ratio { + if !tier1_ratio.is_finite() + || tier1_ratio <= 0.0 + || tier1_ratio >= self.replica_cache_capacity_ratio + { + return Err(ConfigError::InvalidClientConfig { + detail: format!( + "replica_writeback_tier1_capacity_ratio must be finite, positive, and smaller than replica_cache_capacity_ratio ({})", + self.replica_cache_capacity_ratio + ), + } + .into_kverror()); + } + if !replica_task_placement.restrict_to_remote_only_node_roles { + return Err(ConfigError::InvalidClientConfig { + detail: "replica_writeback_tier1_capacity_ratio requires replica_task_placement.restrict_to_remote_only_node_roles=true" + .to_string(), + } + .into_kverror()); + } + } let mut test_spec_config = self.test_spec_config; let transport_mode_was_explicit = test_spec_config.transport_mode.is_some(); @@ -1735,6 +1905,17 @@ impl MasterConfigYaml { materialize_default_test_spec_transport_mode(&mut test_spec_config); validate_required_transfer_rpc_fast_path_ready_timeout(&test_spec_config)?; validate_owner_local_reserve_timeouts(&test_spec_config)?; + validate_owner_local_reserve_expected_capacity(&test_spec_config)?; + if test_spec_config + .owner_local_reserve_expected_capacity + .is_some() + { + return Err(ConfigError::InvalidClientConfig { + detail: "test_spec_config.owner_local_reserve_expected_capacity is only valid on owner configs" + .to_string(), + } + .into_kverror()); + } validate_test_spec_tcp_thread_tuning(&test_spec_config)?; let protocol = apply_test_spec_rdma_device_names_to_protocol( self.protocol.unwrap_or(ProtocolConfig { @@ -1763,6 +1944,8 @@ impl MasterConfigYaml { log_dir: self.log_dir, master_ui, replica_task_placement, + replica_cache_capacity_ratio: self.replica_cache_capacity_ratio, + replica_writeback_tier1_capacity_ratio: self.replica_writeback_tier1_capacity_ratio, test_spec_config, }) } @@ -1854,6 +2037,195 @@ fluxonkv_spec: assert!(verified.fluxonkv_spec.enable_transfer_rpc_fast_path); } + #[test] + fn owner_replica_writeback_hot_capacity_ratio_is_owner_only_and_bounded() { + let owner = r#" +instance_key: test_owner +contribute_to_cluster_pool_size: + dram: 16777216 + vram: {} +replica_writeback_hot_capacity_ratio: RATIO +fluxonkv_spec: + etcd_addresses: ["127.0.0.1:2379"] + cluster_name: test_cluster + share_mem_path: /tmp/test_owner_hot + large_file_paths: [/tmp/test_owner_hot_large] + sub_cluster: rack-a +"#; + let verified = ClientConfigYaml::from_str(&owner.replace("RATIO", "0.75")) + .unwrap() + .verify() + .unwrap(); + assert_eq!(verified.replica_writeback_hot_capacity_ratio, Some(0.75)); + + for invalid in ["0", "1", "-0.1", ".nan"] { + let err = ClientConfigYaml::from_str(&owner.replace("RATIO", invalid)) + .unwrap() + .verify() + .unwrap_err(); + assert!( + err.to_string() + .contains("replica_writeback_hot_capacity_ratio") + ); + } + + let external = r#" +instance_key: test_external +replica_writeback_hot_capacity_ratio: 0.75 +fluxonkv_spec: + cluster_name: test_cluster + share_mem_path: /tmp/test_external_hot +"#; + let err = ClientConfigYaml::from_str(external) + .unwrap() + .verify() + .unwrap_err(); + assert!( + err.to_string() + .contains("replica_writeback_hot_capacity_ratio is only valid on owner configs") + ); + } + + #[test] + fn owner_local_reserve_expected_capacity_accepts_exact_fit_payload_target() { + let cfg = ClientConfigYaml::from_str( + r#" +instance_key: test_owner +contribute_to_cluster_pool_size: + dram: 137438953472 + vram: {} +fluxonkv_spec: + etcd_addresses: ["127.0.0.1:2379"] + cluster_name: test_cluster + share_mem_path: /tmp/test_owner_expected + large_file_paths: [/tmp/test_owner_expected_large] + sub_cluster: rack-a +test_spec_config: + owner_local_reserve_expected_capacity: + value_len: 4718592 + payload_capacity_bytes: 109951162777 +"#, + ) + .unwrap(); + let verified = cfg.verify().unwrap(); + let expected = verified + .test_spec_config + .owner_local_reserve_expected_capacity + .unwrap(); + assert_eq!(expected.value_len, 4_718_592); + assert_eq!(expected.payload_capacity_bytes, 109_951_162_777); + assert_eq!( + crate::owner_local_reserve_expected_grant_count( + expected.value_len, + expected.payload_capacity_bytes, + ), + Some(207) + ); + } + + #[test] + fn owner_local_reserve_expected_capacity_rejects_zero_value_len() { + let cfg = ClientConfigYaml::from_str( + r#" +instance_key: test_owner +contribute_to_cluster_pool_size: + dram: 1073741824 + vram: {} +fluxonkv_spec: + etcd_addresses: ["127.0.0.1:2379"] + cluster_name: test_cluster + share_mem_path: /tmp/test_owner_expected_zero + large_file_paths: [/tmp/test_owner_expected_zero_large] + sub_cluster: rack-a +test_spec_config: + owner_local_reserve_expected_capacity: + value_len: 0 + payload_capacity_bytes: 4096 +"#, + ) + .unwrap(); + let err = cfg.verify().unwrap_err(); + assert!(err.to_string().contains( + "test_spec_config.owner_local_reserve_expected_capacity.value_len must be > 0" + )); + } + + #[test] + fn owner_local_reserve_expected_capacity_rejects_physical_target_over_owner_capacity() { + let cfg = ClientConfigYaml::from_str( + r#" +instance_key: test_owner +contribute_to_cluster_pool_size: + dram: 16777216 + vram: {} +fluxonkv_spec: + etcd_addresses: ["127.0.0.1:2379"] + cluster_name: test_cluster + share_mem_path: /tmp/test_owner_expected_too_large + large_file_paths: [/tmp/test_owner_expected_too_large_large] + sub_cluster: rack-a +test_spec_config: + owner_local_reserve_expected_capacity: + value_len: 4096 + payload_capacity_bytes: 4096 +"#, + ) + .unwrap(); + let err = cfg.verify().unwrap_err(); + assert!( + err.to_string() + .contains("exceeding owner dram contribution") + ); + } + + #[test] + fn owner_local_reserve_hard_timeout_is_validated_without_soft_override() { + let mut cfg = TestSpecConfig { + owner_local_reserve_hard_timeout_ms: Some(0), + ..Default::default() + }; + assert!( + validate_owner_local_reserve_timeouts(&cfg) + .unwrap_err() + .to_string() + .contains("owner_local_reserve_hard_timeout_ms must be > 0") + ); + + cfg.owner_local_reserve_hard_timeout_ms = Some(5); + assert!( + validate_owner_local_reserve_timeouts(&cfg) + .unwrap_err() + .to_string() + .contains("must be greater than owner_local_reserve_soft_wait_timeout_ms") + ); + + cfg.owner_local_reserve_hard_timeout_ms = Some(20); + validate_owner_local_reserve_timeouts(&cfg).unwrap(); + } + + #[test] + fn replica_task_max_inflight_is_strictly_bounded() { + for value in [1, 16, 64] { + let cfg = TestSpecConfig { + replica_task_max_inflight: Some(value), + ..Default::default() + }; + validate_test_spec_tcp_thread_tuning(&cfg).unwrap(); + } + for value in [0, 65] { + let cfg = TestSpecConfig { + replica_task_max_inflight: Some(value), + ..Default::default() + }; + assert!( + validate_test_spec_tcp_thread_tuning(&cfg) + .unwrap_err() + .to_string() + .contains("replica_task_max_inflight must be in [1, 64]") + ); + } + } + #[test] fn client_config_zero_contribution_allows_owner_bootstrapped_large_file_paths() { let cfg = ClientConfigYaml::from_str( @@ -2486,6 +2858,79 @@ replica_task_placement: .restrict_to_remote_only_node_roles ); assert_eq!(verified.replica_task_placement.role_queue_window_ms, 2.5); + assert_eq!( + verified.replica_cache_capacity_ratio, + DEFAULT_REPLICA_CACHE_CAPACITY_RATIO + ); + } + + #[test] + fn master_config_validates_replica_cache_capacity_ratio() { + let base = r#" +instance_key: test_master +cluster_name: test_cluster +port: 18080 +etcd_endpoints: ["127.0.0.1:2379"] +network: + subnet_whitelist: ["127.0.0.0/8"] +monitoring: + prometheus_base_url: "http://127.0.0.1:4000/v1/prometheus" +log_dir: /tmp/test_master_logs +replica_cache_capacity_ratio: RATIO +"#; + + let valid = MasterConfigYaml::from_str(&base.replace("RATIO", "0.9")) + .unwrap() + .verify() + .unwrap(); + assert_eq!(valid.replica_cache_capacity_ratio, 0.9); + + for invalid in ["0", "-0.1", "1.01", ".nan"] { + let cfg = MasterConfigYaml::from_str(&base.replace("RATIO", invalid)).unwrap(); + let err = cfg.verify().unwrap_err(); + assert!(format!("{err}").contains("replica_cache_capacity_ratio")); + } + } + + #[test] + fn master_config_validates_replica_writeback_tier1_capacity_ratio() { + let base = r#" +instance_key: test_master +cluster_name: test_cluster +port: 18080 +etcd_endpoints: ["127.0.0.1:2379"] +network: + subnet_whitelist: ["127.0.0.0/8"] +monitoring: + prometheus_base_url: "http://127.0.0.1:4000/v1/prometheus" +log_dir: /tmp/test_master_logs +replica_cache_capacity_ratio: 0.95 +replica_writeback_tier1_capacity_ratio: RATIO +"#; + + let valid = MasterConfigYaml::from_str(&base.replace("RATIO", "0.75")) + .unwrap() + .verify() + .unwrap(); + assert_eq!(valid.replica_writeback_tier1_capacity_ratio, Some(0.75)); + + for invalid in ["0", "-0.1", "0.95", "0.96", ".nan"] { + let cfg = MasterConfigYaml::from_str(&base.replace("RATIO", invalid)).unwrap(); + let err = cfg.verify().unwrap_err(); + assert!(format!("{err}").contains("replica_writeback_tier1_capacity_ratio")); + } + + let unrestricted = base + .replace("RATIO", "0.75") + .replace( + "replica_cache_capacity_ratio: 0.95", + "replica_cache_capacity_ratio: 0.95\nreplica_task_placement:\n restrict_to_remote_only_node_roles: false", + ); + let err = MasterConfigYaml::from_str(&unrestricted) + .unwrap() + .verify() + .unwrap_err(); + assert!(format!("{err}").contains("restrict_to_remote_only_node_roles=true")); } #[test] diff --git a/fluxon_rs/fluxon_kv/src/external_client_api/external_client_test.rs b/fluxon_rs/fluxon_kv/src/external_client_api/external_client_test.rs index 1464285..ed9863e 100644 --- a/fluxon_rs/fluxon_kv/src/external_client_api/external_client_test.rs +++ b/fluxon_rs/fluxon_kv/src/external_client_api/external_client_test.rs @@ -48,6 +48,8 @@ fn new_master_config( pprof_duration_seconds: None, master_ui: None, replica_task_placement: ReplicaTaskPlacementConfig::default(), + replica_cache_capacity_ratio: crate::config::DEFAULT_REPLICA_CACHE_CAPACITY_RATIO, + replica_writeback_tier1_capacity_ratio: None, test_spec_config: TestSpecConfig::default(), } } @@ -78,6 +80,7 @@ fn new_client_config( rdma_device_names: None, }, pprof_duration_seconds: None, + replica_writeback_hot_capacity_ratio: None, redis_compat_listen_addr: None, fluxonkv_spec: FluxonKvSpec { etcd_addresses: vec![etcd.to_string()], @@ -121,6 +124,7 @@ fn new_zero_contribution_client_config( rdma_device_names: None, }, pprof_duration_seconds: None, + replica_writeback_hot_capacity_ratio: None, redis_compat_listen_addr: None, fluxonkv_spec: FluxonKvSpec { etcd_addresses: Vec::new(), diff --git a/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs b/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs index 222b821..fed6a1a 100644 --- a/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs +++ b/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs @@ -13,11 +13,12 @@ use crate::cluster_manager::{ use crate::rpcresp_kvresult_convert::ToResult; use crate::{ client_kv_api::msg_pack::{ - ExternalBatchGetCancelReq, ExternalBatchGetReq, ExternalBatchGetStartReq, - ExternalBatchGetStartResp, ExternalBatchGetTransferReq, ExternalBatchGetTransferResp, - ExternalBatchIsExistReq, ExternalBatchPutCommitItemReq, ExternalBatchPutCommitReq, - ExternalBatchPutCommitResp, ExternalBatchPutStartItemReq, ExternalBatchPutStartReq, - ExternalBatchPutStartResp, ExternalBatchPutTransferEndItemReq, + ExternalBatchGetCancelPlan, ExternalBatchGetCancelReq, ExternalBatchGetItemResp, + ExternalBatchGetReq, ExternalBatchGetStartReq, ExternalBatchGetStartResp, + ExternalBatchGetStartTransferPlan, ExternalBatchGetTransferReq, + ExternalBatchGetTransferResp, ExternalBatchIsExistReq, ExternalBatchPutCommitItemReq, + ExternalBatchPutCommitReq, ExternalBatchPutCommitResp, ExternalBatchPutStartItemReq, + ExternalBatchPutStartReq, ExternalBatchPutStartResp, ExternalBatchPutTransferEndItemReq, ExternalBatchPutTransferEndReq, ExternalBatchPutTransferEndResp, ExternalDeleteAckReq, ExternalDeleteReq, ExternalGetReq, ExternalIsExistReq, ExternalObservabilitySnapshotReq, ExternalPutCommitReq, ExternalPutCommitResp, ExternalPutRevokeReq, ExternalPutRevokeResp, @@ -84,6 +85,101 @@ struct PendingExternalGetStart { first_miss_index: Option, } +#[derive(Clone)] +struct PendingInlineExternalGetStart { + keys: Vec, + items: Vec, + owner_start_time: i64, +} + +fn validate_inline_external_get_start_plan( + keys_len: usize, + items: &[ExternalBatchGetItemResp], +) -> KvResult<()> { + if items.len() != keys_len { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "inline external get_start plan length mismatch: expected={} got={}", + keys_len, + items.len() + ), + })); + } + for (idx, item) in items.iter().enumerate() { + if item.error_code != OK || item.external_memholder_info.is_none() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "inline external get_start plan item must be a hit: index={} error_code={} has_memholder={}", + idx, + item.error_code, + item.external_memholder_info.is_some() + ), + })); + } + } + Ok(()) +} + +fn validate_inline_external_get_owner_generation( + plan_owner_start_time: i64, + current_owner_start_time: i64, +) -> KvResult<()> { + if plan_owner_start_time == current_owner_start_time { + return Ok(()); + } + Err(KvError::Api(ApiError::OwnerStartTimeMismatch { + expected: current_owner_start_time, + got: plan_owner_start_time, + })) +} + +#[cfg(test)] +mod inline_external_get_start_tests { + use super::{ + validate_inline_external_get_owner_generation, validate_inline_external_get_start_plan, + }; + use crate::client_kv_api::msg_pack::ExternalBatchGetItemResp; + use crate::memholder::ExternalMemHolderInfo; + use crate::rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, OK}; + + fn inline_hit(holder_id: u64) -> ExternalBatchGetItemResp { + ExternalBatchGetItemResp { + error_code: OK, + error_json: String::new(), + external_memholder_info: Some(ExternalMemHolderInfo { + offset: holder_id * 4096, + len: 4096, + holder_id, + }), + } + } + + #[test] + fn inline_plan_requires_one_hit_per_requested_key() { + let items = vec![inline_hit(1), inline_hit(2)]; + assert!(validate_inline_external_get_start_plan(2, &items).is_ok()); + assert!(validate_inline_external_get_start_plan(3, &items).is_err()); + + let mut missing = items; + missing[1].external_memholder_info = None; + assert!(validate_inline_external_get_start_plan(2, &missing).is_err()); + } + + #[test] + fn inline_plan_rejects_a_stale_owner_generation() { + assert!(validate_inline_external_get_owner_generation(17, 17).is_ok()); + let err = validate_inline_external_get_owner_generation(17, 18) + .expect_err("stale inline plan must not expose an old mapping"); + assert!(matches!( + err, + KvError::Api(ApiError::OwnerStartTimeMismatch { + expected: 18, + got: 17 + }) + )); + } +} + fn duration_to_i64_us(duration: std::time::Duration) -> i64 { duration.as_micros().min(i64::MAX as u128) as i64 } @@ -357,6 +453,8 @@ pub struct ExternalInner { /// key -> Weak index (dashmap-based) key_weak_memholder_index: DashMap>, pending_external_get_start: DashMap, + /// Fully local plans consumed without a follow-up owner transfer RPC. + pending_inline_external_get_start: DashMap, /// per-key semaphore (permits=1) to ensure single inflight per key inflight1_per_key: SemaphoreMap, put_trace_log_window: Mutex, @@ -422,6 +520,7 @@ impl ExternalClientApi { rpc_caller_client_lease_keepalive: RPCCaller::::new(), key_weak_memholder_index: DashMap::new(), pending_external_get_start: DashMap::new(), + pending_inline_external_get_start: DashMap::new(), inflight1_per_key: SemaphoreMap::new(1, std::time::Duration::from_secs(120)), put_trace_log_window: Mutex::new(ExternalPutTraceLogWindow::new()), })) @@ -1907,11 +2006,12 @@ impl ExternalInner { detail: Some("Shared storage node id unavailable".to_string()), }) })?; + let started_time = self.current_owner_start_time().await; let req = MsgPack { serialize_part: ExternalBatchGetStartReq { keys: keys.clone(), req_node_id: self.view.cluster_manager().get_self_info().id.clone(), - started_time: self.current_owner_start_time().await, + started_time, prefix_best_effort, atomic_group_lens: atomic_group_lens.clone(), transfer_concurrency, @@ -1961,7 +2061,24 @@ impl ExternalInner { } return Err(err); } - return Ok(resp.serialize_part); + let response = resp.serialize_part; + let _ = self + .pending_inline_external_get_start + .remove(&response.handle); + if let ExternalBatchGetStartTransferPlan::InlineLocal { items } = + &response.transfer_plan + { + validate_inline_external_get_start_plan(keys.len(), items)?; + self.pending_inline_external_get_start.insert( + response.handle, + PendingInlineExternalGetStart { + keys: keys.clone(), + items: items.clone(), + owner_start_time: started_time, + }, + ); + } + return Ok(response); } } @@ -1975,6 +2092,87 @@ impl ExternalInner { handle, keys.len() ); + if let Some((_handle, inline_plan)) = self.pending_inline_external_get_start.remove(&handle) + { + if keys != inline_plan.keys { + let expected_keys = inline_plan.keys.clone(); + self.pending_inline_external_get_start + .insert(handle, inline_plan); + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "inline external batch_get_transfer keys mismatch: handle={} expected={:?} got={:?}", + handle, expected_keys, keys + ), + })); + } + + let owner_snapshot = match self.wait_current_owner_mapped_range().await { + Ok(snapshot) => snapshot, + Err(err) => { + self.pending_inline_external_get_start + .insert(handle, inline_plan); + return Err(err); + } + }; + let (_, current_owner_start_time, _, base_ptr_ro, mapped_len) = owner_snapshot; + validate_inline_external_get_owner_generation( + inline_plan.owner_start_time, + current_owner_start_time, + )?; + validate_inline_external_get_start_plan(keys.len(), &inline_plan.items)?; + for (idx, item) in inline_plan.items.iter().enumerate() { + let info = item + .external_memholder_info + .as_ref() + .expect("inline plan was validated above"); + let end = info.offset.checked_add(u64::from(info.len)).ok_or_else(|| { + KvError::Api(ApiError::Unknown { + detail: format!( + "inline external get_start item range overflow: index={} offset={} len={}", + idx, info.offset, info.len + ), + }) + })?; + if end > mapped_len { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "inline external get_start item exceeds owner mapping: index={} end={} mapped_len={}", + idx, end, mapped_len + ), + })); + } + } + + let bandwidth_handle = self + .view + .cluster_manager() + .ipc_bandwidth_attributor_handle() + .expect("ExternalClientApi.batch_get_transfer expects IpcBandwidthAttributor handle to be attached"); + let external_client_id = self.view.cluster_manager().get_self_info().id.clone(); + let mut results = Vec::with_capacity(keys.len()); + for (key, item) in keys.into_iter().zip(inline_plan.items.into_iter()) { + let info = item + .external_memholder_info + .expect("inline plan was validated above"); + if info.len > 0 { + bandwidth_handle.record_tx_bytes(info.len as u64); + } + let holder = Arc::new(ExternalMemHolder::new( + info.offset, + base_ptr_ro + info.offset, + info.len, + info.holder_id, + key.clone(), + external_client_id.clone(), + self.view.clone(), + inline_plan.owner_start_time, + )); + self.key_weak_memholder_index + .insert(key, Arc::downgrade(&holder)); + results.push(Ok(Some(holder))); + } + return Ok(results); + } if keys.is_empty() { return Ok(Vec::new()); } @@ -2072,26 +2270,72 @@ impl ExternalInner { pub async fn cancel_batch_get_start(&self, handle: u64) -> KvResult<()> { tracing::debug!("External cancel_batch_get_start request: handle={}", handle); - let started_time = self.current_owner_start_time().await; - let owner = self.shared_storage_node_id().await.ok_or_else(|| { - KvError::SharedMem(SharedMemError::NotConfigured { - node_id: None, - detail: Some("Shared storage node id unavailable".to_string()), - }) - })?; + let inline_plan = self + .pending_inline_external_get_start + .remove(&handle) + .map(|(_handle, plan)| plan); + let current_owner_start_time = self.current_owner_start_time().await; + if inline_plan + .as_ref() + .is_some_and(|plan| plan.owner_start_time != current_owner_start_time) + { + tracing::info!( + "cancel_batch_get_start: inline plan owner generation is stale; treating holdings as gone" + ); + return Ok(()); + } + let started_time = inline_plan + .as_ref() + .map(|plan| plan.owner_start_time) + .unwrap_or(current_owner_start_time); + let transfer_plan = match inline_plan.as_ref() { + Some(plan) => ExternalBatchGetCancelPlan::InlineLocal { + holder_ids: plan + .items + .iter() + .filter_map(|item| { + item.external_memholder_info + .as_ref() + .map(|info| info.holder_id) + }) + .collect(), + }, + None => ExternalBatchGetCancelPlan::OwnerRpc, + }; + let owner = match self.shared_storage_node_id().await { + Some(owner) => owner, + None => { + if let Some(plan) = inline_plan { + self.pending_inline_external_get_start.insert(handle, plan); + } + return Err(KvError::SharedMem(SharedMemError::NotConfigured { + node_id: None, + detail: Some("Shared storage node id unavailable".to_string()), + })); + } + }; let req = MsgPack { serialize_part: ExternalBatchGetCancelReq { handle, req_node_id: self.view.cluster_manager().get_self_info().id.clone(), started_time, + transfer_plan, }, raw_bytes: Vec::new(), }; - let resp = self + let resp = match self .rpc_caller_external_batch_get_cancel .call(self.view.p2p_module(), owner.into(), req, None, 0) .await - .map_err(KvError::from)?; + { + Ok(resp) => resp, + Err(err) => { + if let Some(plan) = inline_plan { + self.pending_inline_external_get_start.insert(handle, plan); + } + return Err(KvError::from(err)); + } + }; if resp.serialize_part.error_code == OK { return Ok(()); } @@ -2105,6 +2349,9 @@ impl ExternalInner { ); return Ok(()); } + if let Some(plan) = inline_plan { + self.pending_inline_external_get_start.insert(handle, plan); + } Err(err) } @@ -2898,6 +3145,7 @@ key={}, attempt={}/{}, err={}", preferred_sub_cluster: preferred_sub_cluster.map(|s| s.to_string()), }) .collect(), + atomic_group_lens: None, started_time, }, raw_bytes: Vec::new(), diff --git a/fluxon_rs/fluxon_kv/src/kv_test.rs b/fluxon_rs/fluxon_kv/src/kv_test.rs index 4db3a7f..d8331ea 100644 --- a/fluxon_rs/fluxon_kv/src/kv_test.rs +++ b/fluxon_rs/fluxon_kv/src/kv_test.rs @@ -993,6 +993,8 @@ fn new_master_launch( log_dir, master_ui: None, replica_task_placement: ReplicaTaskPlacementConfig::default(), + replica_cache_capacity_ratio: crate::config::DEFAULT_REPLICA_CACHE_CAPACITY_RATIO, + replica_writeback_tier1_capacity_ratio: None, // Keep kv_test self-describing: each round carries the intended transfer mode. test_spec_config: kv_test_round_test_spec_config(round.round_profile), }, @@ -1032,6 +1034,7 @@ fn build_client_launch( contribute_to_cluster_pool_size: contribute_to_cluster_pool_size.clone(), protocol: options.protocol_config.unwrap_or_else(tcp_protocol_config), pprof_duration_seconds: None, + replica_writeback_hot_capacity_ratio: None, redis_compat_listen_addr: None, fluxonkv_spec: FluxonKvSpec { etcd_addresses: fluxonkv_etcd_addresses, diff --git a/fluxon_rs/fluxon_kv/src/kvcore_test_lib.rs b/fluxon_rs/fluxon_kv/src/kvcore_test_lib.rs index 376cc8a..d17dc57 100644 --- a/fluxon_rs/fluxon_kv/src/kvcore_test_lib.rs +++ b/fluxon_rs/fluxon_kv/src/kvcore_test_lib.rs @@ -94,6 +94,8 @@ fn new_master_config_with_cluster( pprof_duration_seconds: None, master_ui: None, replica_task_placement: ReplicaTaskPlacementConfig::default(), + replica_cache_capacity_ratio: crate::config::DEFAULT_REPLICA_CACHE_CAPACITY_RATIO, + replica_writeback_tier1_capacity_ratio: None, test_spec_config: TestSpecConfig::default(), }; println!("fluxonkv core created master config for test: {:?}", conf); @@ -136,6 +138,7 @@ fn new_client_config_with_cluster_and_dram( rdma_device_names: None, }, pprof_duration_seconds: None, + replica_writeback_hot_capacity_ratio: None, redis_compat_listen_addr: None, fluxonkv_spec: FluxonKvSpec { etcd_addresses: vec![etcd], diff --git a/fluxon_rs/fluxon_kv/src/lib.rs b/fluxon_rs/fluxon_kv/src/lib.rs index 609dc47..0842a68 100644 --- a/fluxon_rs/fluxon_kv/src/lib.rs +++ b/fluxon_rs/fluxon_kv/src/lib.rs @@ -31,6 +31,37 @@ pub use crate::cluster_manager::{ClusterEvent, ClusterMember}; pub use fluxon_observability::types::FsMountKind; pub const OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES: u64 = 512 * 1024 * 1024; +pub(crate) const OWNER_LOCAL_RESERVE_MIN_SLOT_SIZE_BYTES: u64 = 4 * 1024; + +pub(crate) fn owner_local_reserve_slot_size_bytes(value_len: u64) -> Option { + let normalized = value_len.max(OWNER_LOCAL_RESERVE_MIN_SLOT_SIZE_BYTES); + let alignment_mask = OWNER_LOCAL_RESERVE_MIN_SLOT_SIZE_BYTES - 1; + let slot_size = normalized + .checked_add(alignment_mask) + .map(|rounded| rounded & !alignment_mask)?; + (slot_size <= OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES).then_some(slot_size) +} + +pub(crate) fn owner_local_reserve_slots_per_grant(slot_size: u64) -> Option { + if slot_size == 0 || slot_size > OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES { + return None; + } + u32::try_from(OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES / slot_size).ok() +} + +pub(crate) fn owner_local_reserve_expected_grant_count( + value_len: u64, + payload_capacity_bytes: u64, +) -> Option { + if value_len == 0 || payload_capacity_bytes == 0 { + return None; + } + let slot_size = owner_local_reserve_slot_size_bytes(value_len)?; + let slots_per_grant = u64::from(owner_local_reserve_slots_per_grant(slot_size)?); + let value_count = + payload_capacity_bytes / value_len + u64::from(payload_capacity_bytes % value_len != 0); + Some(value_count / slots_per_grant + u64::from(value_count % slots_per_grant != 0)) +} pub type MembershipEventReceiver = limit_thirdparty::tokio::sync::abroadcast::Receiver; @@ -804,6 +835,7 @@ fn build_side_transfer_worker_config( test_spec_config.side_transfer_role = Some(SideTransferRole::Worker); test_spec_config.transport_mode = None; test_spec_config.rdma_device_names = None; + test_spec_config.owner_local_reserve_expected_capacity = None; Ok(ClientConfig { cluster_name: owner_config.cluster_name.clone(), @@ -818,6 +850,7 @@ fn build_side_transfer_worker_config( rdma_device_names: None, }, pprof_duration_seconds: owner_config.pprof_duration_seconds, + replica_writeback_hot_capacity_ratio: None, redis_compat_listen_addr: None, fluxonkv_spec: FluxonKvSpec { etcd_addresses: Vec::new(), @@ -868,6 +901,7 @@ fn build_side_transfer_worker_config_yaml( protocol: Some(side_config.protocol), contribute_to_cluster_pool_size: None, pprof_duration_seconds: side_config.pprof_duration_seconds, + replica_writeback_hot_capacity_ratio: None, fluxonkv_spec: crate::config::FluxonKvSpecYaml { etcd_addresses: None, cluster_name: side_config.cluster_name, @@ -1522,6 +1556,8 @@ async fn run_master_impl( master_kv_router_arg: MasterKvRouterNewArg { test_spec_config: config.test_spec_config.clone(), replica_task_placement: config.replica_task_placement.clone(), + replica_cache_capacity_ratio: config.replica_cache_capacity_ratio, + replica_writeback_tier1_capacity_ratio: config.replica_writeback_tier1_capacity_ratio, }, metric_reporter_arg: MetricReporterNewArg { test_spec_config: config.test_spec_config.clone(), @@ -2069,6 +2105,11 @@ async fn run_client_impl( }, client_kv_api_arg: ClientKvApiNewArg { test_spec_config: config.test_spec_config.clone(), + owner_hot_cache_capacity_bytes: config.replica_writeback_hot_capacity_ratio.map( + |ratio| { + (config.contribute_to_cluster_pool_size.dram as f64 * ratio).floor() as u64 + }, + ), }, client_seg_pool_arg: ClientSegPoolNewArg { contribute_size: config.contribute_to_cluster_pool_size.clone(), @@ -2488,6 +2529,7 @@ mod tests { rdma_device_names: None, }, pprof_duration_seconds: None, + replica_writeback_hot_capacity_ratio: None, redis_compat_listen_addr: None, fluxonkv_spec: FluxonKvSpec { etcd_addresses: vec!["http://127.0.0.1:2379".to_string()], @@ -2795,6 +2837,7 @@ mod tests { rdma_device_names: None, }, pprof_duration_seconds: None, + replica_writeback_hot_capacity_ratio: None, redis_compat_listen_addr: None, fluxonkv_spec: FluxonKvSpec { etcd_addresses: Vec::new(), diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/count_prefix_index.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/count_prefix_index.rs index 4c6e34a..ab7cdad 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/count_prefix_index.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/count_prefix_index.rs @@ -1,5 +1,7 @@ use std::collections::HashMap; +type KeyVersion = (u64, u32); + /// Radix tree node used for prefix counting. /// /// Each node tracks the total number of keys in its subtree via `count`. @@ -25,15 +27,33 @@ impl Node { #[derive(Default)] pub struct PrefixRadixTree { root: Node, + /// Current version for every logical key represented in the radix counts. + /// + /// Route publication and final-route reclaim are intentionally processed by separate async + /// actors. Their events can therefore be duplicated or observed out of order. Keeping the + /// version here makes both operations idempotent and prevents an old remove from deleting a + /// newer incarnation of the same key. + versions: HashMap, } impl PrefixRadixTree { pub fn new() -> Self { - Self { root: Node::new() } + Self { + root: Node::new(), + versions: HashMap::new(), + } } - /// Insert a new key. Must only be called once per logical key. - pub fn insert(&mut self, key: &str) { + /// Insert or update a key version. Returns true only when a new logical key was counted. + pub fn insert(&mut self, key: &str, version: KeyVersion) -> bool { + if let Some(current) = self.versions.get_mut(key) { + if *current != version { + *current = version; + } + return false; + } + + self.versions.insert(key.to_string(), version); let bytes = key.as_bytes(); let mut node = &mut self.root; node.count = node @@ -48,25 +68,42 @@ impl PrefixRadixTree { .checked_add(1) .expect("PrefixRadixTree count overflow on insert (child)"); } + true } - /// Remove an existing key. Must only be called for keys that were inserted. - pub fn remove(&mut self, key: &str) { + /// Remove exactly one key version. Missing, duplicate, or stale removes are harmless. + pub fn remove(&mut self, key: &str, version: KeyVersion) -> bool { + if !self + .versions + .get(key) + .is_some_and(|current| *current == version) + { + return false; + } + + // Validate the complete path before mutating any count. This keeps the operation + // non-panicking even if an index built by older code was inconsistent. + let mut current = &self.root; + for &byte in key.as_bytes() { + let Some(child) = current.children.get(&byte) else { + self.versions.remove(key); + return false; + }; + current = child; + } + self.versions.remove(key); + fn remove_inner(node: &mut Node, bytes: &[u8], idx: usize) -> bool { - node.count = node - .count - .checked_sub(1) - .expect("PrefixRadixTree underflow on remove"); + node.count = node.count.saturating_sub(1); if idx == bytes.len() { return node.count == 0; } let b = bytes[idx]; - let child = node - .children - .get_mut(&b) - .expect("PrefixRadixTree remove: missing child for existing key"); + let Some(child) = node.children.get_mut(&b) else { + return node.count == 0; + }; let should_prune = remove_inner(child, bytes, idx + 1); if should_prune { node.children.remove(&b); @@ -75,6 +112,7 @@ impl PrefixRadixTree { } remove_inner(&mut self.root, key.as_bytes(), 0); + true } /// Count keys whose name starts with the given prefix. @@ -89,3 +127,40 @@ impl PrefixRadixTree { node.count } } + +#[cfg(test)] +mod tests { + use super::PrefixRadixTree; + + #[test] + fn duplicate_insert_and_remove_are_idempotent() { + let mut tree = PrefixRadixTree::new(); + assert!(tree.insert("prefix/key", (1, 0))); + assert!(!tree.insert("prefix/key", (1, 0))); + assert_eq!(tree.count_prefix("prefix/"), 1); + + assert!(tree.remove("prefix/key", (1, 0))); + assert!(!tree.remove("prefix/key", (1, 0))); + assert_eq!(tree.count_prefix("prefix/"), 0); + } + + #[test] + fn stale_remove_cannot_delete_newer_key_version() { + let mut tree = PrefixRadixTree::new(); + assert!(tree.insert("prefix/key", (1, 0))); + assert!(!tree.insert("prefix/key", (2, 0))); + assert!(!tree.remove("prefix/key", (1, 0))); + assert_eq!(tree.count_prefix("prefix/"), 1); + + assert!(tree.remove("prefix/key", (2, 0))); + assert_eq!(tree.count_prefix("prefix/"), 0); + } + + #[test] + fn remove_before_delayed_insert_is_a_noop() { + let mut tree = PrefixRadixTree::new(); + assert!(!tree.remove("prefix/key", (3, 0))); + assert!(tree.insert("prefix/key", (3, 0))); + assert_eq!(tree.count_prefix("prefix/"), 1); + } +} diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/delete.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/delete.rs index 4a25934..703257f 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/delete.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/delete.rs @@ -1,8 +1,7 @@ use super::{ MasterKvRouterView, msg_pack::{ - BatchDeleteAckReq, BatchDeleteAckResp, BatchDeleteClientKvMetaCacheReq, DeleteAckReq, - DeleteAckResp, DeleteClientKvMetaCacheItem, DeleteReq, DeleteResp, + BatchDeleteAckReq, BatchDeleteAckResp, DeleteAckReq, DeleteAckResp, DeleteReq, DeleteResp, }, }; use crate::master_kv_router::OneKvNodesRoutes; @@ -11,12 +10,18 @@ use crate::memholder::{ EnsureMemholderMgmtDeleteActorOwned, MasterOwnerMemMgr, MemholderManagerTrait, }; use crate::{ - cluster_manager::NodeID, - p2p::msg_pack::{MsgPack, RPCCaller}, + p2p::msg_pack::MsgPack, rpcresp_kvresult_convert::msg_and_error::{self, kv}, }; use limit_thirdparty::tokio; -use std::{sync::Arc, time::Duration}; +use std::sync::Arc; + +#[cfg(any(test, feature = "test_bins"))] +use super::msg_pack::{BatchDeleteClientKvMetaCacheReq, DeleteClientKvMetaCacheItem}; +#[cfg(any(test, feature = "test_bins"))] +use crate::{cluster_manager::NodeID, p2p::msg_pack::RPCCaller}; +#[cfg(any(test, feature = "test_bins"))] +use std::time::Duration; /// Remove a key from master indices and trigger client cache invalidation broadcast. /// @@ -45,7 +50,7 @@ pub fn do_delete_one_kv_all_replicas( if view.master_kv_router().prefix_index_enabled() { let inner = view.master_kv_router().inner(); let mut tree = inner.prefix_index.write().await; - tree.remove(&key_clone); + tree.remove(&key_clone, deleted_put_id); } if let Err(err) = view @@ -68,6 +73,8 @@ pub fn do_delete_one_kv_all_replicas( if let Some(cache) = view.master_kv_router().get_node_cache_controller(node_id) { let _ = cache.remove(&key_clone); + view.master_kv_router() + .remove_node_writeback_tier1_entry(node_id, &key_clone); tracing::debug!( "Removed key {} from node cache controller: {}", key_clone, @@ -84,6 +91,8 @@ pub fn do_delete_one_kv_all_replicas( } } +/// Test-only direct route removal. Production eviction uses the fenced owner reclaim protocol. +#[cfg(any(test, feature = "test_bins"))] pub fn evict_one_kv_replica_for_node( view: &MasterKvRouterView, key: String, @@ -145,7 +154,7 @@ pub fn evict_one_kv_replica_for_node( let _ = view.spawn("local_evict_remove_prefix_index", async move { let inner = view_task.master_kv_router().inner(); let mut tree = inner.prefix_index.write().await; - tree.remove(&key_for_prefix); + tree.remove(&key_for_prefix, put_id); }); } } diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs index 52d348e..5e0833e 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs @@ -1,5 +1,6 @@ use super::{ - InflightGetInfo, KvRouteInfo, MasterKvRouterView, NodeValueReplicaDesc, OwnerHoldingGetInfo, + InflightGetInfo, KvRouteInfo, MasterKeyActivityCompletionGuard, MasterKvRouterView, + OwnerHoldingGetInfo, msg_pack::{ BatchGetDoneItemResp, BatchGetDoneReq, BatchGetDoneResp, BatchGetRevokeItemResp, BatchGetRevokeReq, BatchGetRevokeResp, BatchGetStartItemResp, BatchGetStartReq, @@ -8,6 +9,7 @@ use super::{ GetStartResp, MemHolderKeepAliveReq, MemHolderKeepAliveResp, MemHolderReleaseReq, MemHolderReleaseResp, }, + route_maintenance::{RoutePublishEvent, enqueue_post_route_maintenance}, }; use crate::master_kv_router::OneKvNodesRoutes; use crate::master_kv_router::put::PutIDForAKey; @@ -28,48 +30,31 @@ use std::{ sync::{Arc, atomic::Ordering}, }; -fn update_moka_for_node( - view: MasterKvRouterView, - node_id: String, - key: String, - weight: u32, - put_id: PutIDForAKey, - new_inserted: bool, -) { +fn touch_moka_for_node(view: MasterKvRouterView, node_id: String, key: String) { if !view.master_kv_router().replica_cache_enabled() { return; } let view_task = view.clone(); - view.spawn("update_moka_for_node", async move { + view.spawn("touch_moka_for_node", async move { if let Some(cache) = view_task .master_kv_router() .get_node_cache_controller(&node_id) { - if new_inserted { - cache.insert( - key.clone(), - NodeValueReplicaDesc { - weight_bytes: weight, - put_id, - }, - ); - tracing::debug!( - "Inserted key: {:?} into node cache: {}, weight={}", - key, - node_id, - weight - ); - } else { - let _ = cache.get(&key); - tracing::debug!( - "Touched key: {:?} on node cache: {} (TTL refresh)", - key, - node_id - ); + if let Some(desc) = cache.get(&key) + && let Some(tier1_cache) = view_task + .master_kv_router() + .get_node_writeback_tier1_controller(&node_id) + { + tier1_cache.insert(key.clone(), desc); } + tracing::debug!( + "Touched key: {:?} on node cache: {} (TTL refresh)", + key, + node_id + ); } else { tracing::warn!( - "No cache controller found for node: {} when updating moka", + "No cache controller found for node: {} when touching moka", node_id ); } @@ -132,6 +117,14 @@ pub async fn handle_get_start( tracing::debug!("Handling GetStartReq: {:?}", req.serialize_part); + let activity_lease = match view + .master_kv_router() + .reserve_inflight_get_key(&req.serialize_part.key) + { + Ok(activity_lease) => activity_lease, + Err(err) => return failed_resp_err(err, None, &view, &req.serialize_part.key), + }; + let get_id = view .master_kv_router() .inner() @@ -303,6 +296,12 @@ pub async fn handle_get_start( error_json: String::new(), server_process_us: 0, }; + view.master_kv_router().record_get_source_selection( + req_node_id.as_ref(), + resp_node_id.as_ref(), + src_len, + allocation_mode, + ); // 创建在途的Get操作信息 let info = InflightGetInfo { put_id: one_kv_nodes_routes.put_id, @@ -313,6 +312,7 @@ pub async fn handle_get_start( allocation: target_allocation, // 存储target allocation route: one_kv_nodes_routes.clone(), allocation_mode, + _activity_lease: activity_lease, }; view.master_kv_router() @@ -326,13 +326,10 @@ pub async fn handle_get_start( // For leased keys, there should be no moka entry; skip touching to avoid // unnecessary cache work. if one_kv_nodes_routes.lease_id.is_none() { - update_moka_for_node( + touch_moka_for_node( view.clone(), src_node_id.to_string(), req.serialize_part.key.clone(), - 0, - one_kv_nodes_routes.put_id, - false, ); } @@ -379,6 +376,8 @@ pub async fn handle_get_revoke( .remove(&get_id) .await { + let _activity_completion = + MasterKeyActivityCompletionGuard::new(inflight_info._activity_lease.clone()); inflight_info.release_durable_slot_if_needed(); tracing::info!("Revoked get operation with get_id: {}", get_id); } else { @@ -409,6 +408,8 @@ pub async fn handle_get_done( .remove(&get_id) .await { + let _activity_completion = + MasterKeyActivityCompletionGuard::new(inflight_info._activity_lease.clone()); let mut allocation_mode = inflight_info.allocation_mode; let route = inflight_info.route.clone(); // clone req_node_id to avoid borrow/move conflict when inserting into kv_routes @@ -441,6 +442,7 @@ pub async fn handle_get_done( if allocation_mode == GetAllocationMode::DurableReplica { let mut promote_committed = false; + let mut route_publish_event = None; if let Some(one_kv_nodes_routes) = view.master_kv_router().inner().kv_routes.get(&key) { if one_kv_nodes_routes.put_id == inflight_info.put_id { let mut nodes_replicas = one_kv_nodes_routes.nodes_replicas.write(); @@ -455,44 +457,18 @@ pub async fn handle_get_done( backing: super::KvReplicaBacking::Allocation( inflight_info.allocation, ), + owner_local_indexed: true, tomb_tag, }, ); promote_committed = true; - // Read lease binding from route snapshot: for this put_id, - // if the key is leased, we must NOT insert into moka. - if one_kv_nodes_routes.lease_id.is_none() { - // notify moka cache controller for requesting node after route insert - // See put.rs for rationale: saturate weight to avoid u32 truncation - let req_weight = if alloc_cap > u32::MAX as u64 { - tracing::warn!( - "moka weight saturation on get_done: key={} put_id=({},{}) cap={}B exceeds u32::MAX; weight set to u32::MAX", - key, - inflight_info.put_id.0, - inflight_info.put_id.1, - alloc_cap - ); - u32::MAX - } else { - alloc_cap as u32 - }; - update_moka_for_node( - view.clone(), - req_node_id.to_string(), - key.clone(), - req_weight, - inflight_info.put_id, - true, - ); - } else { - tracing::debug!( - "Skip moka insert for leased key={} put_id=({},{}) on node {}", - key, - inflight_info.put_id.0, - inflight_info.put_id.1, - req_node_id - ); - } + route_publish_event = Some(RoutePublishEvent::replica_append( + key.clone(), + inflight_info.put_id, + one_kv_nodes_routes.lease_id, + req_node_id.clone(), + alloc_cap, + )); } else { tracing::warn!( "get node is tomb, get_id: {}, put_id: {:?}", @@ -522,10 +498,42 @@ pub async fn handle_get_done( key ); } + if let Some(event) = route_publish_event { + enqueue_post_route_maintenance(&view, event).await; + } if !promote_committed { allocation_mode = GetAllocationMode::Temporary; route.release_get_durable_slot(); } + } else if allocation_mode == GetAllocationMode::ReuseReplica { + let mut local_index_published = false; + if let Some(current_route) = view.master_kv_router().inner().kv_routes.get(&key) { + if current_route.put_id == inflight_info.put_id { + let mut replicas = current_route.nodes_replicas.write(); + if let Some(replica) = replicas.get_mut(&req_node_id) { + local_index_published = !replica.tomb_tag.is_tomb() + && matches!( + &replica.backing, + super::KvReplicaBacking::Allocation(allocation) + if Arc::ptr_eq(allocation, &inflight_info.allocation) + ); + if local_index_published { + replica.owner_local_indexed = true; + } + } + } + } + if !local_index_published { + tracing::warn!( + "Reused get allocation is no longer the current owner route; returning a temporary holder: get_id={} key={} put_id=({},{}) owner={}", + get_id, + key, + inflight_info.put_id.0, + inflight_info.put_id.1, + req_node_id + ); + allocation_mode = GetAllocationMode::Temporary; + } } tracing::info!( diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs index 9e02cf4..c0af49e 100644 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs @@ -3,8 +3,11 @@ mod get; pub mod msg_pack; pub mod placement; pub mod put; +mod reclaim; mod count_prefix_index; +mod route_maintenance; +mod tiered_writeback; use self::{ count_prefix_index::PrefixRadixTree, @@ -17,21 +20,24 @@ use self::{ handle_get_start, }, msg_pack::{ - BatchDeleteAckReq, BatchDeleteClientKvMetaCacheReq, BatchGetDoneReq, BatchGetRevokeReq, - BatchGetStartReq, BatchIsExistReq, BatchPreparePutKeysReq, BatchPutDoneReq, - BatchPutRevokeReq, BatchPutStartReq, BatchReleasePutKeyReservationsReq, CountPrefixReq, - CountPrefixResp, DeleteAckReq, DeleteReq, GetAllocationMode, GetDoneReq, - GetMasterOnlyMetricPartReq, GetMasterOnlyMetricPartResp, GetMetaReq, GetRevokeReq, - GetStartReq, MemHolderKeepAliveReq, MemHolderReleaseReq, PutAppendDoneReq, - PutAppendRevokeReq, PutAppendStartReq, PutDoneReq, PutRevokeReq, PutStartReq, - ReleaseLocalGrantReq, ReserveLocalGrantReq, + BatchDeleteAckReq, BatchDeleteClientKvMetaCacheReq, BatchEnqueueReplicaTaskReq, + BatchGetDoneReq, BatchGetRevokeReq, BatchGetStartReq, BatchIsExistReq, + BatchOwnerReclaimReq, BatchPreparePutKeysReq, BatchPutDoneReq, BatchPutRevokeReq, + BatchPutStartReq, BatchReleasePutKeyReservationsReq, CountPrefixReq, CountPrefixResp, + DeleteAckReq, DeleteReq, GetAllocationMode, GetDoneReq, GetMasterOnlyMetricPartReq, + GetMasterOnlyMetricPartResp, GetMetaReq, GetRevokeReq, GetStartReq, GroupedBatchPutDoneReq, + MemHolderKeepAliveReq, MemHolderReleaseReq, OwnerReclaimBacking, OwnerReclaimItem, + OwnerReclaimReason, PutAppendDoneReq, PutAppendRevokeReq, PutAppendStartReq, + PutAtomicGroup, PutDoneReq, PutRevokeReq, PutStartReq, ReleaseLocalGrantReq, + ReserveLocalGrantReq, }, placement::{PlacementPolicy, build_placement_policy}, put::{ handle_batch_prepare_put_keys, handle_batch_put_done, handle_batch_put_revoke, - handle_batch_put_start, handle_batch_release_put_key_reservations, handle_put_append_done, - handle_put_append_revoke, handle_put_append_start, handle_put_done, handle_put_revoke, - handle_put_start, handle_release_local_grant, handle_reserve_local_grant, + handle_batch_put_start, handle_batch_release_put_key_reservations, + handle_grouped_batch_put_done, handle_put_append_done, handle_put_append_revoke, + handle_put_append_start, handle_put_done, handle_put_revoke, handle_put_start, + handle_release_local_grant, handle_reserve_local_grant, }, }; use crate::ClientKvApiAccessTrait; @@ -57,6 +63,7 @@ use crate::rpcresp_kvresult_convert; use crate::rpcresp_kvresult_convert::msg_and_error::{KvError, OK}; use fluxon_framework::{LogicalModule, define_module}; use fluxon_framework_compiled::upgrade_view_guard::UpgradeViewGuard; +use fluxon_util::map_lock::AMapLock; use async_trait::async_trait; use chrono::Utc; @@ -70,17 +77,59 @@ use std::borrow::Cow; use std::collections::HashSet; use std::collections::{HashMap, VecDeque}; use std::sync::Arc; -use std::sync::atomic::{AtomicU32, AtomicU64, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use tracing::{debug, error, info, warn}; -// Cache capacity policy: fraction of a node's space reserved for the KV cache. -// Keep as a single source of truth to avoid magic numbers scattered across methods. -const MOKA_CACHE_CAPACITY_RATIO: f32 = 0.8; const MAX_GET_DURABLE_REPLICA_SLOTS: u32 = 2; const PLACEMENT_REPORT_INTERVAL_SECS: u64 = 10; const INFLIGHT_PUT_TTL_SECONDS: u64 = 60; const INFLIGHT_PUT_TTL_SECONDS_SKIP_PUT_END_COMMIT: u64 = 5; +const EVICTION_RECLAIM_QUEUE_CAPACITY: usize = 4096; +const POST_ROUTE_MAINTENANCE_QUEUE_CAPACITY: usize = 512; +const TIER1_WRITEBACK_QUEUE_CAPACITY: usize = 4096; + +fn subtract_pending_eviction_weight( + pending_weight: &AtomicU64, + owner_node_id: &str, + completed_weight: u64, +) { + if completed_weight == 0 { + return; + } + pending_weight + .fetch_update(Ordering::AcqRel, Ordering::Acquire, |current| { + current.checked_sub(completed_weight) + }) + .unwrap_or_else(|pending| { + panic!( + "eviction reclaim pending weight underflow for owner {}: pending={} completed={}", + owner_node_id, pending, completed_weight + ) + }); +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum UnrecoverableCacheEvictionContext { + NormalCapacity, + OwnerLocalReserveNoSpace, +} + +fn allow_unrecoverable_cache_eviction( + owner_is_remote_only: bool, + has_ready_remote_only_owner: bool, + context: UnrecoverableCacheEvictionContext, +) -> bool { + // A normal active-tier eviction must preserve the remote copy whenever a remote-only tier is + // available. Physical local-reserve exhaustion is the liveness boundary: if that remote tier + // has filled and no recoverable active-tier entry remains, refusing to evict the last cached + // copy prevents the owner from accepting any subsequent write-back. The existing three-phase + // owner reclaim transaction removes the route and slot atomically, so dropping that cold cache + // entry is safe and a future lookup simply recomputes it. + context == UnrecoverableCacheEvictionContext::OwnerLocalReserveNoSpace + || owner_is_remote_only + || !has_ready_remote_only_owner +} #[derive(Clone, Copy, Debug)] pub enum PutPlacementMode { @@ -91,14 +140,12 @@ pub enum PutPlacementMode { #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum ReservedCapacityReason { LeaseBoundKv, - LocalReserveGrant, } #[derive(Debug, Default)] pub struct NodeCacheReservedCapacity { pub total_bytes: AtomicU64, pub lease_bound_kv_bytes: AtomicU64, - pub local_reserve_grant_bytes: AtomicU64, } impl NodeCacheReservedCapacity { @@ -111,10 +158,6 @@ impl NodeCacheReservedCapacity { self.lease_bound_kv_bytes .fetch_add(delta, Ordering::Relaxed); } - ReservedCapacityReason::LocalReserveGrant => { - self.local_reserve_grant_bytes - .fetch_add(delta, Ordering::Relaxed); - } } } else { let delta = (-delta_bytes) as u64; @@ -124,10 +167,6 @@ impl NodeCacheReservedCapacity { self.lease_bound_kv_bytes .fetch_sub(delta, Ordering::Relaxed); } - ReservedCapacityReason::LocalReserveGrant => { - self.local_reserve_grant_bytes - .fetch_sub(delta, Ordering::Relaxed); - } } } } @@ -151,6 +190,37 @@ pub struct ReplicaCacheNodeObserveSnapshot { pub effective_capacity_bytes: u64, pub reserved_capacity_bytes: u64, pub base_capacity_bytes: u64, + pub pending_eviction_reclaim_bytes: u64, + pub writeback_tier1_entries: u64, + pub writeback_tier1_weighted_bytes: u64, + pub writeback_tier1_capacity_bytes: u64, + pub writeback_tier1_triggered: u64, + pub writeback_tier1_owner_accepted: u64, + pub writeback_tier1_failed: u64, + pub reclaim_master_activity_deferred: u64, + pub reclaim_master_get_holder_observed: u64, + pub reclaim_owner_holder_deferred: u64, + pub reclaim_owner_other_deferred: u64, + pub reclaim_route_changed: u64, + pub reclaim_retry_queued: u64, + pub reclaim_retry_completed: u64, + pub reclaim_retry_restored: u64, + pub reclaim_completed: u64, + pub owner_hot_demotion_attempts: u64, + pub owner_hot_demotion_cohorts: u64, + pub owner_hot_demotion_selected_bytes: u64, + pub owner_hot_demotion_precheck_rejected: u64, + pub owner_hot_demotion_partial_mismatch: u64, + pub recoverable_first_requested_bytes: u64, + pub recoverable_first_selected_bytes: u64, + pub recoverable_first_shortfall_bytes: u64, + pub recoverable_first_eligible_checks: u64, + pub recoverable_first_route_absent_checks: u64, + pub recoverable_first_version_changed_checks: u64, + pub recoverable_first_route_ineligible_checks: u64, + pub recoverable_first_cpu_route_absent_checks: u64, + pub recoverable_first_atomic_group_incomplete_checks: u64, + pub recoverable_first_tp_cohort_incomplete_checks: u64, } #[derive(Clone, Debug, Default)] @@ -208,14 +278,22 @@ pub struct InflightPutInfo { pub req_node_id: NodeID, pub len: u64, pub commit_info: InflightPutCommitInfo, + pub(crate) _activity_lease: Arc, } #[derive(Clone)] pub struct InflightReplicaTaskInfo { pub node_id: NodeID, + pub source_node_id: NodeID, pub key: String, pub put_id: PutIDForAKey, pub target_allocation: Arc>>, + pub demote_source_on_remote_complete: bool, + /// Protect the source-owner copy only after this inclusive replica has been + /// published successfully. Backend-admitted replicas set this bit; tiered + /// write-back and owner-hot exclusive demotion deliberately do not. + pub protect_source_on_remote_complete: bool, + pub(crate) _activity_lease: Arc, } /// Information about a `get` operation that is currently in progress. @@ -229,6 +307,7 @@ pub struct InflightGetInfo { pub allocation: Arc, pub route: Arc, pub allocation_mode: GetAllocationMode, + pub(crate) _activity_lease: Arc, } impl InflightGetInfo { @@ -256,6 +335,222 @@ pub struct LocalReserveGrantInfo { pub struct PreparedPutKeyReservationInfo { pub owner_node_id: NodeID, pub key: String, + pub(crate) _activity_lease: Arc, +} + +#[derive(Default)] +pub(crate) struct EvictionReclaimCounters { + pub master_activity_deferred: AtomicU64, + pub master_get_holder_observed: AtomicU64, + pub owner_holder_deferred: AtomicU64, + pub owner_other_deferred: AtomicU64, + pub route_changed: AtomicU64, + pub retry_queued: AtomicU64, + pub retry_completed: AtomicU64, + pub retry_restored: AtomicU64, + pub completed: AtomicU64, + pub owner_hot_demotion_attempts: AtomicU64, + pub owner_hot_demotion_cohorts: AtomicU64, + pub owner_hot_demotion_selected_bytes: AtomicU64, + pub owner_hot_demotion_precheck_rejected: AtomicU64, + pub owner_hot_demotion_partial_mismatch: AtomicU64, + pub recoverable_first_requested_bytes: AtomicU64, + pub recoverable_first_selected_bytes: AtomicU64, + pub recoverable_first_shortfall_bytes: AtomicU64, + pub recoverable_first_eligible_checks: AtomicU64, + pub recoverable_first_route_absent_checks: AtomicU64, + pub recoverable_first_version_changed_checks: AtomicU64, + pub recoverable_first_route_ineligible_checks: AtomicU64, + pub recoverable_first_cpu_route_absent_checks: AtomicU64, + pub recoverable_first_atomic_group_incomplete_checks: AtomicU64, + pub recoverable_first_tp_cohort_incomplete_checks: AtomicU64, +} + +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] +pub(crate) struct MasterKeyActivitySnapshot { + pub puts: u32, + pub gets: u32, + pub replicas: u32, + pub reclaim_installed: bool, +} + +#[derive(Clone, Copy, Debug)] +enum MasterKeyActivityKind { + Put, + Get, + Replica, +} + +#[derive(Default)] +struct MasterKeyActivityState { + puts: u32, + gets: u32, + replicas: u32, + reclaim: Option, +} + +#[derive(Default)] +pub(crate) struct MasterKeyActivityTable { + states: Mutex>, +} + +pub(crate) struct MasterKeyActivityLease { + table: Arc, + key: String, + kind: MasterKeyActivityKind, + released: AtomicBool, +} + +impl MasterKeyActivityLease { + pub(crate) fn release_now(&self) { + if self + .released + .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire) + .is_ok() + { + self.table.release(&self.key, self.kind); + } + } +} + +impl Drop for MasterKeyActivityLease { + fn drop(&mut self) { + self.release_now(); + } +} + +pub(crate) struct MasterKeyActivityCompletionGuard { + lease: Option>, +} + +impl MasterKeyActivityCompletionGuard { + pub(crate) fn new(lease: Arc) -> Self { + Self { lease: Some(lease) } + } + + pub(crate) fn disarm(&mut self) { + self.lease = None; + } +} + +impl Drop for MasterKeyActivityCompletionGuard { + fn drop(&mut self) { + if let Some(lease) = self.lease.as_ref() { + lease.release_now(); + } + } +} + +impl MasterKeyActivityTable { + fn reserve( + self: &Arc, + key: &str, + kind: MasterKeyActivityKind, + reject_same_kind_if_active: bool, + ) -> Option> { + let mut states = self.states.lock(); + let state = states.entry(key.to_string()).or_default(); + if state.reclaim.is_some() { + return None; + } + let counter = match kind { + MasterKeyActivityKind::Put => &mut state.puts, + MasterKeyActivityKind::Get => &mut state.gets, + MasterKeyActivityKind::Replica => &mut state.replicas, + }; + if reject_same_kind_if_active && *counter > 0 { + return None; + } + *counter = counter + .checked_add(1) + .expect("master per-key activity counter overflow"); + Some(Arc::new(MasterKeyActivityLease { + table: self.clone(), + key: key.to_string(), + kind, + released: AtomicBool::new(false), + })) + } + + fn release(&self, key: &str, kind: MasterKeyActivityKind) { + let mut states = self.states.lock(); + let remove = { + let state = states + .get_mut(key) + .expect("master per-key activity state missing on release"); + let counter = match kind { + MasterKeyActivityKind::Put => &mut state.puts, + MasterKeyActivityKind::Get => &mut state.gets, + MasterKeyActivityKind::Replica => &mut state.replicas, + }; + *counter = counter + .checked_sub(1) + .expect("master per-key activity counter underflow"); + state.puts == 0 && state.gets == 0 && state.replicas == 0 && state.reclaim.is_none() + }; + if remove { + states.remove(key); + } + } + + pub(crate) fn try_install_reclaim( + &self, + item: &OwnerReclaimItem, + ) -> Result<(), MasterKeyActivitySnapshot> { + let mut states = self.states.lock(); + let state = states.entry(item.key.clone()).or_default(); + if state.puts != 0 || state.gets != 0 || state.replicas != 0 || state.reclaim.is_some() { + return Err(MasterKeyActivitySnapshot { + puts: state.puts, + gets: state.gets, + replicas: state.replicas, + reclaim_installed: state.reclaim.is_some(), + }); + } + state.reclaim = Some(item.clone()); + Ok(()) + } + + pub(crate) fn is_quiescent(&self, key: &str) -> bool { + let states = self.states.lock(); + match states.get(key) { + None => true, + Some(state) => { + state.puts == 0 && state.gets == 0 && state.replicas == 0 && state.reclaim.is_none() + } + } + } + + pub(crate) fn reclaim_matches(&self, item: &OwnerReclaimItem) -> bool { + self.states + .lock() + .get(&item.key) + .and_then(|state| state.reclaim.as_ref()) + == Some(item) + } + + pub(crate) fn clear_reclaim(&self, item: &OwnerReclaimItem) -> bool { + let mut states = self.states.lock(); + let Some(state) = states.get_mut(&item.key) else { + return false; + }; + if state.reclaim.as_ref() != Some(item) { + return false; + } + state.reclaim = None; + if state.puts == 0 && state.gets == 0 && state.replicas == 0 { + states.remove(&item.key); + } + true + } + + #[cfg(test)] + fn has_reclaim(&self, key: &str) -> bool { + self.states + .lock() + .get(key) + .is_some_and(|state| state.reclaim.is_some()) + } } async fn handle_count_prefix( @@ -306,9 +601,11 @@ define_module!( pub struct MasterKvRouterNewArg { pub test_spec_config: TestSpecConfig, pub replica_task_placement: ReplicaTaskPlacementConfig, + pub replica_cache_capacity_ratio: f64, + pub replica_writeback_tier1_capacity_ratio: Option, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct NodeValueReplicaDesc { pub weight_bytes: u32, pub put_id: PutIDForAKey, @@ -349,6 +646,10 @@ impl KvReplicaBacking { pub struct KvRouteInfo { pub node_id: NodeID, pub backing: KvReplicaBacking, + /// Whether this owner also published the route backing into its local key index. + /// Replica-task and remote-put targets are raw master-owned allocations and have no + /// owner-side key entry to fence during capacity eviction. + pub owner_local_indexed: bool, pub tomb_tag: NodeTombTag, } @@ -379,6 +680,9 @@ pub struct OneKvNodesRoutes { /// nodes must not insert leased keys into moka caches. pub lease_id: Option, + /// Version-scoped multi-key group supplied by the put caller. + pub atomic_group: Option>, + /// node_id -> KvRouteInfo pub nodes_replicas: RwLock>, pub get_durable_slots_used: AtomicU32, @@ -422,6 +726,464 @@ impl OneKvNodesRoutes { } } +fn route_has_live_replica_on_node(route: &OneKvNodesRoutes, node_id: &str) -> bool { + route + .nodes_replicas + .read() + .iter() + .any(|(candidate, replica)| candidate.as_ref() == node_id && !replica.tomb_tag.is_tomb()) +} + +fn route_live_remote_cache_nodes( + view: &MasterKvRouterView, + route: &OneKvNodesRoutes, +) -> HashSet { + route + .nodes_replicas + .read() + .iter() + .filter_map(|(node_id, replica)| { + if replica.tomb_tag.is_tomb() { + return None; + } + let member = view + .cluster_manager() + .get_member_info_cached(node_id.as_ref()); + placement::member_matches_roles( + member.as_ref(), + &view + .master_kv_router() + .inner() + .replica_task_placement + .remote_only_node_roles, + ) + .then(|| node_id.as_ref().to_string()) + }) + .collect() +} + +const MAX_INFERRED_TP_COHORT_SIZE: usize = 256; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(crate) struct InferredTpKey<'a> { + pub(crate) logical_prefix: &'a str, + pub(crate) rank: usize, + pub(crate) size: usize, +} + +/// Decode the canonical SGLang HiCache suffix `__`. +/// +/// This is deliberately strict and is only used to make owner reclaim more +/// conservative. A key that cannot be decoded keeps the existing non-TP +/// behavior; a decoded TP key whose peer routes are absent or inconsistent is +/// never considered recoverable. +pub(crate) fn infer_sglang_tp_key(key: &str) -> Option> { + let (before_size, raw_size) = key.rsplit_once('_')?; + let (logical_prefix, raw_rank) = before_size.rsplit_once('_')?; + if logical_prefix.is_empty() + || raw_rank.is_empty() + || raw_size.is_empty() + || !raw_rank.bytes().all(|byte| byte.is_ascii_digit()) + || !raw_size.bytes().all(|byte| byte.is_ascii_digit()) + { + return None; + } + let rank = raw_rank.parse::().ok()?; + let size = raw_size.parse::().ok()?; + if size == 0 + || size > MAX_INFERRED_TP_COHORT_SIZE + || rank >= size + || raw_rank != rank.to_string() + || raw_size != size.to_string() + { + return None; + } + Some(InferredTpKey { + logical_prefix, + rank, + size, + }) +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum RecoverableReplicaStatus { + Recoverable, + RouteAbsent, + VersionChanged, + RouteIneligible, + CpuRouteAbsent, + AtomicGroupIncomplete, + TpCohortIncomplete, +} + +fn recoverable_cohort_weight( + expected_entries: &HashMap, + mut recoverable_status: F, +) -> Option +where + F: FnMut(&str, &NodeValueReplicaDesc) -> RecoverableReplicaStatus, +{ + let mut expected_weight = 0u64; + for (key, desc) in expected_entries { + if recoverable_status(key, desc) != RecoverableReplicaStatus::Recoverable { + return None; + } + expected_weight = expected_weight.checked_add(u64::from(desc.weight_bytes))?; + } + (expected_weight != 0).then_some(expected_weight) +} + +impl EvictionReclaimCounters { + fn record_recoverable_first_status(&self, status: RecoverableReplicaStatus) { + let counter = match status { + RecoverableReplicaStatus::Recoverable => &self.recoverable_first_eligible_checks, + RecoverableReplicaStatus::RouteAbsent => &self.recoverable_first_route_absent_checks, + RecoverableReplicaStatus::VersionChanged => { + &self.recoverable_first_version_changed_checks + } + RecoverableReplicaStatus::RouteIneligible => { + &self.recoverable_first_route_ineligible_checks + } + RecoverableReplicaStatus::CpuRouteAbsent => { + &self.recoverable_first_cpu_route_absent_checks + } + RecoverableReplicaStatus::AtomicGroupIncomplete => { + &self.recoverable_first_atomic_group_incomplete_checks + } + RecoverableReplicaStatus::TpCohortIncomplete => { + &self.recoverable_first_tp_cohort_incomplete_checks + } + }; + counter.fetch_add(1, Ordering::Relaxed); + } +} + +fn current_atomic_group_members( + key: &str, + route: &OneKvNodesRoutes, + desc: &NodeValueReplicaDesc, +) -> Result, RecoverableReplicaStatus> { + let Some(group) = route.atomic_group.as_ref() else { + return Ok(vec![msg_pack::PutAtomicGroupMember { + key: key.to_string(), + put_id: desc.put_id, + }]); + }; + if !group + .members + .iter() + .any(|member| member.key == key && member.put_id == desc.put_id) + { + return Err(RecoverableReplicaStatus::AtomicGroupIncomplete); + } + Ok(group.members.clone()) +} + +fn current_tp_cohort_keys( + key: &str, + route: &OneKvNodesRoutes, + desc: &NodeValueReplicaDesc, +) -> Result, RecoverableReplicaStatus> { + let current_members = current_atomic_group_members(key, route, desc)?; + let Some(key_tp) = infer_sglang_tp_key(key) else { + return Ok(current_members + .into_iter() + .map(|member| member.key) + .collect()); + }; + if key_tp.size == 1 { + return Ok(current_members + .into_iter() + .map(|member| member.key) + .collect()); + } + + let mut logical_members = Vec::with_capacity(current_members.len()); + for member in current_members { + let Some(member_tp) = infer_sglang_tp_key(&member.key) else { + return Err(RecoverableReplicaStatus::TpCohortIncomplete); + }; + if member_tp.rank != key_tp.rank || member_tp.size != key_tp.size { + return Err(RecoverableReplicaStatus::TpCohortIncomplete); + } + logical_members.push(member_tp.logical_prefix.to_string()); + } + + let mut cohort_keys = Vec::with_capacity(logical_members.len() * key_tp.size); + for rank in 0..key_tp.size { + cohort_keys.extend( + logical_members + .iter() + .map(|logical_prefix| format!("{logical_prefix}_{rank}_{}", key_tp.size)), + ); + } + Ok(cohort_keys) +} + +fn intersect_remote_nodes( + common_remote_nodes: &mut Option>, + mut member_remote_nodes: HashSet, + owner_node_id: &str, +) -> Result<(), RecoverableReplicaStatus> { + member_remote_nodes.remove(owner_node_id); + if member_remote_nodes.is_empty() { + return Err(RecoverableReplicaStatus::CpuRouteAbsent); + } + match common_remote_nodes.as_mut() { + Some(common) => common.retain(|node_id| member_remote_nodes.contains(node_id)), + None => *common_remote_nodes = Some(member_remote_nodes), + } + if common_remote_nodes.as_ref().is_some_and(HashSet::is_empty) { + return Err(RecoverableReplicaStatus::AtomicGroupIncomplete); + } + Ok(()) +} + +fn validate_recoverable_group( + owner_node_id: &str, + expected_keys: &[String], + expected_put_ids: Option<&[PutIDForAKey]>, + route_lookup: &dyn Fn(&str) -> Option>, + live_remote_nodes: &dyn Fn(&OneKvNodesRoutes) -> HashSet, +) -> Result, RecoverableReplicaStatus> { + if expected_put_ids.is_some_and(|put_ids| put_ids.len() != expected_keys.len()) { + return Err(RecoverableReplicaStatus::AtomicGroupIncomplete); + } + let Some(first_key) = expected_keys.first() else { + return Err(RecoverableReplicaStatus::AtomicGroupIncomplete); + }; + let Some(first_route) = route_lookup(first_key) else { + return Err(RecoverableReplicaStatus::RouteAbsent); + }; + + if expected_keys.len() == 1 { + if expected_put_ids.is_some_and(|put_ids| first_route.put_id != put_ids[0]) { + return Err(RecoverableReplicaStatus::VersionChanged); + } + if first_route.lease_id.is_some() || first_route.atomic_group.is_some() { + return Err(RecoverableReplicaStatus::AtomicGroupIncomplete); + } + let mut common_remote_nodes = None; + intersect_remote_nodes( + &mut common_remote_nodes, + live_remote_nodes(&first_route), + owner_node_id, + )?; + return common_remote_nodes.ok_or(RecoverableReplicaStatus::CpuRouteAbsent); + } + + let Some(group) = first_route.atomic_group.as_ref() else { + return Err(RecoverableReplicaStatus::AtomicGroupIncomplete); + }; + if group.members.len() != expected_keys.len() + || group + .members + .iter() + .zip(expected_keys) + .any(|(member, expected_key)| member.key != *expected_key) + || expected_put_ids.is_some_and(|put_ids| { + group + .members + .iter() + .zip(put_ids) + .any(|(member, expected_put_id)| member.put_id != *expected_put_id) + }) + { + return Err(RecoverableReplicaStatus::AtomicGroupIncomplete); + } + + let mut common_remote_nodes = None; + for member in &group.members { + let Some(member_route) = route_lookup(&member.key) else { + return Err(RecoverableReplicaStatus::RouteAbsent); + }; + if member_route.put_id != member.put_id + || member_route.lease_id.is_some() + || member_route.atomic_group.as_deref() != Some(group.as_ref()) + { + return Err(RecoverableReplicaStatus::AtomicGroupIncomplete); + } + intersect_remote_nodes( + &mut common_remote_nodes, + live_remote_nodes(&member_route), + owner_node_id, + )?; + } + common_remote_nodes.ok_or(RecoverableReplicaStatus::CpuRouteAbsent) +} + +fn validate_current_recoverable_group( + owner_node_id: &str, + route: &OneKvNodesRoutes, + current_members: &[msg_pack::PutAtomicGroupMember], + route_lookup: &dyn Fn(&str) -> Option>, + live_remote_nodes: &dyn Fn(&OneKvNodesRoutes) -> HashSet, +) -> Result, RecoverableReplicaStatus> { + if current_members.len() == 1 { + let mut common_remote_nodes = None; + intersect_remote_nodes( + &mut common_remote_nodes, + live_remote_nodes(route), + owner_node_id, + )?; + return common_remote_nodes.ok_or(RecoverableReplicaStatus::CpuRouteAbsent); + } + let current_keys = current_members + .iter() + .map(|member| member.key.clone()) + .collect::>(); + let current_put_ids = current_members + .iter() + .map(|member| member.put_id) + .collect::>(); + validate_recoverable_group( + owner_node_id, + ¤t_keys, + Some(¤t_put_ids), + route_lookup, + live_remote_nodes, + ) +} + +fn route_recoverable_replica_status_with( + owner_node_id: &str, + key: &str, + route: &OneKvNodesRoutes, + desc: &NodeValueReplicaDesc, + route_lookup: &dyn Fn(&str) -> Option>, + live_remote_nodes: &dyn Fn(&OneKvNodesRoutes) -> HashSet, +) -> RecoverableReplicaStatus { + if route.put_id != desc.put_id { + return RecoverableReplicaStatus::VersionChanged; + } + if route.lease_id.is_some() || !route_has_live_replica_on_node(route, owner_node_id) { + return RecoverableReplicaStatus::RouteIneligible; + } + + let current_members = match current_atomic_group_members(key, route, desc) { + Ok(members) => members, + Err(status) => return status, + }; + let Some(key_tp) = infer_sglang_tp_key(key) else { + return match validate_current_recoverable_group( + owner_node_id, + route, + ¤t_members, + route_lookup, + live_remote_nodes, + ) { + Ok(_) => RecoverableReplicaStatus::Recoverable, + Err(status) => status, + }; + }; + if key_tp.size == 1 { + return match validate_current_recoverable_group( + owner_node_id, + route, + ¤t_members, + route_lookup, + live_remote_nodes, + ) { + Ok(_) => RecoverableReplicaStatus::Recoverable, + Err(status) => status, + }; + } + + let mut logical_members = Vec::with_capacity(current_members.len()); + for member in ¤t_members { + let Some(member_tp) = infer_sglang_tp_key(&member.key) else { + return RecoverableReplicaStatus::TpCohortIncomplete; + }; + if member_tp.rank != key_tp.rank || member_tp.size != key_tp.size { + return RecoverableReplicaStatus::TpCohortIncomplete; + } + logical_members.push(member_tp.logical_prefix.to_string()); + } + + let mut cohort_remote_nodes: Option> = None; + for rank in 0..key_tp.size { + let peer_keys = logical_members + .iter() + .map(|logical_prefix| format!("{logical_prefix}_{rank}_{}", key_tp.size)) + .collect::>(); + let rank_result = if rank == key_tp.rank { + validate_current_recoverable_group( + owner_node_id, + route, + ¤t_members, + route_lookup, + live_remote_nodes, + ) + } else { + validate_recoverable_group( + owner_node_id, + &peer_keys, + None, + route_lookup, + live_remote_nodes, + ) + }; + let rank_remote_nodes = match rank_result { + Ok(nodes) => nodes, + Err(_) => return RecoverableReplicaStatus::TpCohortIncomplete, + }; + match cohort_remote_nodes.as_mut() { + Some(common) => common.retain(|node_id| rank_remote_nodes.contains(node_id)), + None => cohort_remote_nodes = Some(rank_remote_nodes), + } + if cohort_remote_nodes.as_ref().is_some_and(HashSet::is_empty) { + return RecoverableReplicaStatus::TpCohortIncomplete; + } + } + if cohort_remote_nodes.is_some_and(|nodes| !nodes.is_empty()) { + RecoverableReplicaStatus::Recoverable + } else { + RecoverableReplicaStatus::TpCohortIncomplete + } +} + +#[cfg(test)] +fn route_has_recoverable_replica_with( + owner_node_id: &str, + key: &str, + route: &OneKvNodesRoutes, + desc: &NodeValueReplicaDesc, + route_lookup: &dyn Fn(&str) -> Option>, + live_remote_nodes: &dyn Fn(&OneKvNodesRoutes) -> HashSet, +) -> bool { + route_recoverable_replica_status_with( + owner_node_id, + key, + route, + desc, + route_lookup, + live_remote_nodes, + ) == RecoverableReplicaStatus::Recoverable +} + +fn route_recoverable_replica_status( + view: &MasterKvRouterView, + owner_node_id: &str, + key: &str, + route: &OneKvNodesRoutes, + desc: &NodeValueReplicaDesc, +) -> RecoverableReplicaStatus { + route_recoverable_replica_status_with( + owner_node_id, + key, + route, + desc, + &|member_key| { + view.master_kv_router() + .inner() + .kv_routes + .get(member_key) + .map(|entry| entry.clone()) + }, + &|member_route| route_live_remote_cache_nodes(view, member_route), + ) +} + #[cfg(test)] mod tests { use super::*; @@ -433,6 +1195,7 @@ mod tests { let routes = OneKvNodesRoutes { put_id: (1, 0), lease_id: None, + atomic_group: None, nodes_replicas: RwLock::new(HashMap::new()), get_durable_slots_used: AtomicU32::new(0), }; @@ -445,6 +1208,509 @@ mod tests { assert!(routes.try_reserve_get_durable_slot()); } + #[test] + fn reclaim_fence_is_atomic_with_all_master_key_activity() { + let table = Arc::new(MasterKeyActivityTable::default()); + let item = OwnerReclaimItem { + key: "k".to_string(), + put_id: (7, 3), + epoch: 11, + backing: OwnerReclaimBacking::CommittedSlot { + grant_id: 13, + slot_index: 17, + slot_size: 8 * 1024 * 1024, + }, + reason: OwnerReclaimReason::Reserve, + }; + + let get_lease = table + .reserve("k", MasterKeyActivityKind::Get, false) + .expect("get activity should be admitted before reclaim"); + assert!(!table.is_quiescent("k")); + assert_eq!( + table.try_install_reclaim(&item), + Err(MasterKeyActivitySnapshot { + puts: 0, + gets: 1, + replicas: 0, + reclaim_installed: false, + }) + ); + drop(get_lease); + + assert!(table.is_quiescent("k")); + assert!(table.try_install_reclaim(&item).is_ok()); + assert!(!table.is_quiescent("k")); + assert!(table.has_reclaim("k")); + assert!( + table + .reserve("k", MasterKeyActivityKind::Put, false) + .is_none() + ); + assert!( + table + .reserve("k", MasterKeyActivityKind::Get, false) + .is_none() + ); + assert!( + table + .reserve("k", MasterKeyActivityKind::Replica, false) + .is_none() + ); + + assert!(table.clear_reclaim(&item)); + assert!(!table.has_reclaim("k")); + assert!( + table + .reserve("k", MasterKeyActivityKind::Put, true) + .is_some() + ); + } + + #[test] + fn explicit_activity_completion_is_idempotent_with_retired_cache_clones() { + let table = Arc::new(MasterKeyActivityTable::default()); + let lease = table + .reserve("retired-clone", MasterKeyActivityKind::Get, false) + .expect("get activity should be admitted"); + let retired_cache_clone = lease.clone(); + + lease.release_now(); + lease.release_now(); + assert!(table.is_quiescent("retired-clone")); + + drop(lease); + drop(retired_cache_clone); + assert!(table.is_quiescent("retired-clone")); + } + + fn test_route_info(node_id: &str, tomb: bool) -> KvRouteInfo { + let tomb_tag = NodeTombTag::new(); + if tomb { + tomb_tag.set_tomb(); + } + KvRouteInfo { + node_id: node_id.to_string().into(), + backing: KvReplicaBacking::CommittedSlot(CommittedSlotReplica { + owner_node_id: node_id.to_string().into(), + grant_id: 1, + slot_index: 0, + slot_size: 1024, + addr: 0, + len: 1024, + base_addr: 0, + }), + owner_local_indexed: true, + tomb_tag, + } + } + + fn test_route( + put_id: PutIDForAKey, + lease_id: Option, + replicas: Vec<(&str, bool)>, + ) -> OneKvNodesRoutes { + OneKvNodesRoutes { + put_id, + lease_id, + atomic_group: None, + nodes_replicas: RwLock::new( + replicas + .into_iter() + .map(|(node_id, tomb)| { + (node_id.to_string().into(), test_route_info(node_id, tomb)) + }) + .collect(), + ), + get_durable_slots_used: AtomicU32::new(0), + } + } + + fn test_remote_nodes(route: &OneKvNodesRoutes) -> HashSet { + route + .nodes_replicas + .read() + .iter() + .filter_map(|(node_id, replica)| { + (!replica.tomb_tag.is_tomb() && node_id.as_ref().starts_with("cpu")) + .then(|| node_id.as_ref().to_string()) + }) + .collect() + } + + #[test] + fn recoverable_route_requires_live_local_and_live_remote_cache_same_version() { + let desc = NodeValueReplicaDesc { + weight_bytes: 1024, + put_id: (7, 3), + }; + let no_lookup = |_key: &str| None; + let recoverable = |route: &OneKvNodesRoutes| { + route_has_recoverable_replica_with( + "gpu0", + "k", + route, + &desc, + &no_lookup, + &test_remote_nodes, + ) + }; + + let cpu_copy = test_route((7, 3), None, vec![("gpu0", false), ("cpu0", false)]); + assert!(recoverable(&cpu_copy)); + + let local_only = test_route((7, 3), None, vec![("gpu0", false)]); + assert!(!recoverable(&local_only)); + + let gpu_copy = test_route((7, 3), None, vec![("gpu0", false), ("gpu1", false)]); + assert!(!recoverable(&gpu_copy)); + + let remote_tomb = test_route((7, 3), None, vec![("gpu0", false), ("cpu0", true)]); + assert!(!recoverable(&remote_tomb)); + + let local_tomb = test_route((7, 3), None, vec![("gpu0", true), ("cpu0", false)]); + assert!(!recoverable(&local_tomb)); + + let stale = test_route((8, 0), None, vec![("gpu0", false), ("cpu0", false)]); + assert!(!recoverable(&stale)); + + let leased = test_route((7, 3), Some(11), vec![("gpu0", false), ("cpu0", false)]); + assert!(!recoverable(&leased)); + } + + #[test] + fn recoverable_atomic_group_requires_one_common_remote_cache_owner() { + let group = Arc::new(PutAtomicGroup { + members: vec![ + msg_pack::PutAtomicGroupMember { + key: "k0".to_string(), + put_id: (7, 0), + }, + msg_pack::PutAtomicGroupMember { + key: "k1".to_string(), + put_id: (7, 1), + }, + ], + }); + let make_route = |put_id, remote_node: Option<&str>| { + let mut replicas = vec![("gpu0", false)]; + if let Some(remote_node) = remote_node { + replicas.push((remote_node, false)); + } + let mut route = test_route(put_id, None, replicas); + route.atomic_group = Some(group.clone()); + Arc::new(route) + }; + let desc = NodeValueReplicaDesc { + weight_bytes: 1024, + put_id: (7, 0), + }; + + let k0 = make_route((7, 0), Some("cpu0")); + let k1 = make_route((7, 1), Some("cpu0")); + let routes = HashMap::from([("k0".to_string(), k0.clone()), ("k1".to_string(), k1)]); + assert!(route_has_recoverable_replica_with( + "gpu0", + "k0", + &k0, + &desc, + &|key| routes.get(key).cloned(), + &test_remote_nodes, + )); + + let split_k1 = make_route((7, 1), Some("cpu1")); + let split_routes = + HashMap::from([("k0".to_string(), k0.clone()), ("k1".to_string(), split_k1)]); + assert!(!route_has_recoverable_replica_with( + "gpu0", + "k0", + &k0, + &desc, + &|key| split_routes.get(key).cloned(), + &test_remote_nodes, + )); + + let partial_k1 = make_route((7, 1), None); + let partial_routes = HashMap::from([ + ("k0".to_string(), k0.clone()), + ("k1".to_string(), partial_k1), + ]); + assert!(!route_has_recoverable_replica_with( + "gpu0", + "k0", + &k0, + &desc, + &|key| partial_routes.get(key).cloned(), + &test_remote_nodes, + )); + } + + #[test] + fn infer_sglang_tp_key_accepts_only_canonical_suffix() { + assert_eq!( + infer_sglang_tp_key("prefix:page_model_1_2"), + Some(InferredTpKey { + logical_prefix: "prefix:page_model", + rank: 1, + size: 2, + }) + ); + assert!(infer_sglang_tp_key("prefix:page_model_2_2").is_none()); + assert!(infer_sglang_tp_key("prefix:page_model_01_2").is_none()); + assert!(infer_sglang_tp_key("prefix:page_model_x_2").is_none()); + assert!(infer_sglang_tp_key("prefix:page_model_0_0").is_none()); + } + + #[test] + fn recoverable_atomic_group_requires_complete_tp_cohort_on_one_cpu_owner() { + let rank0_group = Arc::new(PutAtomicGroup { + members: vec![ + msg_pack::PutAtomicGroupMember { + key: "page0_model_0_2".to_string(), + put_id: (10, 0), + }, + msg_pack::PutAtomicGroupMember { + key: "page1_model_0_2".to_string(), + put_id: (10, 1), + }, + ], + }); + let rank1_group = Arc::new(PutAtomicGroup { + members: vec![ + msg_pack::PutAtomicGroupMember { + key: "page0_model_1_2".to_string(), + put_id: (11, 0), + }, + msg_pack::PutAtomicGroupMember { + key: "page1_model_1_2".to_string(), + put_id: (11, 1), + }, + ], + }); + let make_route = |put_id, group: Arc, remote_node: Option<&str>| { + let mut replicas = vec![("gpu0", false)]; + if let Some(remote_node) = remote_node { + replicas.push((remote_node, false)); + } + let mut route = test_route(put_id, None, replicas); + route.atomic_group = Some(group); + Arc::new(route) + }; + let rank0_page0 = make_route((10, 0), rank0_group.clone(), Some("cpu0")); + let rank0_page1 = make_route((10, 1), rank0_group.clone(), Some("cpu0")); + let rank1_page0 = make_route((11, 0), rank1_group.clone(), Some("cpu0")); + let rank1_page1 = make_route((11, 1), rank1_group.clone(), Some("cpu0")); + let routes = HashMap::from([ + ("page0_model_0_2".to_string(), rank0_page0.clone()), + ("page1_model_0_2".to_string(), rank0_page1), + ("page0_model_1_2".to_string(), rank1_page0), + ("page1_model_1_2".to_string(), rank1_page1), + ]); + let desc = NodeValueReplicaDesc { + weight_bytes: 1024, + put_id: (10, 0), + }; + assert_eq!( + current_tp_cohort_keys("page0_model_0_2", &rank0_page0, &desc).unwrap(), + vec![ + "page0_model_0_2", + "page1_model_0_2", + "page0_model_1_2", + "page1_model_1_2", + ] + ); + assert!(route_has_recoverable_replica_with( + "gpu0", + "page0_model_0_2", + &rank0_page0, + &desc, + &|key| routes.get(key).cloned(), + &test_remote_nodes, + )); + + let missing_peer_routes = routes + .iter() + .filter(|(key, _)| key.as_str() != "page1_model_1_2") + .map(|(key, route)| (key.clone(), route.clone())) + .collect::>(); + assert_eq!( + route_recoverable_replica_status_with( + "gpu0", + "page0_model_0_2", + &rank0_page0, + &desc, + &|key| missing_peer_routes.get(key).cloned(), + &test_remote_nodes, + ), + RecoverableReplicaStatus::TpCohortIncomplete + ); + + let rank1_page0_cpu1 = make_route((11, 0), rank1_group.clone(), Some("cpu1")); + let rank1_page1_cpu1 = make_route((11, 1), rank1_group, Some("cpu1")); + let split_cpu_routes = routes + .iter() + .map(|(key, route)| (key.clone(), route.clone())) + .chain([ + ("page0_model_1_2".to_string(), rank1_page0_cpu1), + ("page1_model_1_2".to_string(), rank1_page1_cpu1), + ]) + .collect::>(); + assert!(!route_has_recoverable_replica_with( + "gpu0", + "page0_model_0_2", + &rank0_page0, + &desc, + &|key| split_cpu_routes.get(key).cloned(), + &test_remote_nodes, + )); + } + + #[test] + fn recoverable_single_page_requires_all_tp_ranks() { + let rank0 = Arc::new(test_route( + (20, 0), + None, + vec![("gpu0", false), ("cpu0", false)], + )); + let rank1 = Arc::new(test_route( + (21, 0), + None, + vec![("gpu0", false), ("cpu0", false)], + )); + let desc = NodeValueReplicaDesc { + weight_bytes: 1024, + put_id: (20, 0), + }; + let complete = HashMap::from([ + ("page_model_0_2".to_string(), rank0.clone()), + ("page_model_1_2".to_string(), rank1), + ]); + assert!(route_has_recoverable_replica_with( + "gpu0", + "page_model_0_2", + &rank0, + &desc, + &|key| complete.get(key).cloned(), + &test_remote_nodes, + )); + + let rank0_only = HashMap::from([("page_model_0_2".to_string(), rank0.clone())]); + assert!(!route_has_recoverable_replica_with( + "gpu0", + "page_model_0_2", + &rank0, + &desc, + &|key| rank0_only.get(key).cloned(), + &test_remote_nodes, + )); + } + + #[test] + fn owner_hot_demotion_rejects_the_whole_cohort_before_moka_selection() { + let expected_entries = HashMap::from([ + ( + "rank0".to_string(), + NodeValueReplicaDesc { + weight_bytes: 1024, + put_id: (30, 0), + }, + ), + ( + "rank1".to_string(), + NodeValueReplicaDesc { + weight_bytes: 1024, + put_id: (31, 0), + }, + ), + ]); + let cache = moka::sync::SegmentedCache::builder(8) + .weigher(Box::new(|_key: &String, desc: &NodeValueReplicaDesc| { + desc.weight_bytes + })) + .build(); + for (key, desc) in &expected_entries { + cache.insert(key.clone(), desc.clone()); + } + cache.run_pending_tasks(); + + let selected_weight = recoverable_cohort_weight(&expected_entries, |key, _desc| { + if key == "rank0" { + RecoverableReplicaStatus::Recoverable + } else { + RecoverableReplicaStatus::TpCohortIncomplete + } + }) + .map_or(0, |expected_weight| { + cache.evict_some_if(expected_weight, |candidate_key, candidate_desc| { + expected_entries.get(candidate_key).is_some_and(|expected| { + expected.put_id == candidate_desc.put_id + && expected.weight_bytes == candidate_desc.weight_bytes + }) + }) + }); + + assert_eq!(selected_weight, 0); + assert!(cache.get("rank0").is_some()); + assert!(cache.get("rank1").is_some()); + } + + #[test] + fn unrecoverable_fallback_is_only_for_last_level_or_no_remote_tier() { + assert!(allow_unrecoverable_cache_eviction( + false, + false, + UnrecoverableCacheEvictionContext::NormalCapacity, + )); + assert!(!allow_unrecoverable_cache_eviction( + false, + true, + UnrecoverableCacheEvictionContext::NormalCapacity, + )); + assert!(allow_unrecoverable_cache_eviction( + true, + true, + UnrecoverableCacheEvictionContext::NormalCapacity, + )); + assert!(allow_unrecoverable_cache_eviction( + false, + true, + UnrecoverableCacheEvictionContext::OwnerLocalReserveNoSpace, + )); + } + + #[test] + fn unbounded_segmented_metadata_cache_only_evicts_when_requested() { + let cache = moka::sync::SegmentedCache::builder(8) + .weigher(Box::new(|_key: &u64, weight: &u32| *weight)) + .build(); + assert_eq!(cache.policy().max_capacity(), None); + + for key in 0..128 { + cache.insert(key, 8); + } + cache.run_pending_tasks(); + assert_eq!(cache.weighted_size(), 1024); + + let evicted = cache.evict_some_if(64, |_key, _weight| true); + assert!(evicted >= 64); + assert_eq!(cache.weighted_size(), 1024 - evicted); + } + + #[test] + fn synchronous_restore_re_eviction_keeps_new_pending_weight() { + let weight = 8 * 1024 * 1024; + let pending = AtomicU64::new(weight); + + // A synchronous Moka Size listener enqueues the restored entry again before the old + // request completes. Completing the old request must leave exactly the new request. + pending.fetch_add(weight, Ordering::AcqRel); + subtract_pending_eviction_weight(&pending, "owner", weight); + assert_eq!(pending.load(Ordering::Acquire), weight); + + subtract_pending_eviction_weight(&pending, "owner", weight); + assert_eq!(pending.load(Ordering::Acquire), 0); + } + fn new_test_member(metadata: HashMap) -> ClusterMember { ClusterMember { id: "node-a".to_string(), @@ -488,6 +1754,33 @@ mod tests { &side_worker )); } + + #[test] + fn tier1_source_accepts_gpu_owner_role_and_rejects_remote_cache() { + let placement_config = ReplicaTaskPlacementConfig::default(); + + // This is the production GPU-owner shape: it deliberately does not match the + // prefill/decode roles carried by the associated zero-contribution client. + let gpu_owner = new_test_member(HashMap::from([ + ("client".to_string(), "true".to_string()), + ("p2p_relay".to_string(), "true".to_string()), + ])); + assert!(MasterKvRouter::tier1_source_member_eligible( + Some(&gpu_owner), + &placement_config, + )); + + let mut remote_cache = gpu_owner.clone(); + remote_cache.sub_cluster = Some("remote_cache".to_string()); + assert!(!MasterKvRouter::tier1_source_member_eligible( + Some(&remote_cache), + &placement_config, + )); + assert!(!MasterKvRouter::tier1_source_member_eligible( + None, + &placement_config, + )); + } } pub struct MasterKvRouterInner { @@ -495,13 +1788,14 @@ pub struct MasterKvRouterInner { pub policy: Box, test_spec_config: TestSpecConfig, pub replica_task_placement: ReplicaTaskPlacementConfig, + replica_cache_capacity_ratio: f64, + replica_writeback_tier1_capacity_ratio: Option, /// (key, put_time_ms, put_version) -> inflight_put_info pub inflight_puts: moka::future::Cache<(String, u64, u32), InflightPutInfo>, pub inflight_replica_tasks: moka::future::Cache<(String, u64, u32), InflightReplicaTaskInfo>, - /// key -> inflight put count - pub inflight_put_key_counts: Arc>, pub inflight_gets: moka::future::Cache, + pub(crate) key_activity: Arc, /// Cache for holding get operations (owned, flattened by (node_id, holder_id)) pub get_holding: MasterOwnerMemMgr, @@ -518,9 +1812,15 @@ pub struct MasterKvRouterInner { /// Counter for prepared put-key reservation identifiers. pub next_prepared_put_key_reservation_id: AtomicU64, + /// Counter for two-sided owner reclaim epochs. + pub next_owner_reclaim_epoch: AtomicU64, + /// Latest version of key-value replicas pub kv_routes: DashMap>, + /// Interns recent multi-key put groups so all member routes share one descriptor. + put_atomic_groups: moka::sync::SegmentedCache<(String, u64, u32), Arc>, + /// Serializes route-level existence checks with cache-eviction route cleanup. /// This protects route metadata consistency only; it does not create MemHolders /// or move payload data. @@ -539,11 +1839,28 @@ pub struct MasterKvRouterInner { pub node_kv_cache_controller: DashMap>>, + /// Inclusive hot tier. L1 eviction starts a remote-only replica task while the owner copy + /// remains governed by `node_kv_cache_controller` at its unchanged resident capacity. + pub node_writeback_tier1_controller: + DashMap>>, + /// Per-node bytes reserved out of moka usable capacity. /// The reservation is reason-grouped, but `total_bytes` is the authority /// used to derive the effective moka max_capacity for the node. pub node_cache_reserved_capacity: DashMap>, + /// Moka weight already removed and queued for owner-side safe reclaim. + pub eviction_reclaim_pending_weight: DashMap>, + + /// Per-owner reclaim lifecycle counters. These distinguish transient holder/activity + /// deferrals from terminal route changes and bounded retry restoration. + pub(crate) eviction_reclaim_counters: DashMap>, + + /// Serializes all append completions for one logical TP/atomic cohort. Without this lock, + /// several member completions can pass the recoverability precheck together and concurrently + /// select overlapping subsets from Moka. + owner_hot_demotion_locks: AMapLock, + /// Historical final put placement decisions by target node. pub put_target_decision_counts: DashMap>, @@ -556,10 +1873,25 @@ pub struct MasterKvRouterInner { /// Historical accepted replica task reservations by target node. pub replica_task_target_counts: DashMap>, + /// Historical get source choices by requester->source pair. + pub get_requester_source_counts: DashMap>, + pub get_requester_source_bytes: DashMap>, + pub get_allocation_mode_counts: DashMap<&'static str, Arc>, + /// Support replicas: key -> version_id recent_key_versionid_allocator: moka::sync::SegmentedCache>, pub delete_broadcast: EnsureMemholderMgmtDeleteHandle, + post_route_maintenance_tx: ampsc::Sender, + post_route_maintenance_rx: Mutex>>, + eviction_reclaim_tx: ampsc::Sender, + eviction_reclaim_rx: Mutex>>, + tier1_writeback_tx: ampsc::Sender, + tier1_writeback_rx: Mutex>>, + tier1_writeback_dedupe: moka::sync::SegmentedCache<(String, u64, u32), ()>, + tier1_writeback_trigger_counts: DashMap>, + tier1_writeback_owner_accepted_counts: DashMap>, + tier1_writeback_failed_counts: DashMap>, } impl MasterKvRouterInner { @@ -645,16 +1977,16 @@ impl MasterKvRouter { } else { INFLIGHT_PUT_TTL_SECONDS }; - let inflight_put_key_counts: Arc> = Arc::new(DashMap::new()); - let inflight_put_key_counts_for_listener = inflight_put_key_counts.clone(); + let key_activity = Arc::new(MasterKeyActivityTable::default()); let inflight_puts = moka::future::Cache::builder() .time_to_live(Duration::from_secs(inflight_put_ttl_seconds)) - .eviction_listener(move |_put_id, inflight_info: InflightPutInfo, cause| { + .eviction_listener(|_put_id, inflight_info: InflightPutInfo, cause| { if cause == RemovalCause::Expired { - MasterKvRouter::release_inflight_put_key_count_map( - &inflight_put_key_counts_for_listener, - &inflight_info.key, - ); + inflight_info._activity_lease.release_now(); + if let Some(replica_target) = inflight_info.commit_info.replica_target.as_ref() + { + replica_target._activity_lease.release_now(); + } } }) .build(); @@ -663,43 +1995,81 @@ impl MasterKvRouter { .eviction_listener(|_get_id, inflight_info: InflightGetInfo, cause| { if cause == RemovalCause::Expired { inflight_info.release_durable_slot_if_needed(); + inflight_info._activity_lease.release_now(); } }) .build(); let inflight_replica_tasks = moka::future::Cache::builder() .time_to_live(Duration::from_secs(60)) + .eviction_listener(|_put_id, inflight_info: InflightReplicaTaskInfo, cause| { + if cause == RemovalCause::Expired { + inflight_info._activity_lease.release_now(); + } + }) .build(); + let (eviction_reclaim_tx, eviction_reclaim_rx) = + ampsc::channel(EVICTION_RECLAIM_QUEUE_CAPACITY); + let (post_route_maintenance_tx, post_route_maintenance_rx) = + ampsc::channel(POST_ROUTE_MAINTENANCE_QUEUE_CAPACITY); + let (tier1_writeback_tx, tier1_writeback_rx) = + ampsc::channel(TIER1_WRITEBACK_QUEUE_CAPACITY); let inner = MasterKvRouterInner { view: std::sync::OnceLock::new(), policy: policy_impl, test_spec_config: arg.test_spec_config, replica_task_placement: arg.replica_task_placement, + replica_cache_capacity_ratio: arg.replica_cache_capacity_ratio, + replica_writeback_tier1_capacity_ratio: arg.replica_writeback_tier1_capacity_ratio, inflight_puts, inflight_replica_tasks, - inflight_put_key_counts, inflight_gets, + key_activity, get_holding: MasterOwnerMemMgr::default(), next_get_id: AtomicU64::new(0), next_holder_id: AtomicU64::new(0), next_local_reserve_grant_id: AtomicU64::new(1), next_prepared_put_key_reservation_id: AtomicU64::new(1), + next_owner_reclaim_epoch: AtomicU64::new(1), kv_routes: DashMap::new(), + put_atomic_groups: moka::sync::SegmentedCache::builder(8) + .max_capacity(262_144) + .time_to_idle(Duration::from_secs(30 * 60)) + .build(), route_lifetime_lock: Mutex::new(()), local_reserve_grants: DashMap::new(), prepared_put_key_reservations: DashMap::new(), prefix_index: ARwLock::new(PrefixRadixTree::new()), node_kv_cache_controller: DashMap::new(), + node_writeback_tier1_controller: DashMap::new(), node_cache_reserved_capacity: DashMap::new(), + eviction_reclaim_pending_weight: DashMap::new(), + eviction_reclaim_counters: DashMap::new(), + owner_hot_demotion_locks: AMapLock::new(Duration::from_secs(10 * 60)), put_target_decision_counts: DashMap::new(), put_requester_target_decision_counts: DashMap::new(), put_placement_mode_counts: DashMap::new(), replica_task_target_counts: DashMap::new(), + get_requester_source_counts: DashMap::new(), + get_requester_source_bytes: DashMap::new(), + get_allocation_mode_counts: DashMap::new(), recent_key_versionid_allocator: moka::sync::SegmentedCache::builder(8) .time_to_idle(Duration::from_secs(5)) .build(), delete_broadcast: EnsureMemholderMgmtDeleteHandle::new( MasterOwnerMemMgr::DELETE_SUBMIT_QUEUE_CAPACITY, ), + post_route_maintenance_tx, + post_route_maintenance_rx: Mutex::new(Some(post_route_maintenance_rx)), + eviction_reclaim_tx, + eviction_reclaim_rx: Mutex::new(Some(eviction_reclaim_rx)), + tier1_writeback_tx, + tier1_writeback_rx: Mutex::new(Some(tier1_writeback_rx)), + tier1_writeback_dedupe: moka::sync::SegmentedCache::builder(8) + .time_to_live(Duration::from_secs(60)) + .build(), + tier1_writeback_trigger_counts: DashMap::new(), + tier1_writeback_owner_accepted_counts: DashMap::new(), + tier1_writeback_failed_counts: DashMap::new(), }; Ok(Self(inner)) } @@ -720,6 +2090,27 @@ impl MasterKvRouter { .take_rx() .expect("delete_broadcast rx already taken, that's impossible"); delete::spawn_delete_broadcast(view, delete_broadcast_rx); + if let Some(post_route_maintenance_rx) = self.0.post_route_maintenance_rx.lock().take() { + route_maintenance::spawn_post_route_maintenance_actor( + self.0.view().clone(), + post_route_maintenance_rx, + ); + } else { + warn!("post_route_maintenance_rx already taken for MasterKvRouter"); + } + if let Some(eviction_reclaim_rx) = self.0.eviction_reclaim_rx.lock().take() { + reclaim::spawn_eviction_reclaim_actor(self.0.view().clone(), eviction_reclaim_rx); + } else { + warn!("eviction_reclaim_rx already taken for MasterKvRouter"); + } + if let Some(tier1_writeback_rx) = self.0.tier1_writeback_rx.lock().take() { + tiered_writeback::spawn_tier1_writeback_actor( + self.0.view().clone(), + tier1_writeback_rx, + ); + } else { + warn!("tier1_writeback_rx already taken for MasterKvRouter"); + } Ok(()) } @@ -731,6 +2122,86 @@ impl MasterKvRouter { &self.0 } + fn replica_cache_base_capacity(&self, node_space_size: u64) -> u64 { + (node_space_size as f64 * self.inner().replica_cache_capacity_ratio).floor() as u64 + } + + fn replica_cache_effective_capacity(&self, node_id: &str, node_space_size: u64) -> u64 { + let reserved_capacity = self + .inner() + .node_cache_reserved_capacity + .get(node_id) + .map(|reserved| reserved.total_reserved_bytes()) + .unwrap_or(0); + self.replica_cache_base_capacity(node_space_size) + .saturating_sub(reserved_capacity) + } + + fn owner_cache_allows_unrecoverable_eviction_in_context( + &self, + owner_node_id: &str, + context: UnrecoverableCacheEvictionContext, + ) -> bool { + let remote_only_roles = &self.inner().replica_task_placement.remote_only_node_roles; + let owner = self + .inner() + .view() + .cluster_manager() + .get_member_info_cached(owner_node_id); + let owner_is_remote_only = + placement::member_matches_roles(owner.as_ref(), remote_only_roles); + let has_ready_remote_only_owner = self + .inner() + .view() + .cluster_manager() + .get_members() + .into_iter() + .any(|member| { + placement::member_matches_roles(Some(&member), remote_only_roles) + && self + .inner() + .view() + .master_seg_manager() + .get_node_space_size(member.id.as_str()) + != 0 + }); + allow_unrecoverable_cache_eviction( + owner_is_remote_only, + has_ready_remote_only_owner, + context, + ) + } + + pub(crate) fn owner_cache_allows_unrecoverable_eviction(&self, owner_node_id: &str) -> bool { + self.owner_cache_allows_unrecoverable_eviction_in_context( + owner_node_id, + UnrecoverableCacheEvictionContext::NormalCapacity, + ) + } + + pub(crate) fn owner_cache_allows_unrecoverable_reserve_pressure_eviction( + &self, + owner_node_id: &str, + ) -> bool { + self.owner_cache_allows_unrecoverable_eviction_in_context( + owner_node_id, + UnrecoverableCacheEvictionContext::OwnerLocalReserveNoSpace, + ) + } + + fn writeback_tier1_base_capacity(&self, node_space_size: u64) -> Option { + self.inner() + .replica_writeback_tier1_capacity_ratio + .map(|ratio| (node_space_size as f64 * ratio).floor() as u64) + } + + pub fn tiered_writeback_enabled(&self) -> bool { + self.inner() + .replica_writeback_tier1_capacity_ratio + .is_some() + && self.replica_cache_enabled() + } + pub fn replica_cache_enabled(&self) -> bool { !self.0.test_spec_config.disable_master_replica_cache } @@ -753,63 +2224,531 @@ impl MasterKvRouter { (put_time_ms, put_version) } - fn release_inflight_put_key_count_map(counts: &DashMap, key: &str) { - if let Some(mut entry) = counts.get_mut(key) { - if *entry <= 1 { - drop(entry); - counts.remove(key); - } else { - *entry -= 1; + pub(crate) fn reserve_inflight_put_key( + &self, + key: &str, + reject_if_inflight_same_key: bool, + reject_if_exist_same_key: bool, + ) -> Result, KvError> { + if reject_if_exist_same_key && self.key_has_live_replica(key) { + return Err(KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::KeyAlreadyExists { + key: key.to_string(), + }, + )); + } + self.inner() + .key_activity + .reserve(key, MasterKeyActivityKind::Put, reject_if_inflight_same_key) + .ok_or_else(|| { + KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::KeyBeingWritten { + key: key.to_string(), + }, + ) + }) + } + + pub(crate) fn reserve_inflight_get_key( + &self, + key: &str, + ) -> Result, KvError> { + self.inner() + .key_activity + .reserve(key, MasterKeyActivityKind::Get, false) + .ok_or_else(|| { + KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::KeyNotFound { + key: key.to_string(), + }, + ) + }) + } + + pub(crate) fn reserve_inflight_replica_key( + &self, + key: &str, + ) -> Result, KvError> { + self.inner() + .key_activity + .reserve(key, MasterKeyActivityKind::Replica, false) + .ok_or_else(|| { + KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::KeyBeingWritten { + key: key.to_string(), + }, + ) + }) + } + + pub fn key_has_live_replica(&self, key: &str) -> bool { + self.inner() + .kv_routes + .get(key) + .map(|one_kv_nodes_routes| { + one_kv_nodes_routes + .nodes_replicas + .read() + .values() + .any(|kv_info| !kv_info.tomb_tag.is_tomb()) + }) + .unwrap_or(false) + } + + pub(crate) fn resolve_put_atomic_group( + &self, + key: &str, + put_id: PutIDForAKey, + group: Option, + ) -> Result>, KvError> { + let Some(group) = group else { + return Ok(None); + }; + if !(2..=4096).contains(&group.members.len()) { + return Err(KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::InvalidArgument { + detail: format!( + "put atomic group must contain 2..=4096 members; got={}", + group.members.len() + ), + }, + )); + } + let mut keys = HashSet::with_capacity(group.members.len()); + let mut current_member_count = 0usize; + for member in &group.members { + if member.key.is_empty() || !keys.insert(member.key.as_str()) { + return Err(KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::InvalidArgument { + detail: "put atomic group member keys must be non-empty and unique" + .to_string(), + }, + )); + } + if member.key == key && member.put_id == put_id { + current_member_count += 1; } } + if current_member_count != 1 { + return Err(KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::InvalidArgument { + detail: format!( + "put atomic group must contain current member exactly once: key={} put_id=({},{}) count={}", + key, put_id.0, put_id.1, current_member_count + ), + }, + )); + } + + let anchor = group + .members + .first() + .expect("validated non-empty put atomic group"); + let cache_key = (anchor.key.clone(), anchor.put_id.0, anchor.put_id.1); + if let Some(existing) = self.inner().put_atomic_groups.get(&cache_key) { + if existing.as_ref() != &group { + return Err(KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::InvalidArgument { + detail: format!( + "put atomic group anchor was reused with different membership: anchor_key={} anchor_put_id=({},{})", + anchor.key, anchor.put_id.0, anchor.put_id.1 + ), + }, + )); + } + return Ok(Some(existing)); + } + let group = Arc::new(group); + self.inner() + .put_atomic_groups + .insert(cache_key, group.clone()); + Ok(Some(group)) + } + + pub(crate) fn next_owner_reclaim_epoch(&self) -> u64 { + self.inner() + .next_owner_reclaim_epoch + .fetch_add(1, Ordering::Relaxed) + } + + fn enqueue_eviction_reclaim( + &self, + owner_node_id: NodeIDString, + key: String, + desc: NodeValueReplicaDesc, + ) { + let weight_bytes = desc.weight_bytes; + let pending_weight = self + .inner() + .eviction_reclaim_pending_weight + .entry(owner_node_id.clone()) + .or_insert_with(|| Arc::new(AtomicU64::new(0))) + .value() + .clone(); + pending_weight.fetch_add(u64::from(weight_bytes), Ordering::AcqRel); + let request = reclaim::EvictionReclaimRequest { + owner_node_id, + key, + desc, + retry_count: 0, + }; + if let Err(err) = self.inner().eviction_reclaim_tx.try_send(request) { + let queue_error = err.to_string(); + let request = err.into_inner(); + subtract_pending_eviction_weight( + pending_weight.as_ref(), + request.owner_node_id.as_str(), + u64::from(weight_bytes), + ); + let restored = self.restore_eviction_cache_entry_if_current( + request.owner_node_id.as_str(), + request.key, + request.desc, + ); + warn!( + "safe eviction reclaim queue is full or closed: {}; restored={}", + queue_error, restored + ); + } + } + + pub(crate) fn eviction_reclaim_pending_weight(&self, owner_node_id: &str) -> u64 { + self.inner() + .eviction_reclaim_pending_weight + .get(owner_node_id) + .map(|weight| weight.load(Ordering::Acquire)) + .unwrap_or(0) + } + + pub(crate) fn eviction_reclaim_counters( + &self, + owner_node_id: &str, + ) -> Arc { + self.inner() + .eviction_reclaim_counters + .entry(owner_node_id.to_string()) + .or_insert_with(|| Arc::new(EvictionReclaimCounters::default())) + .value() + .clone() + } + + pub(crate) fn complete_eviction_reclaim_weight( + &self, + owner_node_id: &str, + completed_weight: u64, + ) { + if completed_weight == 0 { + return; + } + let pending_weight = self + .inner() + .eviction_reclaim_pending_weight + .get(owner_node_id) + .unwrap_or_else(|| { + panic!( + "eviction reclaim pending weight missing for owner {}", + owner_node_id + ) + }); + subtract_pending_eviction_weight( + pending_weight.value().as_ref(), + owner_node_id, + completed_weight, + ); + } + + pub(crate) fn restore_eviction_cache_entry_if_current( + &self, + owner_node_id: &str, + key: String, + desc: NodeValueReplicaDesc, + ) -> bool { + if !self.eviction_cache_entry_is_current(owner_node_id, &key, &desc) { + return false; + } + self.insert_node_cache_entry(owner_node_id, key, desc) + } + + pub(crate) fn eviction_cache_entry_is_current( + &self, + owner_node_id: &str, + key: &str, + desc: &NodeValueReplicaDesc, + ) -> bool { + self.inner().kv_routes.get(key).is_some_and(|route| { + route.put_id == desc.put_id + && route.lease_id.is_none() + && route + .nodes_replicas + .read() + .iter() + .any(|(node_id, replica)| { + node_id.as_ref() == owner_node_id && !replica.tomb_tag.is_tomb() + }) + }) + } + + fn eviction_cache_entry_recoverable_status( + &self, + owner_node_id: &str, + key: &str, + desc: &NodeValueReplicaDesc, + ) -> RecoverableReplicaStatus { + let Some(route) = self.inner().kv_routes.get(key).map(|route| route.clone()) else { + return RecoverableReplicaStatus::RouteAbsent; + }; + route_recoverable_replica_status(self.inner().view(), owner_node_id, key, &route, desc) + } + + pub(crate) fn evict_recoverable_cache_weight( + &self, + owner_node_id: &str, + requested_weight: u64, + ) -> u64 { + self.evict_recoverable_cache_weight_excluding( + owner_node_id, + requested_weight, + &HashSet::new(), + ) + } + + pub(crate) fn evict_recoverable_cache_weight_excluding( + &self, + owner_node_id: &str, + requested_weight: u64, + excluded_keys: &HashSet, + ) -> u64 { + if requested_weight == 0 { + return 0; + } + let Some(cache) = self.get_node_cache_controller(owner_node_id) else { + return 0; + }; + let counters = self.eviction_reclaim_counters(owner_node_id); + counters + .recoverable_first_requested_bytes + .fetch_add(requested_weight, Ordering::Relaxed); + let selected_weight = cache.evict_some_if(requested_weight, |key, desc| { + if excluded_keys.contains(key) { + return false; + } + let status = self.eviction_cache_entry_recoverable_status(owner_node_id, key, desc); + counters.record_recoverable_first_status(status); + status == RecoverableReplicaStatus::Recoverable + }); + counters + .recoverable_first_selected_bytes + .fetch_add(selected_weight, Ordering::Relaxed); + counters.recoverable_first_shortfall_bytes.fetch_add( + requested_weight.saturating_sub(selected_weight), + Ordering::Relaxed, + ); + selected_weight } - pub fn reserve_inflight_put_key( + pub(crate) async fn demote_owner_hot_cohort_if_recoverable( &self, + owner_node_id: &str, key: &str, - reject_if_inflight_same_key: bool, - reject_if_exist_same_key: bool, - ) -> Result<(), KvError> { - if reject_if_exist_same_key && self.key_has_live_replica(key) { - return Err(KvError::Api( - crate::rpcresp_kvresult_convert::msg_and_error::ApiError::KeyAlreadyExists { - key: key.to_string(), - }, - )); + put_id: PutIDForAKey, + ) -> u64 { + let counters = self.eviction_reclaim_counters(owner_node_id); + counters + .owner_hot_demotion_attempts + .fetch_add(1, Ordering::Relaxed); + + let Some(cache) = self.get_node_cache_controller(owner_node_id) else { + return 0; + }; + cache.run_pending_tasks(); + let Some(anchor_desc) = cache.get(key) else { + return 0; + }; + if anchor_desc.put_id != put_id { + return 0; } - let counts = &self.inner().inflight_put_key_counts; - let mut entry = counts.entry(key.to_string()).or_insert(0); - if reject_if_inflight_same_key && *entry > 0 { - return Err(KvError::Api( - crate::rpcresp_kvresult_convert::msg_and_error::ApiError::KeyBeingWritten { - key: key.to_string(), - }, - )); + let Some(anchor_route) = self.inner().kv_routes.get(key).map(|route| route.clone()) else { + return 0; + }; + let Ok(cohort_keys) = current_tp_cohort_keys(key, &anchor_route, &anchor_desc) else { + return 0; + }; + let Some(cohort_anchor) = cohort_keys.iter().min() else { + return 0; + }; + let cohort_lock = self + .inner() + .owner_hot_demotion_locks + .get_lock(format!("{owner_node_id}\0{cohort_anchor}")); + let _cohort_guard = cohort_lock.lock().await; + + // The route and Moka state may have changed while another member completion held the + // cohort lock. Recompute the complete cohort under the lock before selecting anything. + cache.run_pending_tasks(); + let Some(anchor_desc) = cache.get(key) else { + return 0; + }; + if anchor_desc.put_id != put_id { + return 0; + } + let Some(anchor_route) = self.inner().kv_routes.get(key).map(|route| route.clone()) else { + return 0; + }; + let Ok(locked_cohort_keys) = current_tp_cohort_keys(key, &anchor_route, &anchor_desc) + else { + return 0; + }; + if locked_cohort_keys != cohort_keys { + counters + .owner_hot_demotion_precheck_rejected + .fetch_add(1, Ordering::Relaxed); + return 0; } - *entry += 1; - Ok(()) - } - pub fn key_has_live_replica(&self, key: &str) -> bool { - self.inner() - .kv_routes - .get(key) - .map(|one_kv_nodes_routes| { - one_kv_nodes_routes - .nodes_replicas - .read() - .values() - .any(|kv_info| !kv_info.tomb_tag.is_tomb()) + // Demotion is an all-or-nothing TP/atomic-cohort transition. Do not + // silently shrink the cohort when one of its source entries has + // already disappeared from this owner's cache: doing so can recreate + // the mixed local/remote layout that made the prefix unrecoverable in + // E23. + let expected_cohort_len = locked_cohort_keys.len(); + let expected_entries = locked_cohort_keys + .into_iter() + .map(|cohort_key| cache.get(&cohort_key).map(|desc| (cohort_key, desc))) + .collect::>>(); + let Some(expected_entries) = expected_entries else { + counters + .owner_hot_demotion_precheck_rejected + .fetch_add(1, Ordering::Relaxed); + return 0; + }; + if expected_entries.len() != expected_cohort_len || expected_entries.is_empty() { + counters + .owner_hot_demotion_precheck_rejected + .fetch_add(1, Ordering::Relaxed); + return 0; + } + + // Validate the whole TP/atomic cohort before asking Moka to select anything. Performing + // this check in the eviction predicate allowed one recoverable member to be selected even + // when a later member was not recoverable, which turned an intended exclusive transition + // into a partial source demotion. + let Some(expected_weight) = + recoverable_cohort_weight(&expected_entries, |candidate_key, candidate_desc| { + let status = self.eviction_cache_entry_recoverable_status( + owner_node_id, + candidate_key, + candidate_desc, + ); + counters.record_recoverable_first_status(status); + status }) - .unwrap_or(false) + else { + counters + .owner_hot_demotion_precheck_rejected + .fetch_add(1, Ordering::Relaxed); + return 0; + }; + + let selected_weight = + cache.evict_some_if(expected_weight, |candidate_key, candidate_desc| { + expected_entries + .get(candidate_key) + .is_some_and(|expected_desc| { + expected_desc.put_id == candidate_desc.put_id + && expected_desc.weight_bytes == candidate_desc.weight_bytes + }) + }); + if selected_weight != expected_weight { + counters + .owner_hot_demotion_partial_mismatch + .fetch_add(1, Ordering::Relaxed); + tracing::error!( + "owner hot TP-cohort demotion selected a partial cohort: owner={} key={} put_id=({},{}) cohort_entries={} expected_weight={} selected_weight={}", + owner_node_id, + key, + put_id.0, + put_id.1, + expected_entries.len(), + expected_weight, + selected_weight + ); + } + if selected_weight == expected_weight { + counters + .owner_hot_demotion_cohorts + .fetch_add(1, Ordering::Relaxed); + counters + .owner_hot_demotion_selected_bytes + .fetch_add(selected_weight, Ordering::Relaxed); + tracing::debug!( + "owner hot complete TP-cohort demotion selected: owner={} key={} put_id=({},{}) cohort_entries={} selected_weight={}", + owner_node_id, + key, + put_id.0, + put_id.1, + expected_entries.len(), + selected_weight + ); + } + selected_weight } - pub fn release_inflight_put_key(&self, key: &str) { - Self::release_inflight_put_key_count_map(&self.inner().inflight_put_key_counts, key); + pub(crate) fn insert_node_cache_entry( + &self, + owner_node_id: &str, + key: String, + desc: NodeValueReplicaDesc, + ) -> bool { + let Some(cache) = self.get_node_cache_controller(owner_node_id) else { + return false; + }; + cache.run_pending_tasks(); + let existing_weight = cache + .get(&key) + .map(|existing| u64::from(existing.weight_bytes)) + .unwrap_or(0); + let projected_weight = cache + .weighted_size() + .saturating_sub(existing_weight) + .saturating_add(u64::from(desc.weight_bytes)); + let node_space_size = self + .inner() + .view() + .master_seg_manager() + .get_node_space_size(owner_node_id); + let capacity = self.replica_cache_effective_capacity(owner_node_id, node_space_size); + let requested_weight = projected_weight.saturating_sub(capacity); + if requested_weight != 0 { + let recoverable_selected_weight = + self.evict_recoverable_cache_weight(owner_node_id, requested_weight); + let fallback_requested_weight = + requested_weight.saturating_sub(recoverable_selected_weight); + let fallback_selected_weight = + if self.owner_cache_allows_unrecoverable_eviction(owner_node_id) { + cache.evict_some(fallback_requested_weight) + } else { + 0 + }; + tracing::debug!( + "recoverable-first cache admission: owner={} key={} requested_weight={} recoverable_selected_weight={} fallback_requested_weight={} fallback_selected_weight={} projected_weight={} capacity={}", + owner_node_id, + key, + requested_weight, + recoverable_selected_weight, + fallback_requested_weight, + fallback_selected_weight, + projected_weight, + capacity + ); + } + cache.insert(key, desc); + true } fn register_rpc_callers(&self) { RPCCaller::::new().regist(self.0.view().p2p_module()); + RPCCaller::::new().regist(self.0.view().p2p_module()); + RPCCaller::::new().regist(self.0.view().p2p_module()); } fn register_rpc_handlers(&self) { @@ -827,9 +2766,11 @@ impl MasterKvRouter { let (get_id, mut ack) = handle_get_start(view_task, msg, resp.node_id().clone()).await; ack.serialize_part.server_process_us = Utc::now().timestamp_micros() - t0; + let get_started = ack.serialize_part.error_code + == crate::rpcresp_kvresult_convert::msg_and_error::OK; if let Err(e) = resp.send_resp(ack).await { error!("Failed to send GetStartResp: {:?}", e); - if get_id != 0 { + if get_started { if let Some(inflight_info) = cleanup_view .master_kv_router() .inner() @@ -838,6 +2779,7 @@ impl MasterKvRouter { .await { inflight_info.release_durable_slot_if_needed(); + inflight_info._activity_lease.release_now(); } } } @@ -947,14 +2889,9 @@ impl MasterKvRouter { if let Err(e) = resp.send_resp(ack).await { error!("Failed to send BatchPreparePutKeysResp: {:?}", e); for reservation_id in reservation_ids { - if let Some(info) = view_task + let _ = view_task .master_kv_router() - .take_prepared_put_key_reservation(reservation_id) - { - view_task - .master_kv_router() - .release_inflight_put_key(&info.key); - } + .take_prepared_put_key_reservation(reservation_id); } } }); @@ -1002,12 +2939,20 @@ impl MasterKvRouter { if let Err(e) = resp.send_resp(ack).await { error!("Failed to send PutStartResp: {:?}", e); if put_id != (0, 0) { - view_task + if let Some(inflight_info) = view_task .master_kv_router() .inner() .inflight_puts .remove(&(key, put_id.0, put_id.1)) - .await; + .await + { + inflight_info._activity_lease.release_now(); + if let Some(replica_target) = + inflight_info.commit_info.replica_target.as_ref() + { + replica_target._activity_lease.release_now(); + } + } } } else { #[cfg(feature = "test_bins")] @@ -1244,17 +3189,55 @@ impl MasterKvRouter { Ok(()) }); + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let view2 = view.clone(); + let req_node_id = resp.node_id().clone(); + view.spawn("rpc_grouped_batch_put_done", async move { + let t0 = Utc::now().timestamp_micros(); + let mut ack = handle_grouped_batch_put_done(view2, msg, req_node_id).await; + ack.serialize_part.server_process_us = Utc::now().timestamp_micros() - t0; + if let Err(e) = resp.send_resp(ack).await { + error!("Failed to send GroupedBatchPutDoneResp: {:?}", e); + } + }); + Ok(()) + }); + let view = self.0.view().clone(); RPCHandler::::new().regist(p2p, move |resp, msg| { let view = view.clone(); let view2 = view.clone(); + let cleanup_view = view.clone(); let req_node_id = resp.node_id().clone(); view.spawn("rpc_batch_get_start", async move { let t0 = Utc::now().timestamp_micros(); let mut ack = handle_batch_get_start(view2, msg, req_node_id).await; ack.serialize_part.server_process_us = Utc::now().timestamp_micros() - t0; + let started_get_ids = ack + .serialize_part + .items + .iter() + .filter(|item| { + item.error_code == crate::rpcresp_kvresult_convert::msg_and_error::OK + }) + .map(|item| item.get_id) + .collect::>(); if let Err(e) = resp.send_resp(ack).await { error!("Failed to send BatchGetStartResp: {:?}", e); + for get_id in started_get_ids { + if let Some(inflight_info) = cleanup_view + .master_kv_router() + .inner() + .inflight_gets + .remove(&get_id) + .await + { + inflight_info.release_durable_slot_if_needed(); + inflight_info._activity_lease.release_now(); + } + } } }); Ok(()) @@ -1774,6 +3757,47 @@ impl MasterKvRouter { target_counter.fetch_add(1, Ordering::Relaxed); } + pub(crate) fn record_get_source_selection( + &self, + requester_node_id: &str, + source_node_id: &str, + bytes: u64, + allocation_mode: GetAllocationMode, + ) { + let requester_source_key = RequesterTargetPair::new(requester_node_id, source_node_id); + let source_count = self + .inner() + .get_requester_source_counts + .entry(requester_source_key.clone()) + .or_insert_with(|| Arc::new(AtomicU64::new(0))) + .value() + .clone(); + source_count.fetch_add(1, Ordering::Relaxed); + + let source_bytes = self + .inner() + .get_requester_source_bytes + .entry(requester_source_key) + .or_insert_with(|| Arc::new(AtomicU64::new(0))) + .value() + .clone(); + source_bytes.fetch_add(bytes, Ordering::Relaxed); + + let mode_key = match allocation_mode { + GetAllocationMode::Temporary => "temporary", + GetAllocationMode::ReuseReplica => "reuse_replica", + GetAllocationMode::DurableReplica => "durable_replica", + }; + let mode_count = self + .inner() + .get_allocation_mode_counts + .entry(mode_key) + .or_insert_with(|| Arc::new(AtomicU64::new(0))) + .value() + .clone(); + mode_count.fetch_add(1, Ordering::Relaxed); + } + fn spawn_put_placement_reporter(&self) { let view = self.inner().view().clone(); let view_task = view.clone(); @@ -1819,12 +3843,39 @@ impl MasterKvRouter { .collect(); replica_task_target_counts.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(&b.0))); + let mut get_source_counts: Vec<(String, u64)> = router + .inner() + .get_requester_source_counts + .iter() + .map(|entry| (entry.key().as_log_key(), entry.value().load(Ordering::Relaxed))) + .collect(); + get_source_counts.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(&b.0))); + + let mut get_source_bytes: Vec<(String, u64)> = router + .inner() + .get_requester_source_bytes + .iter() + .map(|entry| (entry.key().as_log_key(), entry.value().load(Ordering::Relaxed))) + .collect(); + get_source_bytes.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(&b.0))); + + let mut get_allocation_mode_counts: Vec<(String, u64)> = router + .inner() + .get_allocation_mode_counts + .iter() + .map(|entry| (entry.key().to_string(), entry.value().load(Ordering::Relaxed))) + .collect(); + get_allocation_mode_counts.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(&b.0))); + info!( - "put placement historical distribution | target_counts={:?} | mode_counts={:?} | requester_target_counts={:?} | replica_task_target_counts={:?}", + "placement historical distribution | put_target_counts={:?} | put_mode_counts={:?} | put_requester_target_counts={:?} | replica_task_target_counts={:?} | get_requester_source_counts={:?} | get_requester_source_bytes={:?} | get_allocation_mode_counts={:?}", target_counts, mode_counts, requester_target_counts, replica_task_target_counts, + get_source_counts, + get_source_bytes, + get_allocation_mode_counts, ); } _ = shutdown_waiter.wait() => { @@ -1861,7 +3912,10 @@ impl MasterKvRouter { let cache_node_id = node_id_owned.clone(); Arc::new( moka::sync::SegmentedCache::builder(8) - .max_capacity((node_space_size as f32 * MOKA_CACHE_CAPACITY_RATIO) as u64) + // The resident cache is a metadata/LRU controller. Its aggregate + // effective capacity is enforced explicitly with `evict_some_if`. + // Leaving the Moka segments unbounded prevents per-segment hash skew + // from performing an independent Size eviction outside that policy. // Use the actual allocated/rounded size as weight to // make eviction reflect real memory usage. .weigher(Box::new(|_key: &String, value: &NodeValueReplicaDesc| { @@ -1884,19 +3938,11 @@ impl MasterKvRouter { evicted_put_id.0, evicted_put_id.1 ); - if let Err(code) = crate::master_kv_router::delete::evict_one_kv_replica_for_node( - &view, - k.clone(), - cache_node_id.clone().into(), - evicted_put_id, - ) { - warn!( - "Eviction-triggered local replica cleanup failed for key {} on node {}: {:?}", - k, - cache_node_id, - code - ); - } + view.master_kv_router().enqueue_eviction_reclaim( + cache_node_id.clone(), + k, + _value, + ); } _ => {} } @@ -1910,6 +3956,210 @@ impl MasterKvRouter { ) } + pub fn tier1_source_node_eligible(&self, node_id: &str) -> bool { + if !self.tiered_writeback_enabled() { + return false; + } + let member = self + .inner() + .view() + .cluster_manager() + .get_member_info_cached(node_id); + Self::tier1_source_member_eligible(member.as_ref(), &self.inner().replica_task_placement) + } + + fn tier1_source_member_eligible( + member: Option<&crate::cluster_manager::ClusterMember>, + placement_config: &ReplicaTaskPlacementConfig, + ) -> bool { + // Route entries are keyed by the storage owner that holds the payload. In the + // external-SGLang topology that owner is tagged `sglang_owner`; the separate + // zero-contribution SGLang client carries the `prefill`/`decode` role. Requiring + // the owner itself to match active_node_roles therefore disables T1 entirely. + // + // A T1 source only needs to be a known, non-remote-only owner. The caller also + // requires a non-zero registered segment before constructing the tier cache. + member.is_some() + && !placement::member_matches_roles(member, &placement_config.remote_only_node_roles) + } + + pub fn get_node_writeback_tier1_controller( + &self, + node_id: &str, + ) -> Option>> { + if !self.tier1_source_node_eligible(node_id) { + return None; + } + let node_space_size = self + .inner() + .view() + .master_seg_manager() + .get_node_space_size(node_id); + let base_capacity = self.writeback_tier1_base_capacity(node_space_size)?; + if base_capacity == 0 { + return None; + } + let view = self.inner().view().clone(); + let node_id_owned = node_id.to_string(); + Some( + self.inner() + .node_writeback_tier1_controller + .entry(node_id_owned.clone()) + .or_insert_with(move || { + let cache_node_id = node_id_owned.clone(); + Arc::new( + moka::sync::SegmentedCache::builder(8) + .max_capacity(base_capacity) + .weigher(Box::new(|_key: &String, value: &NodeValueReplicaDesc| { + value.weight_bytes + })) + .eviction_listener(Box::new( + move |key: Arc, + value: NodeValueReplicaDesc, + cause: RemovalCause| { + if cause == RemovalCause::Size { + view.master_kv_router().enqueue_tier1_writeback( + cache_node_id.clone(), + (*key).clone(), + value, + ); + } + }, + )) + .build(), + ) + }) + .value() + .clone(), + ) + } + + pub fn remove_node_writeback_tier1_entry(&self, node_id: &str, key: &str) { + if let Some(cache) = self + .inner() + .node_writeback_tier1_controller + .get(node_id) + .map(|entry| entry.value().clone()) + { + let _ = cache.remove(key); + } + } + + pub(crate) fn tier1_writeback_entry_is_current( + &self, + source_node_id: &str, + key: &str, + desc: &NodeValueReplicaDesc, + ) -> bool { + if self.inner().inflight_replica_tasks.contains_key(&( + key.to_string(), + desc.put_id.0, + desc.put_id.1, + )) { + return false; + } + self.inner().kv_routes.get(key).is_some_and(|route| { + if route.put_id != desc.put_id || route.lease_id.is_some() { + return false; + } + let replicas = route.nodes_replicas.read(); + replicas.values().any(|replica| { + replica.node_id.as_ref() == source_node_id && !replica.tomb_tag.is_tomb() + }) && replicas.values().all(|replica| { + replica.tomb_tag.is_tomb() || replica.node_id.as_ref() == source_node_id + }) + }) + } + + fn enqueue_tier1_writeback( + &self, + source_node_id: NodeIDString, + key: String, + desc: NodeValueReplicaDesc, + ) { + if !self.tier1_writeback_entry_is_current(&source_node_id, &key, &desc) { + return; + } + let dedupe_key = (key.clone(), desc.put_id.0, desc.put_id.1); + if self + .inner() + .tier1_writeback_dedupe + .get(&dedupe_key) + .is_some() + { + return; + } + self.inner() + .tier1_writeback_dedupe + .insert(dedupe_key.clone(), ()); + Self::increment_tier1_writeback_counter( + &self.inner().tier1_writeback_trigger_counts, + &source_node_id, + 1, + ); + let request = tiered_writeback::Tier1WritebackRequest { + source_node_id: source_node_id.clone(), + key, + desc, + }; + if let Err(err) = self.inner().tier1_writeback_tx.try_send(request) { + self.inner().tier1_writeback_dedupe.remove(&dedupe_key); + self.record_tier1_writeback_failed(&source_node_id, 1); + tracing::warn!("tier1 write-back queue is full or closed: {}", err); + } + } + + fn increment_tier1_writeback_counter( + counters: &DashMap>, + source_node_id: &str, + count: u64, + ) { + if count == 0 { + return; + } + counters + .entry(source_node_id.to_string()) + .or_insert_with(|| Arc::new(AtomicU64::new(0))) + .fetch_add(count, Ordering::Relaxed); + } + + pub(crate) fn record_tier1_writeback_owner_accepted(&self, source_node_id: &str, count: u64) { + Self::increment_tier1_writeback_counter( + &self.inner().tier1_writeback_owner_accepted_counts, + source_node_id, + count, + ); + } + + pub(crate) fn record_tier1_writeback_failed(&self, source_node_id: &str, count: u64) { + Self::increment_tier1_writeback_counter( + &self.inner().tier1_writeback_failed_counts, + source_node_id, + count, + ); + } + + fn tier1_writeback_counter( + counters: &DashMap>, + source_node_id: &str, + ) -> u64 { + counters + .get(source_node_id) + .map(|counter| counter.load(Ordering::Relaxed)) + .unwrap_or(0) + } + + pub(crate) fn finish_tier1_writeback_request( + &self, + request: tiered_writeback::Tier1WritebackRequest, + ) { + self.inner().tier1_writeback_dedupe.remove(&( + request.key, + request.desc.put_id.0, + request.desc.put_id.1, + )); + } + /// Atomically adjust a node's moka usable-capacity reservation by `delta_bytes`. /// Positive delta reserves capacity (fetch_sub from usable capacity), /// negative delta releases reservation (fetch_add back to usable capacity). @@ -1932,7 +4182,7 @@ impl MasterKvRouter { reserved_capacity.apply_delta(reason, delta_bytes); - // Recompute target capacity: base(=MOKA_CACHE_CAPACITY_RATIO * node_space) - reserved_total + // Recompute target capacity from the configured base ratio minus live reservations. let reserved_total = reserved_capacity.total_reserved_bytes(); let node_space_size = self .inner() @@ -1954,21 +4204,56 @@ impl MasterKvRouter { ), ); } - let base_capacity = (node_space_size as f32 * MOKA_CACHE_CAPACITY_RATIO) as u64; + let base_capacity = self.replica_cache_base_capacity(node_space_size); let new_capacity = base_capacity.saturating_sub(reserved_total); if let Some(cache) = self.get_node_cache_controller(node_id) { - if let Err(e) = cache.set_max_capacity(new_capacity) { - // Revert counter and return error. - reserved_capacity.apply_delta(reason, -delta_bytes); - return Err(crate::rpcresp_kvresult_convert::msg_and_error::KvError::Unreachable( - crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::RpcDecodeError { - rpc_input_json: format!( - "moka.set_max_capacity failed: node_id={}, new_capacity={}, err={}", - node_id, new_capacity, e + if let Some(tier1_cache) = self + .inner() + .node_writeback_tier1_controller + .get(node_id) + .map(|entry| entry.value().clone()) + { + let tier1_capacity = self + .writeback_tier1_base_capacity(node_space_size) + .unwrap_or(0) + .min(new_capacity); + if let Err(e) = tier1_cache.set_max_capacity(tier1_capacity) { + reserved_capacity.apply_delta(reason, -delta_bytes); + return Err( + crate::rpcresp_kvresult_convert::msg_and_error::KvError::Unreachable( + crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::RpcDecodeError { + rpc_input_json: format!( + "tier1 moka.set_max_capacity failed: node_id={}, new_capacity={}, err={}", + node_id, tier1_capacity, e + ), + }, ), - } - )); + ); + } + } + cache.run_pending_tasks(); + let requested_weight = cache.weighted_size().saturating_sub(new_capacity); + let recoverable_selected_weight = + self.evict_recoverable_cache_weight(node_id, requested_weight); + let fallback_requested_weight = + requested_weight.saturating_sub(recoverable_selected_weight); + let fallback_selected_weight = + if self.owner_cache_allows_unrecoverable_eviction(node_id) { + cache.evict_some(fallback_requested_weight) + } else { + 0 + }; + if requested_weight != 0 { + tracing::debug!( + "resident cache effective-capacity adjustment: owner={} effective_capacity={} requested_weight={} recoverable_selected_weight={} fallback_requested_weight={} fallback_selected_weight={}", + node_id, + new_capacity, + requested_weight, + recoverable_selected_weight, + fallback_requested_weight, + fallback_selected_weight + ); } Ok(()) } else { @@ -2060,21 +4345,117 @@ impl MasterKvRouter { .view() .master_seg_manager() .get_node_space_size(owner_node.as_str()); - let base_capacity_bytes = (node_space_size as f32 * MOKA_CACHE_CAPACITY_RATIO) as u64; + let base_capacity_bytes = self.replica_cache_base_capacity(node_space_size); let reserved_capacity_bytes = self .inner() .node_cache_reserved_capacity .get(owner_node.as_str()) .map(|reserved| reserved.total_reserved_bytes()) .unwrap_or(0); - let effective_capacity_bytes = cache.policy().max_capacity().unwrap_or(0); + let effective_capacity_bytes = + self.replica_cache_effective_capacity(owner_node.as_str(), node_space_size); + let pending_eviction_reclaim_bytes = + self.eviction_reclaim_pending_weight(owner_node.as_str()); + let reclaim_counters = self.eviction_reclaim_counters(owner_node.as_str()); + let tier1_cache = self + .inner() + .node_writeback_tier1_controller + .get(owner_node.as_str()) + .map(|entry| entry.value().clone()); replica_cache_nodes.push(ReplicaCacheNodeObserveSnapshot { - owner_node, + owner_node: owner_node.clone(), entries: cache.entry_count(), weighted_bytes: cache.weighted_size(), effective_capacity_bytes, reserved_capacity_bytes, base_capacity_bytes, + pending_eviction_reclaim_bytes, + writeback_tier1_entries: tier1_cache + .as_ref() + .map(|cache| cache.entry_count()) + .unwrap_or(0), + writeback_tier1_weighted_bytes: tier1_cache + .as_ref() + .map(|cache| cache.weighted_size()) + .unwrap_or(0), + writeback_tier1_capacity_bytes: tier1_cache + .as_ref() + .and_then(|cache| cache.policy().max_capacity()) + .unwrap_or(0), + writeback_tier1_triggered: Self::tier1_writeback_counter( + &self.inner().tier1_writeback_trigger_counts, + owner_node.as_str(), + ), + writeback_tier1_owner_accepted: Self::tier1_writeback_counter( + &self.inner().tier1_writeback_owner_accepted_counts, + owner_node.as_str(), + ), + writeback_tier1_failed: Self::tier1_writeback_counter( + &self.inner().tier1_writeback_failed_counts, + owner_node.as_str(), + ), + reclaim_master_activity_deferred: reclaim_counters + .master_activity_deferred + .load(Ordering::Relaxed), + reclaim_master_get_holder_observed: reclaim_counters + .master_get_holder_observed + .load(Ordering::Relaxed), + reclaim_owner_holder_deferred: reclaim_counters + .owner_holder_deferred + .load(Ordering::Relaxed), + reclaim_owner_other_deferred: reclaim_counters + .owner_other_deferred + .load(Ordering::Relaxed), + reclaim_route_changed: reclaim_counters.route_changed.load(Ordering::Relaxed), + reclaim_retry_queued: reclaim_counters.retry_queued.load(Ordering::Relaxed), + reclaim_retry_completed: reclaim_counters.retry_completed.load(Ordering::Relaxed), + reclaim_retry_restored: reclaim_counters.retry_restored.load(Ordering::Relaxed), + reclaim_completed: reclaim_counters.completed.load(Ordering::Relaxed), + owner_hot_demotion_attempts: reclaim_counters + .owner_hot_demotion_attempts + .load(Ordering::Relaxed), + owner_hot_demotion_cohorts: reclaim_counters + .owner_hot_demotion_cohorts + .load(Ordering::Relaxed), + owner_hot_demotion_selected_bytes: reclaim_counters + .owner_hot_demotion_selected_bytes + .load(Ordering::Relaxed), + owner_hot_demotion_precheck_rejected: reclaim_counters + .owner_hot_demotion_precheck_rejected + .load(Ordering::Relaxed), + owner_hot_demotion_partial_mismatch: reclaim_counters + .owner_hot_demotion_partial_mismatch + .load(Ordering::Relaxed), + recoverable_first_requested_bytes: reclaim_counters + .recoverable_first_requested_bytes + .load(Ordering::Relaxed), + recoverable_first_selected_bytes: reclaim_counters + .recoverable_first_selected_bytes + .load(Ordering::Relaxed), + recoverable_first_shortfall_bytes: reclaim_counters + .recoverable_first_shortfall_bytes + .load(Ordering::Relaxed), + recoverable_first_eligible_checks: reclaim_counters + .recoverable_first_eligible_checks + .load(Ordering::Relaxed), + recoverable_first_route_absent_checks: reclaim_counters + .recoverable_first_route_absent_checks + .load(Ordering::Relaxed), + recoverable_first_version_changed_checks: reclaim_counters + .recoverable_first_version_changed_checks + .load(Ordering::Relaxed), + recoverable_first_route_ineligible_checks: reclaim_counters + .recoverable_first_route_ineligible_checks + .load(Ordering::Relaxed), + recoverable_first_cpu_route_absent_checks: reclaim_counters + .recoverable_first_cpu_route_absent_checks + .load(Ordering::Relaxed), + recoverable_first_atomic_group_incomplete_checks: reclaim_counters + .recoverable_first_atomic_group_incomplete_checks + .load(Ordering::Relaxed), + recoverable_first_tp_cohort_incomplete_checks: reclaim_counters + .recoverable_first_tp_cohort_incomplete_checks + .load(Ordering::Relaxed), }); } @@ -2105,7 +4486,52 @@ impl MasterKvRouter { "master_get_holding", snapshot.get_holding_bytes, ); + tracing::info!( + "master get holding runtime: entries={} bytes={}", + snapshot.get_holding_entries, + snapshot.get_holding_bytes + ); for node in snapshot.replica_cache_nodes { + tracing::info!( + "replica cache runtime: owner={} entries={} weighted_bytes={} effective_capacity_bytes={} base_capacity_bytes={} reserved_capacity_bytes={} pending_eviction_reclaim_bytes={} writeback_tier1_entries={} writeback_tier1_weighted_bytes={} writeback_tier1_capacity_bytes={} writeback_tier1_triggered={} writeback_tier1_owner_accepted={} writeback_tier1_failed={} reclaim_master_activity_deferred={} reclaim_master_get_holder_observed={} reclaim_owner_holder_deferred={} reclaim_owner_other_deferred={} reclaim_route_changed={} reclaim_retry_queued={} reclaim_retry_completed={} reclaim_retry_restored={} reclaim_completed={} owner_hot_demotion_attempts={} owner_hot_demotion_cohorts={} owner_hot_demotion_selected_bytes={} owner_hot_demotion_precheck_rejected={} owner_hot_demotion_partial_mismatch={} recoverable_first_requested_bytes={} recoverable_first_selected_bytes={} recoverable_first_shortfall_bytes={} recoverable_first_eligible_checks={} recoverable_first_route_absent_checks={} recoverable_first_version_changed_checks={} recoverable_first_route_ineligible_checks={} recoverable_first_cpu_route_absent_checks={} recoverable_first_atomic_group_incomplete_checks={} recoverable_first_tp_cohort_incomplete_checks={}", + node.owner_node, + node.entries, + node.weighted_bytes, + node.effective_capacity_bytes, + node.base_capacity_bytes, + node.reserved_capacity_bytes, + node.pending_eviction_reclaim_bytes, + node.writeback_tier1_entries, + node.writeback_tier1_weighted_bytes, + node.writeback_tier1_capacity_bytes, + node.writeback_tier1_triggered, + node.writeback_tier1_owner_accepted, + node.writeback_tier1_failed, + node.reclaim_master_activity_deferred, + node.reclaim_master_get_holder_observed, + node.reclaim_owner_holder_deferred, + node.reclaim_owner_other_deferred, + node.reclaim_route_changed, + node.reclaim_retry_queued, + node.reclaim_retry_completed, + node.reclaim_retry_restored, + node.reclaim_completed, + node.owner_hot_demotion_attempts, + node.owner_hot_demotion_cohorts, + node.owner_hot_demotion_selected_bytes, + node.owner_hot_demotion_precheck_rejected, + node.owner_hot_demotion_partial_mismatch, + node.recoverable_first_requested_bytes, + node.recoverable_first_selected_bytes, + node.recoverable_first_shortfall_bytes, + node.recoverable_first_eligible_checks, + node.recoverable_first_route_absent_checks, + node.recoverable_first_version_changed_checks, + node.recoverable_first_route_ineligible_checks, + node.recoverable_first_cpu_route_absent_checks, + node.recoverable_first_atomic_group_incomplete_checks, + node.recoverable_first_tp_cohort_incomplete_checks + ); metrics.set_kv_replica_cache_entries( node.owner_node.as_str(), node.entries, @@ -2129,6 +4555,16 @@ impl MasterKvRouter { "base", node.base_capacity_bytes, ); + metrics.set_kv_replica_cache_capacity_bytes( + node.owner_node.as_str(), + "pending_eviction_reclaim", + node.pending_eviction_reclaim_bytes, + ); + metrics.set_kv_replica_cache_capacity_bytes( + node.owner_node.as_str(), + "writeback_tier1", + node.writeback_tier1_capacity_bytes, + ); } } } diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs index 2185436..9f7717b 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs @@ -5,6 +5,7 @@ use crate::{ }; use bitcode::{Decode, Encode}; use std::collections::HashMap; +use std::sync::Arc; use super::put::PutIDForAKey; @@ -264,20 +265,42 @@ impl RPCReq for GetMasterOnlyMetricPartReq { } #[derive(Default, Debug, Clone, Encode, Decode)] -pub struct ReserveLocalGrantReq; +pub struct ReserveLocalGrantReq { + /// Slot class that needs capacity. Zero means a raw grant request with no reclaim fallback. + pub slot_size: u64, + /// Number of slots the owner is currently short of in this class. + pub required_free_slots: u32, + /// Reclaim committed slots before growing the physical grant pool. This keeps owner-local + /// free-slot headroom without changing the owner's advertised capacity. + pub reclaim_before_grow: bool, +} impl MsgPackSerializePart for ReserveLocalGrantReq { fn msg_id(&self) -> u32 { MsgId::ReserveLocalGrantReq as u32 } } +#[allow(unused_assignments)] +#[derive(Default, Debug, Clone, Encode, Decode)] +pub enum ReserveLocalGrantOutcome { + #[default] + None, + Granted { + grant_id: u64, + node_id: NodeIDString, + addr: u64, + base_addr: u64, + len: u64, + }, + Reclaimed { + slot_size: u64, + reclaimed_slots: u32, + }, +} + #[derive(Default, Debug, Clone, Encode, Decode)] pub struct ReserveLocalGrantResp { - pub grant_id: u64, - pub node_id: NodeIDString, - pub addr: u64, - pub base_addr: u64, - pub len: u64, + pub outcome: ReserveLocalGrantOutcome, pub error_code: ErrorCode, pub error_json: String, pub server_process_us: i64, @@ -291,6 +314,134 @@ impl RPCReq for ReserveLocalGrantReq { type Resp = ReserveLocalGrantResp; } +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)] +pub enum OwnerReclaimPhase { + #[default] + Prepare, + Commit, + Abort, + Finalize, +} + +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)] +pub enum OwnerReclaimItemState { + #[default] + Busy, + Prepared, + Committed, + Aborted, + Finalized, + Stale, +} + +#[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)] +pub enum OwnerReclaimBacking { + #[default] + Allocation, + CommittedSlot { + grant_id: u64, + slot_index: u32, + slot_size: u64, + }, + /// A master-owned allocation with no owner-side key index. The master reclaims this + /// backing directly after installing its key-activity fence and never sends it to the owner. + UnindexedAllocation, +} + +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)] +pub enum OwnerReclaimReason { + #[default] + Reserve, + CapacityEviction, +} + +#[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)] +pub struct OwnerReclaimItem { + pub key: String, + pub put_id: (u64, u32), + pub epoch: u64, + pub backing: OwnerReclaimBacking, + pub reason: OwnerReclaimReason, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchOwnerReclaimReq { + pub phase: OwnerReclaimPhase, + pub items: Vec, +} + +impl MsgPackSerializePart for BatchOwnerReclaimReq { + fn msg_id(&self) -> u32 { + MsgId::BatchOwnerReclaimReq as u32 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct OwnerReclaimItemResp { + pub key: String, + pub epoch: u64, + pub state: OwnerReclaimItemState, + pub detail: String, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchOwnerReclaimResp { + pub items: Vec, + pub error_code: ErrorCode, + pub error_json: String, +} + +impl MsgPackSerializePart for BatchOwnerReclaimResp { + fn msg_id(&self) -> u32 { + MsgId::BatchOwnerReclaimResp as u32 + } +} + +impl RPCReq for BatchOwnerReclaimReq { + type Resp = BatchOwnerReclaimResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct EnqueueReplicaTaskItem { + pub key: String, + pub put_id: PutIDForAKey, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchEnqueueReplicaTaskReq { + pub items: Vec, +} + +impl MsgPackSerializePart for BatchEnqueueReplicaTaskReq { + fn msg_id(&self) -> u32 { + MsgId::BatchEnqueueReplicaTaskReq as u32 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct EnqueueReplicaTaskItemResp { + pub key: String, + pub put_id: PutIDForAKey, + pub accepted: bool, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchEnqueueReplicaTaskResp { + pub items: Vec, + pub error_code: ErrorCode, + pub error_json: String, +} + +impl MsgPackSerializePart for BatchEnqueueReplicaTaskResp { + fn msg_id(&self) -> u32 { + MsgId::BatchEnqueueReplicaTaskResp as u32 + } +} + +impl RPCReq for BatchEnqueueReplicaTaskReq { + type Resp = BatchEnqueueReplicaTaskResp; +} + #[derive(Default, Debug, Clone, Encode, Decode)] pub struct ReleaseLocalGrantReq { pub grant_id: u64, @@ -461,6 +612,95 @@ pub struct PutDoneCommittedSlot { pub len: u64, } +#[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)] +pub struct PutAtomicGroupMember { + pub key: String, + pub put_id: PutIDForAKey, +} + +/// Version-scoped members of one caller-declared atomic put group. +/// +/// Groups with one member are represented as `None` on the route. Multi-member +/// groups let eviction require one common remote-cache owner to hold every member. +#[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)] +pub struct PutAtomicGroup { + pub members: Vec, +} + +pub fn build_put_atomic_group_assignments( + keys_and_put_ids: &[(String, PutIDForAKey)], + atomic_group_lens: &[usize], +) -> Result>, String> { + build_shared_put_atomic_group_assignments(keys_and_put_ids, atomic_group_lens).map( + |assignments| { + assignments + .into_iter() + .map(|group| group.map(|group| group.as_ref().clone())) + .collect() + }, + ) +} + +/// Builds one shared descriptor per multi-key group and assigns cheap `Arc` +/// clones to its members. This is the grouped-put representation used by the +/// V2 route-publish protocol; unlike the legacy wire representation, it is +/// linear in the number of keys rather than the sum of squared group sizes. +pub fn build_shared_put_atomic_group_assignments( + keys_and_put_ids: &[(String, PutIDForAKey)], + atomic_group_lens: &[usize], +) -> Result>>, String> { + if atomic_group_lens.is_empty() && !keys_and_put_ids.is_empty() { + return Err("atomic_group_lens must be non-empty".to_string()); + } + let mut offset = 0usize; + let mut assignments = Vec::with_capacity(keys_and_put_ids.len()); + for (group_index, group_len) in atomic_group_lens.iter().copied().enumerate() { + if group_len == 0 { + return Err(format!( + "atomic_group_lens entries must be > 0; index={group_index}" + )); + } + if group_len > 4096 { + return Err(format!( + "atomic_group_lens entries must be <= 4096; index={group_index} len={group_len}" + )); + } + let end = offset + .checked_add(group_len) + .ok_or_else(|| "atomic_group_lens sum overflowed usize".to_string())?; + let members = keys_and_put_ids.get(offset..end).ok_or_else(|| { + format!( + "atomic_group_lens exceeds keys length; end={} keys={}", + end, + keys_and_put_ids.len() + ) + })?; + if group_len == 1 { + assignments.push(None); + } else { + let group = Arc::new(PutAtomicGroup { + members: members + .iter() + .map(|(key, put_id)| PutAtomicGroupMember { + key: key.clone(), + put_id: *put_id, + }) + .collect(), + }); + assignments.extend((0..group_len).map(|_| Some(group.clone()))); + } + offset = end; + } + if offset != keys_and_put_ids.len() { + return Err(format!( + "atomic_group_lens must sum to keys length; sum={} keys={}", + offset, + keys_and_put_ids.len() + )); + } + Ok(assignments) +} + #[derive(Default, Debug, Clone, Encode, Decode)] pub struct PutDoneReq { pub key: String, @@ -471,6 +711,8 @@ pub struct PutDoneReq { pub committed_slot: Option, /// Ask master to keep a local read holder for the committing node. pub publish_local_cache: bool, + /// Multi-key atomic group for this exact key version. + pub atomic_group: Option, } impl MsgPackSerializePart for PutDoneReq { fn msg_id(&self) -> u32 { @@ -591,6 +833,7 @@ pub struct BatchPutDoneItemReq { pub lease_id: Option, pub committed_slot: Option, pub publish_local_cache: bool, + pub atomic_group: Option, } #[derive(Default, Debug, Clone, Encode, Decode)] @@ -628,12 +871,56 @@ impl RPCReq for BatchPutDoneReq { type Resp = BatchPutDoneResp; } +/// Linear-size V2 batch route publication. `atomic_group_lens` partitions the +/// ordered items; the master reconstructs each group once from the item keys +/// and put ids, then shares one interned descriptor across member routes. +/// +/// The V1 `BatchPutDoneReq` remains registered unchanged for rolling and API +/// compatibility. +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct GroupedBatchPutDoneItemReq { + pub key: String, + pub put_id: PutIDForAKey, + pub lease_id: Option, + pub committed_slot: Option, + pub publish_local_cache: bool, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct GroupedBatchPutDoneReq { + pub items: Vec, + pub atomic_group_lens: Vec, +} +impl MsgPackSerializePart for GroupedBatchPutDoneReq { + fn msg_id(&self) -> u32 { + MsgId::GroupedBatchPutDoneReq as u32 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct GroupedBatchPutDoneResp { + pub items: Vec, + pub error_code: ErrorCode, + pub error_json: String, + pub server_process_us: i64, +} +impl MsgPackSerializePart for GroupedBatchPutDoneResp { + fn msg_id(&self) -> u32 { + MsgId::GroupedBatchPutDoneResp as u32 + } +} +impl RPCReq for GroupedBatchPutDoneReq { + type Resp = GroupedBatchPutDoneResp; +} + #[derive(Default, Debug, Clone, Encode, Decode)] pub struct PutAppendStartReq { pub key: String, pub put_id: PutIDForAKey, pub len: u64, pub preferred_sub_cluster: Option, + pub demote_source_on_remote_complete: bool, + pub protect_source_on_remote_complete: bool, } impl MsgPackSerializePart for PutAppendStartReq { fn msg_id(&self) -> u32 { @@ -936,3 +1223,112 @@ impl MsgPackSerializePart for BatchDeleteClientKvMetaCacheResp { impl RPCReq for BatchDeleteClientKvMetaCacheReq { type Resp = BatchDeleteClientKvMetaCacheResp; } + +#[cfg(test)] +mod put_atomic_group_tests { + use super::*; + + #[test] + fn assignments_expand_only_multi_member_groups() { + let keys_and_put_ids = vec![ + ("a".to_string(), (1, 0)), + ("b".to_string(), (1, 1)), + ("c".to_string(), (1, 2)), + ]; + let assignments = build_put_atomic_group_assignments(&keys_and_put_ids, &[2, 1]).unwrap(); + assert_eq!(assignments.len(), 3); + assert_eq!(assignments[0], assignments[1]); + assert_eq!(assignments[0].as_ref().unwrap().members.len(), 2); + assert!(assignments[2].is_none()); + } + + #[test] + fn assignments_reject_invalid_partitions() { + let keys_and_put_ids = vec![("a".to_string(), (1, 0)), ("b".to_string(), (1, 1))]; + assert!(build_put_atomic_group_assignments(&keys_and_put_ids, &[1]).is_err()); + assert!(build_put_atomic_group_assignments(&keys_and_put_ids, &[0, 2]).is_err()); + } + + #[test] + fn batch_put_done_group_round_trips_on_wire() { + let group = PutAtomicGroup { + members: vec![ + PutAtomicGroupMember { + key: "a".to_string(), + put_id: (1, 0), + }, + PutAtomicGroupMember { + key: "b".to_string(), + put_id: (1, 1), + }, + ], + }; + let req = BatchPutDoneReq { + items: vec![BatchPutDoneItemReq { + key: "a".to_string(), + put_id: (1, 0), + lease_id: None, + committed_slot: None, + publish_local_cache: false, + atomic_group: Some(group.clone()), + }], + }; + let decoded: BatchPutDoneReq = + bitcode::decode(&bitcode::encode(&req)).expect("decode atomic put group"); + assert_eq!(decoded.items[0].atomic_group.as_ref(), Some(&group)); + } + + #[test] + fn grouped_batch_put_done_wire_is_linear_and_round_trips() { + let keys_and_put_ids = (0..128) + .map(|index| (format!("page-{index:03}"), (7, index))) + .collect::>(); + let group = PutAtomicGroup { + members: keys_and_put_ids + .iter() + .map(|(key, put_id)| PutAtomicGroupMember { + key: key.clone(), + put_id: *put_id, + }) + .collect(), + }; + let legacy = BatchPutDoneReq { + items: keys_and_put_ids + .iter() + .map(|(key, put_id)| BatchPutDoneItemReq { + key: key.clone(), + put_id: *put_id, + lease_id: None, + committed_slot: None, + publish_local_cache: false, + atomic_group: Some(group.clone()), + }) + .collect(), + }; + let grouped = GroupedBatchPutDoneReq { + items: keys_and_put_ids + .iter() + .map(|(key, put_id)| GroupedBatchPutDoneItemReq { + key: key.clone(), + put_id: *put_id, + lease_id: None, + committed_slot: None, + publish_local_cache: false, + }) + .collect(), + atomic_group_lens: vec![128], + }; + let legacy_bytes = bitcode::encode(&legacy); + let grouped_bytes = bitcode::encode(&grouped); + assert!( + grouped_bytes.len() * 16 < legacy_bytes.len(), + "grouped={} legacy={}", + grouped_bytes.len(), + legacy_bytes.len() + ); + let decoded: GroupedBatchPutDoneReq = + bitcode::decode(&grouped_bytes).expect("decode grouped put done"); + assert_eq!(decoded.items.len(), 128); + assert_eq!(decoded.atomic_group_lens, vec![128]); + } +} diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/placement.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/placement.rs index 69c5db0..1880278 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/placement.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/placement.rs @@ -391,7 +391,7 @@ fn no_space_error(last_no_space_ctx: Option) -> KvError { } } -fn member_matches_roles(member: Option<&ClusterMember>, roles: &[String]) -> bool { +pub(super) fn member_matches_roles(member: Option<&ClusterMember>, roles: &[String]) -> bool { let Some(member) = member else { return false; }; diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs index 6849105..ccdf281 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs @@ -1,20 +1,21 @@ -use super::NodeValueReplicaDesc; use super::{ CommittedSlotReplica, InflightPutAllocation, InflightPutCommitInfo, InflightPutInfo, InflightReplicaTaskInfo, KvReplicaBacking, KvRouteInfo, LocalReserveGrantInfo, - MasterKvRouterView, OwnerHoldingGetInfo, PreparedPutKeyReservationInfo, PutPlacementMode, - ReservedCapacityReason, + MasterKeyActivityCompletionGuard, MasterKvRouterView, OwnerHoldingGetInfo, + PreparedPutKeyReservationInfo, PutPlacementMode, ReservedCapacityReason, msg_pack::{ BatchPreparePutKeysReq, BatchPreparePutKeysResp, BatchPutDoneItemResp, BatchPutDoneReq, BatchPutDoneResp, BatchPutRevokeItemResp, BatchPutRevokeReq, BatchPutRevokeResp, BatchPutStartItemResp, BatchPutStartReq, BatchPutStartResp, - BatchReleasePutKeyReservationsReq, BatchReleasePutKeyReservationsResp, PutAppendDoneReq, - PutAppendDoneResp, PutAppendRevokeReq, PutAppendRevokeResp, PutAppendStartReq, - PutAppendStartResp, PutDoneReq, PutDoneResp, PutRevokeReq, PutRevokeResp, PutStartReq, - PutStartResp, ReleaseLocalGrantReq, ReleaseLocalGrantResp, ReserveLocalGrantReq, - ReserveLocalGrantResp, + BatchReleasePutKeyReservationsReq, BatchReleasePutKeyReservationsResp, + GroupedBatchPutDoneReq, GroupedBatchPutDoneResp, PutAppendDoneReq, PutAppendDoneResp, + PutAppendRevokeReq, PutAppendRevokeResp, PutAppendStartReq, PutAppendStartResp, + PutAtomicGroup, PutDoneReq, PutDoneResp, PutRevokeReq, PutRevokeResp, PutStartReq, + PutStartResp, ReleaseLocalGrantReq, ReleaseLocalGrantResp, ReserveLocalGrantOutcome, + ReserveLocalGrantReq, ReserveLocalGrantResp, build_shared_put_atomic_group_assignments, }, placement::PutPlacementTarget, + route_maintenance::{RoutePublishEvent, enqueue_post_route_maintenance}, }; use crate::master_kv_router::OneKvNodesRoutes; use crate::master_kv_router::delete::DeleteKeyInfo; @@ -41,36 +42,6 @@ use std::{ pub type PutIDForAKey = (u64, u32); -struct InflightPutKeyReservation { - view: MasterKvRouterView, - key: String, - active: bool, -} - -impl InflightPutKeyReservation { - fn new(view: MasterKvRouterView, key: String) -> Self { - Self { - view, - key, - active: true, - } - } - - fn disarm(&mut self) { - self.active = false; - } -} - -impl Drop for InflightPutKeyReservation { - fn drop(&mut self) { - if self.active { - self.view - .master_kv_router() - .release_inflight_put_key(&self.key); - } - } -} - fn validate_put_start_source_node_override( view: &MasterKvRouterView, requester_node_id: &NodeID, @@ -192,7 +163,7 @@ fn append_current_route_replica_if_matching( put_id: PutIDForAKey, node_id: NodeID, allocation: Allocation, -) -> bool { +) -> Option { let Some(one_kv_nodes_routes) = view.master_kv_router().inner().kv_routes.get(key) else { tracing::debug!( "append_current_route_replica_if_matching skipped because route disappeared: key={} put_id=({},{})", @@ -200,7 +171,7 @@ fn append_current_route_replica_if_matching( put_id.0, put_id.1 ); - return false; + return None; }; if one_kv_nodes_routes.put_id != put_id { tracing::debug!( @@ -211,7 +182,7 @@ fn append_current_route_replica_if_matching( put_id.0, put_id.1 ); - return false; + return None; } let Some(tomb_tag) = view.master_seg_manager().get_node_tomb_tag(&node_id) else { tracing::warn!( @@ -221,7 +192,7 @@ fn append_current_route_replica_if_matching( put_id.1, node_id ); - return false; + return None; }; if tomb_tag.is_tomb() { tracing::warn!( @@ -231,42 +202,26 @@ fn append_current_route_replica_if_matching( put_id.1, node_id ); - return false; + return None; } - let alloc_cap = allocation.capcity(); - let req_weight = if alloc_cap > u32::MAX as u64 { - tracing::warn!( - "moka weight saturation on put append: key={} put_id=({},{}) cap={}B exceeds u32::MAX; weight set to u32::MAX", - key, - put_id.0, - put_id.1, - alloc_cap - ); - u32::MAX - } else { - alloc_cap as u32 - }; + let capacity_bytes = allocation.capcity(); let lease_id = one_kv_nodes_routes.lease_id; one_kv_nodes_routes.nodes_replicas.write().insert( node_id.clone(), KvRouteInfo { node_id: node_id.clone(), backing: KvReplicaBacking::Allocation(Arc::new(allocation)), + owner_local_indexed: false, tomb_tag, }, ); - if lease_id.is_none() { - if let Some(cache) = view.master_kv_router().get_node_cache_controller(&node_id) { - cache.insert( - key.to_string(), - NodeValueReplicaDesc { - weight_bytes: req_weight, - put_id, - }, - ); - } - } - true + Some(RoutePublishEvent::replica_append( + key.to_string(), + put_id, + lease_id, + node_id, + capacity_bytes, + )) } fn allocate_from_node_local_segment( @@ -331,6 +286,8 @@ fn reserve_replica_task( preferred_sub_cluster, len, &HashSet::new(), + false, + true, ) } @@ -342,7 +299,10 @@ fn reserve_replica_task_excluding( preferred_sub_cluster: Option<&str>, len: u64, excluded_nodes: &HashSet, + demote_source_on_remote_complete: bool, + protect_source_on_remote_complete: bool, ) -> msg_and_error::KvResult { + let activity_lease = view.master_kv_router().reserve_inflight_replica_key(key)?; let (target_node_id, target_allocation) = view .master_kv_router() .inner() @@ -366,9 +326,13 @@ fn reserve_replica_task_excluding( ); Ok(InflightReplicaTaskInfo { node_id: target_node_id, + source_node_id: source_node_id.clone(), key: key.to_string(), put_id, target_allocation: Arc::new(Mutex::new(Some(target_allocation))), + demote_source_on_remote_complete, + protect_source_on_remote_complete, + _activity_lease: activity_lease, }) } @@ -377,24 +341,12 @@ async fn publish_completed_put_route( key: String, put_id: PutIDForAKey, lease_id_opt: Option, + atomic_group: Option>, node_id: NodeID, completed_info: KvRouteInfo, target_cap_bytes: u64, local_cache_holder_id: Option, ) -> MsgPack { - let saturated_weight_u32 = if target_cap_bytes > u32::MAX as u64 { - tracing::warn!( - "moka weight saturation: key={} put_id=({},{}) cap={}B exceeds u32::MAX; weight set to u32::MAX", - key, - put_id.0, - put_id.1, - target_cap_bytes - ); - u32::MAX - } else { - target_cap_bytes as u32 - }; - let mut old_one_kv_routes: Option> = None; let mut inserted = false; { @@ -408,6 +360,7 @@ async fn publish_completed_put_route( Arc::new(OneKvNodesRoutes { put_id, lease_id: lease_id_opt, + atomic_group: atomic_group.clone(), nodes_replicas: RwLock::new(HashMap::new()), get_durable_slots_used: AtomicU32::new(0), }) @@ -417,6 +370,7 @@ async fn publish_completed_put_route( *one_kv_routes = Arc::new(OneKvNodesRoutes { put_id, lease_id: lease_id_opt, + atomic_group: atomic_group.clone(), nodes_replicas: RwLock::new(HashMap::new()), get_durable_slots_used: AtomicU32::new(0), }); @@ -443,48 +397,19 @@ async fn publish_completed_put_route( } } - { - let view_task = view.clone(); - let key_for_spawn = key.clone(); - let node_for_spawn = node_id.clone(); - let do_prefix_index_update = view.master_kv_router().prefix_index_enabled(); - let do_cache_insert = - lease_id_opt.is_none() && view.master_kv_router().replica_cache_enabled(); - let cap_bytes_u32 = saturated_weight_u32; - view.spawn("post_put_done_maintenance", async move { - if do_prefix_index_update { - let inner = view_task.master_kv_router().inner(); - let mut tree = inner.prefix_index.write().await; - tree.insert(&key_for_spawn); - } - - if do_cache_insert { - let cache = view_task - .master_kv_router() - .get_node_cache_controller(&node_for_spawn); - if let Some(cache) = cache { - let desc = NodeValueReplicaDesc { - weight_bytes: cap_bytes_u32, - put_id, - }; - tracing::debug!("Inserting key: {:?} into cache", key_for_spawn); - cache.insert(key_for_spawn.clone(), desc); - tracing::debug!( - "Inserted key: {:?} into cache, current cache size: {}", - key_for_spawn, - cache.weighted_size() - ); - } else { - tracing::warn!( - "No cache controller found for node: {}, node is not ready", - node_for_spawn - ); - } - } - }); - } + enqueue_post_route_maintenance( + &view, + RoutePublishEvent::primary_put( + key.clone(), + put_id, + lease_id_opt, + node_id.clone(), + target_cap_bytes, + ), + ) + .await; - tracing::info!( + tracing::debug!( "Completed put operation with put_id: {:?}, key: {:?}", put_id, key @@ -507,21 +432,23 @@ pub async fn handle_put_start( req_node_id: NodeID, ) -> (PutIDForAKey, MsgPack) { let key = req.serialize_part.key.clone(); - if let Err(err) = view.master_kv_router().reserve_inflight_put_key( + let activity_lease = match view.master_kv_router().reserve_inflight_put_key( &key, req.serialize_part.reject_if_inflight_same_key, req.serialize_part.reject_if_exist_same_key, ) { - let resp: PutStartResp = crate::rpcresp_kvresult_convert::FromError::from_error(&err); - return ( - (0, 0), - MsgPack { - serialize_part: resp, - raw_bytes: Vec::new(), - }, - ); - } - let mut key_reservation = InflightPutKeyReservation::new(view.clone(), key.clone()); + Ok(activity_lease) => activity_lease, + Err(err) => { + let resp: PutStartResp = crate::rpcresp_kvresult_convert::FromError::from_error(&err); + return ( + (0, 0), + MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + }, + ); + } + }; let source_node_id = match req.serialize_part.source_node_id.as_ref() { Some(source_node_id) => { let source_node_id: NodeID = source_node_id.clone().into(); @@ -588,6 +515,7 @@ pub async fn handle_put_start( src_target_allocation: Arc::new(Mutex::new(Some(inflight_alloc))), replica_target: replica_target.clone(), }, + _activity_lease: activity_lease.clone(), }; let view_task = view.clone(); @@ -637,9 +565,22 @@ pub async fn handle_put_start( } }; - let put_target = Ok(PutPlacementTarget::Local { - node_id: source_node_id.clone(), - }); + let put_target = if req.serialize_part.make_replica_task { + Ok(PutPlacementTarget::Local { + node_id: source_node_id.clone(), + }) + } else { + view.master_kv_router() + .inner() + .policy + .select_put_target( + &view, + &source_node_id, + req.serialize_part.preferred_sub_cluster.as_deref(), + req.serialize_part.len, + ) + .await + }; match put_target { Ok(PutPlacementTarget::Local { node_id }) => { @@ -738,9 +679,7 @@ pub async fn handle_put_start( allocation_size, replica_target, ); - let result = fut.await; - key_reservation.disarm(); - return result; + return fut.await; } Ok(PutPlacementTarget::Remote { node_id, @@ -793,9 +732,7 @@ pub async fn handle_put_start( allocation_size, None, ); - let result = fut.await; - key_reservation.disarm(); - return result; + return fut.await; } Err(err) => { let resp: PutStartResp = crate::rpcresp_kvresult_convert::FromError::from_error(&err); @@ -815,9 +752,42 @@ pub async fn handle_reserve_local_grant( req: MsgPack, req_node_id: NodeID, ) -> (u64, MsgPack) { - let _ = req; - - let mut allocation = match allocate_from_node_local_segment( + if req.serialize_part.reclaim_before_grow + && req.serialize_part.slot_size != 0 + && req.serialize_part.required_free_slots != 0 + { + let reclaimed = crate::master_kv_router::reclaim::reclaim_owner_slots_for_reserve( + &view, + &req_node_id, + req.serialize_part.slot_size, + req.serialize_part.required_free_slots, + ) + .await; + tracing::info!( + "owner reserve proactive headroom reclaim: owner={} slot_size={} requested_slots={} reclaimed={}", + req_node_id, + req.serialize_part.slot_size, + req.serialize_part.required_free_slots, + reclaimed + ); + if reclaimed != 0 { + return ( + 0, + MsgPack { + serialize_part: ReserveLocalGrantResp { + outcome: ReserveLocalGrantOutcome::Reclaimed { + slot_size: req.serialize_part.slot_size, + reclaimed_slots: reclaimed, + }, + error_code: msg_and_error::OK, + ..Default::default() + }, + raw_bytes: Vec::new(), + }, + ); + } + } + let allocation = match allocate_from_node_local_segment( &view, &req_node_id, OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES, @@ -825,6 +795,85 @@ pub async fn handle_reserve_local_grant( ) { Ok(allocation) => allocation, Err(err) => { + let physical_no_space = matches!( + &err, + msg_and_error::KvError::Api(msg_and_error::ApiError::NoSpace { .. }) + ); + if physical_no_space + && req.serialize_part.slot_size != 0 + && req.serialize_part.required_free_slots != 0 + { + let requested_eviction_weight = req + .serialize_part + .slot_size + .saturating_mul(u64::from(req.serialize_part.required_free_slots)); + let pending_eviction_weight = view + .master_kv_router() + .eviction_reclaim_pending_weight(req_node_id.as_ref()); + let additional_eviction_weight = + requested_eviction_weight.saturating_sub(pending_eviction_weight); + if additional_eviction_weight != 0 { + if let Some(cache) = view + .master_kv_router() + .get_node_cache_controller(req_node_id.as_ref()) + { + let weighted_size_before = cache.weighted_size(); + let recoverable_evicted_weight = + view.master_kv_router().evict_recoverable_cache_weight( + req_node_id.as_ref(), + additional_eviction_weight, + ); + let fallback_requested_weight = + additional_eviction_weight.saturating_sub(recoverable_evicted_weight); + let fallback_evicted_weight = if view + .master_kv_router() + .owner_cache_allows_unrecoverable_reserve_pressure_eviction( + req_node_id.as_ref(), + ) { + cache.evict_some(fallback_requested_weight) + } else { + 0 + }; + tracing::info!( + "owner reserve requested moka eviction: owner={} slot_size={} requested_slots={} requested_weight={} pending_weight_before={} recoverable_evicted_weight={} fallback_requested_weight={} fallback_evicted_weight={} shortfall_weight={} weighted_size_before={} weighted_size_after={}", + req_node_id, + req.serialize_part.slot_size, + req.serialize_part.required_free_slots, + requested_eviction_weight, + pending_eviction_weight, + recoverable_evicted_weight, + fallback_requested_weight, + fallback_evicted_weight, + fallback_requested_weight.saturating_sub(fallback_evicted_weight), + weighted_size_before, + cache.weighted_size() + ); + } + } + let reclaimed = crate::master_kv_router::reclaim::reclaim_owner_slots_for_reserve( + &view, + &req_node_id, + req.serialize_part.slot_size, + req.serialize_part.required_free_slots, + ) + .await; + if reclaimed != 0 { + return ( + 0, + MsgPack { + serialize_part: ReserveLocalGrantResp { + outcome: ReserveLocalGrantOutcome::Reclaimed { + slot_size: req.serialize_part.slot_size, + reclaimed_slots: reclaimed, + }, + error_code: msg_and_error::OK, + ..Default::default() + }, + raw_bytes: Vec::new(), + }, + ); + } + } let resp: ReserveLocalGrantResp = crate::rpcresp_kvresult_convert::FromError::from_error(&err); return ( @@ -837,43 +886,6 @@ pub async fn handle_reserve_local_grant( } }; - let reserved_bytes = allocation.capcity(); - if let Err(err) = view.master_kv_router().adjust_node_cache_reserved_capacity( - req_node_id.as_ref(), - ReservedCapacityReason::LocalReserveGrant, - reserved_bytes as i64, - ) { - let resp: ReserveLocalGrantResp = - crate::rpcresp_kvresult_convert::FromError::from_error(&err); - return ( - 0, - MsgPack { - serialize_part: resp, - raw_bytes: Vec::new(), - }, - ); - } - - let view_clone = view.clone(); - let node_id_string = req_node_id.as_ref().to_string(); - allocation.set_on_drop(move || { - if let Err(e) = view_clone - .master_kv_router() - .adjust_node_cache_reserved_capacity( - &node_id_string, - ReservedCapacityReason::LocalReserveGrant, - -(reserved_bytes as i64), - ) - { - tracing::warn!( - "Failed to restore moka capacity on local reserve grant drop: node_id={}, bytes={}, err={}", - node_id_string, - reserved_bytes, - e - ); - } - }); - let grant_id = view.master_kv_router().next_local_reserve_grant_id(); let grant_base_addr = allocation.base_addr(); let grant_abs_addr = grant_base_addr + allocation.addr(); @@ -890,11 +902,13 @@ pub async fn handle_reserve_local_grant( grant_id, MsgPack { serialize_part: ReserveLocalGrantResp { - grant_id, - node_id: req_node_id.into_owned(), - addr: grant_abs_addr, - base_addr: grant_base_addr, - len: grant_len, + outcome: ReserveLocalGrantOutcome::Granted { + grant_id, + node_id: req_node_id.into_owned(), + addr: grant_abs_addr, + base_addr: grant_base_addr, + len: grant_len, + }, error_code: msg_and_error::OK, error_json: String::new(), server_process_us: 0, @@ -952,29 +966,29 @@ pub async fn handle_batch_prepare_put_keys( ) -> (Vec, MsgPack) { let mut reservation_ids = Vec::with_capacity(req.serialize_part.items.len()); for item in req.serialize_part.items { - if let Err(err) = view.master_kv_router().reserve_inflight_put_key( + let activity_lease = match view.master_kv_router().reserve_inflight_put_key( &item.key, item.reject_if_inflight_same_key, item.reject_if_exist_same_key, ) { - for reservation_id in reservation_ids.drain(..) { - if let Some(info) = view - .master_kv_router() - .take_prepared_put_key_reservation(reservation_id) - { - view.master_kv_router().release_inflight_put_key(&info.key); + Ok(activity_lease) => activity_lease, + Err(err) => { + for reservation_id in reservation_ids.drain(..) { + let _ = view + .master_kv_router() + .take_prepared_put_key_reservation(reservation_id); } + let resp: BatchPreparePutKeysResp = + crate::rpcresp_kvresult_convert::FromError::from_error(&err); + return ( + Vec::new(), + MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + }, + ); } - let resp: BatchPreparePutKeysResp = - crate::rpcresp_kvresult_convert::FromError::from_error(&err); - return ( - Vec::new(), - MsgPack { - serialize_part: resp, - raw_bytes: Vec::new(), - }, - ); - } + }; let reservation_id = view .master_kv_router() .next_prepared_put_key_reservation_id(); @@ -984,6 +998,7 @@ pub async fn handle_batch_prepare_put_keys( PreparedPutKeyReservationInfo { owner_node_id: req_node_id.clone(), key: item.key, + _activity_lease: activity_lease, }, ); reservation_ids.push(reservation_id); @@ -1043,9 +1058,7 @@ pub async fn handle_batch_release_put_key_reservations( taken.push((reservation_id, info)); } - for (_reservation_id, info) in taken { - view.master_kv_router().release_inflight_put_key(&info.key); - } + drop(taken); MsgPack { serialize_part: BatchReleasePutKeyReservationsResp::default(), @@ -1070,8 +1083,13 @@ pub async fn handle_put_revoke( .remove(&kvrouter_key) .await { - view.master_kv_router() - .release_inflight_put_key(&inflight_info.key); + let _activity_completion = + MasterKeyActivityCompletionGuard::new(inflight_info._activity_lease.clone()); + let _replica_activity_completion = inflight_info + .commit_info + .replica_target + .as_ref() + .map(|target| MasterKeyActivityCompletionGuard::new(target._activity_lease.clone())); tracing::info!("Revoked put operation with put_id: {:?}", kvrouter_key); } else { tracing::warn!( @@ -1090,6 +1108,15 @@ pub async fn handle_put_done( view: MasterKvRouterView, req: MsgPack, req_node_id: NodeID, +) -> MsgPack { + handle_put_done_with_resolved_group(view, req, req_node_id, None).await +} + +async fn handle_put_done_with_resolved_group( + view: MasterKvRouterView, + req: MsgPack, + req_node_id: NodeID, + resolved_atomic_group: Option>, ) -> MsgPack { tracing::debug!("Handling PutDoneReq: {:?}", req.serialize_part); @@ -1097,10 +1124,30 @@ pub async fn handle_put_done( let lease_id_opt = req.serialize_part.lease_id; let full_put_id: (String, u64, u32) = (req.serialize_part.key.clone(), put_id.0, put_id.1); let local_cache_holder_id: Option; + let atomic_group = if let Some(group) = resolved_atomic_group { + Some(group) + } else { + match view.master_kv_router().resolve_put_atomic_group( + &req.serialize_part.key, + put_id, + req.serialize_part.atomic_group.clone(), + ) { + Ok(group) => group, + Err(err) => { + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), + raw_bytes: Vec::new(), + }; + } + } + }; // Remove from inflight_puts and store in completed_puts if let Some(InflightPutInfo { - key, commit_info, .. + key, + commit_info, + _activity_lease, + .. }) = view .master_kv_router() .inner() @@ -1108,7 +1155,11 @@ pub async fn handle_put_done( .remove(&full_put_id) .await { - view.master_kv_router().release_inflight_put_key(&key); + let _activity_completion = MasterKeyActivityCompletionGuard::new(_activity_lease); + let mut replica_activity_completion = commit_info + .replica_target + .as_ref() + .map(|target| MasterKeyActivityCompletionGuard::new(target._activity_lease.clone())); let node_id = commit_info.node_id; let Some(allocs) = commit_info.src_target_allocation.lock().take() else { tracing::warn!( @@ -1159,7 +1210,7 @@ pub async fn handle_put_done( let (target_cap_bytes, completed_info, local_cache_publish_supported) = match allocs { InflightPutAllocation::Local(mut target_allocation) => { if let Some(slot) = route_committed_slot { - let target_cap_bytes = slot.len; + let target_cap_bytes = slot.slot_size; if let Some(lease_id) = lease_id_opt { if let Err(e) = view .master_lease_manager() @@ -1202,6 +1253,7 @@ pub async fn handle_put_done( len: slot.len, base_addr: slot.base_addr, }), + owner_local_indexed: true, tomb_tag, }, false, @@ -1238,6 +1290,14 @@ pub async fn handle_put_done( let view_clone = view.clone(); let node_id_string = node_id.as_ref().to_string(); target_allocation.set_on_drop(move || { + // The allocation can be released while FrameworkInner itself is + // being dropped. At that point the weak module view can no longer + // be upgraded and restoring the runtime Moka reservation is both + // impossible and unnecessary. Keep an upgrade guard alive for the + // whole callback so dependency access cannot race the final drop. + let Some(_view_guard) = view_clone.try_upgrade() else { + return; + }; if let Err(e) = view_clone .master_kv_router() .adjust_node_cache_reserved_capacity( @@ -1260,6 +1320,7 @@ pub async fn handle_put_done( KvRouteInfo { node_id: node_id.clone(), backing: KvReplicaBacking::Allocation(Arc::new(target_allocation)), + owner_local_indexed: req.serialize_part.publish_local_cache, tomb_tag, }, true, @@ -1303,6 +1364,11 @@ pub async fn handle_put_done( let view_clone = view.clone(); let node_id_string = node_id.as_ref().to_string(); target.set_on_drop(move || { + // See the equivalent local-placement callback above. A final framework + // teardown must not call back into the module currently being destroyed. + let Some(_view_guard) = view_clone.try_upgrade() else { + return; + }; if let Err(e) = view_clone .master_kv_router() .adjust_node_cache_reserved_capacity( @@ -1325,13 +1391,14 @@ pub async fn handle_put_done( KvRouteInfo { node_id: node_id.clone(), backing: KvReplicaBacking::Allocation(Arc::new(target)), + owner_local_indexed: false, tomb_tag, }, false, ) } InflightPutAllocation::LocalCommittedSlot(slot) => { - let target_cap_bytes = slot.len; + let target_cap_bytes = slot.slot_size; if let Some(lease_id) = lease_id_opt { if let Err(e) = view .master_lease_manager() @@ -1367,6 +1434,7 @@ pub async fn handle_put_done( KvRouteInfo { node_id: node_id.clone(), backing: KvReplicaBacking::CommittedSlot(slot), + owner_local_indexed: true, tomb_tag, }, false, @@ -1374,19 +1442,6 @@ pub async fn handle_put_done( } }; - // NOTE on weight sizing for moka cache: - // - moka's `weigher` returns a u32 per-entry weight while the cache's - // `max_capacity` and `weighted_size()` use u64. If an allocation's - // capacity exceeds u32::MAX (e.g., >= 4 GiB), a naive `as u32` cast - // would truncate and could become 0 for ~exact 4 GiB multiples. - // That would effectively disable size-based eviction because such - // entries would contribute 0 to the cache weight and the cache would - // never reach its configured capacity. This directly causes the - // observed "non‑lease mode eviction not working; puts fill to full". - // - To make eviction robust, we saturate the per-entry weight at - // u32::MAX when `capcity()` is larger than u32::MAX. This keeps the - // cache accounting conservative (evicts earlier rather than later) - // and prevents weight=0 due to truncation. local_cache_holder_id = if req.serialize_part.publish_local_cache { if !local_cache_publish_supported { let err = msg_and_error::KvError::Api( @@ -1435,20 +1490,6 @@ pub async fn handle_put_done( None }; - let saturated_weight_u32 = if target_cap_bytes > u32::MAX as u64 { - tracing::warn!( - "moka weight saturation: key={} put_id=({},{}) cap={}B exceeds u32::MAX; weight set to u32::MAX", - key, - put_id.0, - put_id.1, - target_cap_bytes - ); - u32::MAX - } else { - target_cap_bytes as u32 - }; - // Note: moka cache insertion happens after commit in a spawned task - // using the same saturated weight; avoid unused local here. // Insert into kv_routes with replica support let mut old_one_kv_routes: Option> = None; let mut inserted = false; @@ -1463,6 +1504,7 @@ pub async fn handle_put_done( Arc::new(OneKvNodesRoutes { put_id, lease_id: lease_id_opt, + atomic_group: atomic_group.clone(), nodes_replicas: RwLock::new(HashMap::new()), get_durable_slots_used: AtomicU32::new(0), }) @@ -1473,6 +1515,7 @@ pub async fn handle_put_done( *one_kv_routes = Arc::new(OneKvNodesRoutes { put_id, lease_id: lease_id_opt, + atomic_group: atomic_group.clone(), nodes_replicas: RwLock::new(HashMap::new()), get_durable_slots_used: AtomicU32::new(0), }); @@ -1496,6 +1539,10 @@ pub async fn handle_put_done( replica_target, ) .await; + replica_activity_completion + .as_mut() + .expect("replica target activity guard must exist") + .disarm(); } if let Some(old) = old_one_kv_routes { @@ -1514,58 +1561,21 @@ pub async fn handle_put_done( } } - // Post-commit maintenance: update prefix-count index (for CountPrefix RPC) - // and, if applicable, update per-node cache controller. Run both in a - // spawned task to keep the PutDone RPC path lean and consistent with - // other async cache control operations. Deletion path already removes - // the index entry in delete.rs (do_delete_one_kv_all_replicas). - { - let view_task = view.clone(); - let key_for_spawn = key.clone(); - let node_for_spawn = node_id.clone(); - let do_prefix_index_update = view.master_kv_router().prefix_index_enabled(); - let do_cache_insert = - lease_id_opt.is_none() && view.master_kv_router().replica_cache_enabled(); - // Reuse the saturated weight computed above for moka insertion - let cap_bytes_u32 = saturated_weight_u32; - view.spawn("post_put_done_maintenance", async move { - // 1) Update prefix-counting index - if do_prefix_index_update { - let inner = view_task.master_kv_router().inner(); - let mut tree = inner.prefix_index.write().await; - tree.insert(&key_for_spawn); - } - - // 2) Optionally update node cache controller (non-leased keys) - if do_cache_insert { - let cache = view_task - .master_kv_router() - .get_node_cache_controller(&node_for_spawn); - if let Some(cache) = cache { - let desc = NodeValueReplicaDesc { - weight_bytes: cap_bytes_u32, - put_id, - }; - tracing::debug!("Inserting key: {:?} into cache", key_for_spawn); - cache.insert(key_for_spawn.clone(), desc); - tracing::debug!( - "Inserted key: {:?} into cache, current cache size: {}", - key_for_spawn, - cache.weighted_size() - ); - } else { - tracing::warn!( - "No cache controller found for node: {}, node is not ready", - node_for_spawn - ); - } - } - }); - } + enqueue_post_route_maintenance( + &view, + RoutePublishEvent::primary_put( + key.clone(), + put_id, + lease_id_opt, + node_id.clone(), + target_cap_bytes, + ), + ) + .await; // Lease attach is handled before kv_routes insertion - tracing::info!( + tracing::debug!( "Completed put operation with put_id: {:?}, key: {:?}", put_id, key @@ -1573,6 +1583,20 @@ pub async fn handle_put_done( } else { if let Some(slot) = req.serialize_part.committed_slot.clone() { let key = req.serialize_part.key.clone(); + let _activity_lease = match view + .master_kv_router() + .reserve_inflight_put_key(&key, false, false) + { + Ok(activity_lease) => activity_lease, + Err(err) => { + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error( + &err, + ), + raw_bytes: Vec::new(), + }; + } + }; let node_id = req_node_id; let Some(tomb_tag) = view.master_seg_manager().get_node_tomb_tag(&node_id) else { let err = msg_and_error::KvError::Api( @@ -1615,7 +1639,7 @@ pub async fn handle_put_done( raw_bytes: Vec::new(), }; } - let target_cap_bytes = slot.len; + let target_cap_bytes = slot.slot_size; if let Some(lease_id) = lease_id_opt { if let Err(e) = view .master_lease_manager() @@ -1655,6 +1679,7 @@ pub async fn handle_put_done( len: slot.len, base_addr: slot.base_addr, }), + owner_local_indexed: true, tomb_tag, }; return publish_completed_put_route( @@ -1662,6 +1687,7 @@ pub async fn handle_put_done( key, put_id, lease_id_opt, + atomic_group, node_id, completed_info, target_cap_bytes, @@ -1795,6 +1821,7 @@ pub async fn handle_batch_put_done( lease_id, committed_slot: item.committed_slot, publish_local_cache: item.publish_local_cache, + atomic_group: item.atomic_group, }, raw_bytes: Vec::new(), }, @@ -1821,6 +1848,115 @@ pub async fn handle_batch_put_done( } } +/// V2 route publication for local-first puts. The wire carries each key once +/// plus a compact ordered partition. The master materializes one shared group +/// descriptor per partition and passes cheap `Arc` clones to member routes, +/// avoiding both repeated wire descriptors and repeated group validation. +pub async fn handle_grouped_batch_put_done( + view: MasterKvRouterView, + req: MsgPack, + req_node_id: NodeID, +) -> MsgPack { + let GroupedBatchPutDoneReq { + items: request_items, + atomic_group_lens, + } = req.serialize_part; + let keys_and_put_ids = request_items + .iter() + .map(|item| (item.key.clone(), item.put_id)) + .collect::>(); + let assignments = + match build_shared_put_atomic_group_assignments(&keys_and_put_ids, &atomic_group_lens) { + Ok(assignments) => assignments, + Err(detail) => { + let err = msg_and_error::ApiError::InvalidArgument { detail }; + let (error_code, error_json) = err.to_code_and_json(); + return MsgPack { + serialize_part: GroupedBatchPutDoneResp { + items: Vec::new(), + error_code, + error_json, + server_process_us: 0, + }, + raw_bytes: Vec::new(), + }; + } + }; + + // The partition builder derives membership from these exact ordered items. + // Reject duplicate/empty keys once per group so every member is represented + // exactly once before any route becomes visible. + let mut offset = 0usize; + for group_len in atomic_group_lens.iter().copied() { + if group_len > 1 { + let mut unique = HashSet::with_capacity(group_len); + let end = offset + group_len; + if keys_and_put_ids[offset..end] + .iter() + .any(|(key, _)| key.is_empty() || !unique.insert(key.as_str())) + { + let err = msg_and_error::ApiError::InvalidArgument { + detail: format!( + "grouped put member keys must be non-empty and unique: offset={} len={}", + offset, group_len + ), + }; + let (error_code, error_json) = err.to_code_and_json(); + return MsgPack { + serialize_part: GroupedBatchPutDoneResp { + items: Vec::new(), + error_code, + error_json, + server_process_us: 0, + }, + raw_bytes: Vec::new(), + }; + } + } + offset += group_len; + } + + let mut items = Vec::with_capacity(request_items.len()); + for (item, atomic_group) in request_items.into_iter().zip(assignments) { + let key = item.key.clone(); + let put_id = item.put_id; + let resp = handle_put_done_with_resolved_group( + view.clone(), + MsgPack { + serialize_part: PutDoneReq { + key, + put_id, + lease_id: item.lease_id, + committed_slot: item.committed_slot, + publish_local_cache: item.publish_local_cache, + atomic_group: None, + }, + raw_bytes: Vec::new(), + }, + req_node_id.clone(), + atomic_group, + ) + .await; + let part = resp.serialize_part; + items.push(BatchPutDoneItemResp { + key: item.key, + put_id: item.put_id, + error_code: part.error_code, + error_json: part.error_json, + local_cache_holder_id: part.local_cache_holder_id, + }); + } + MsgPack { + serialize_part: GroupedBatchPutDoneResp { + items, + error_code: msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + }, + raw_bytes: Vec::new(), + } +} + pub async fn handle_put_append_start( view: MasterKvRouterView, req: MsgPack, @@ -1839,12 +1975,20 @@ pub async fn handle_put_append_start( .map(|route| current_route_needs_remote_replica(route, &req_node_id, put_id)) .unwrap_or(false); if !current_route_still_needs_remote { - let _ = view + if let Some(inflight) = view .master_kv_router() .inner() .inflight_replica_tasks .remove(&(key.clone(), put_id.0, put_id.1)) - .await; + .await + { + inflight._activity_lease.release_now(); + } + if req.serialize_part.demote_source_on_remote_complete { + view.master_kv_router() + .demote_owner_hot_cohort_if_recoverable(req_node_id.as_ref(), &key, put_id) + .await; + } return MsgPack { serialize_part: PutAppendStartResp { scheduled: false, @@ -1887,6 +2031,8 @@ pub async fn handle_put_append_start( req.serialize_part.preferred_sub_cluster.as_deref(), req.serialize_part.len, &excluded_nodes, + req.serialize_part.demote_source_on_remote_complete, + req.serialize_part.protect_source_on_remote_complete, ) { Ok(reservation) => reservation, Err(msg_and_error::KvError::Api(msg_and_error::ApiError::NoSpace { @@ -1978,12 +2124,15 @@ pub async fn handle_put_append_revoke( ) -> MsgPack { let put_id = req.serialize_part.put_id; let key = req.serialize_part.key; - let _ = view + if let Some(inflight) = view .master_kv_router() .inner() .inflight_replica_tasks .remove(&(key, put_id.0, put_id.1)) - .await; + .await + { + inflight._activity_lease.release_now(); + } MsgPack { serialize_part: PutAppendRevokeResp { error_code: msg_and_error::OK, @@ -2017,6 +2166,8 @@ pub async fn handle_put_append_done( raw_bytes: Vec::new(), }; }; + let _activity_completion = + MasterKeyActivityCompletionGuard::new(inflight._activity_lease.clone()); let Some(allocation) = inflight.target_allocation.lock().take() else { let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { detail: format!( @@ -2029,13 +2180,22 @@ pub async fn handle_put_append_done( raw_bytes: Vec::new(), }; }; - let appended = append_current_route_replica_if_matching( + let published = append_current_route_replica_if_matching( &view, &key, inflight.put_id, inflight.node_id, allocation, ); + let appended = published.is_some(); + if let Some(event) = published { + enqueue_post_route_maintenance(&view, event).await; + } + if inflight.demote_source_on_remote_complete { + view.master_kv_router() + .demote_owner_hot_cohort_if_recoverable(inflight.source_node_id.as_ref(), &key, put_id) + .await; + } MsgPack { serialize_part: PutAppendDoneResp { appended, diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs new file mode 100644 index 0000000..8a4223c --- /dev/null +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs @@ -0,0 +1,1291 @@ +use super::{KvReplicaBacking, MasterKvRouterView, NodeValueReplicaDesc}; +use crate::cluster_manager::{NodeID, NodeIDString}; +use crate::master_kv_router::msg_pack::{ + BatchOwnerReclaimReq, OwnerReclaimBacking, OwnerReclaimItem, OwnerReclaimItemResp, + OwnerReclaimItemState, OwnerReclaimPhase, OwnerReclaimReason, +}; +use crate::memholder::MemholderManagerTrait; +use crate::p2p::msg_pack::{MIN_EXPLICIT_RPC_TIMEOUT_SECS, MsgPack, RPCCaller}; +use crate::rpcresp_kvresult_convert::msg_and_error::OK; +use limit_thirdparty::tokio; +use std::collections::HashMap; +use std::collections::HashSet; +use std::future::Future; +use std::sync::atomic::Ordering; +use std::time::{Duration, Instant}; + +const OWNER_RECLAIM_RPC_TIMEOUT: Duration = Duration::from_secs(MIN_EXPLICIT_RPC_TIMEOUT_SECS); +const OWNER_RECLAIM_MAX_BATCH: usize = 256; +const OWNER_RECLAIM_MERGE_WINDOW: Duration = Duration::from_millis(5); +const EVICTION_RECLAIM_RETRY_INITIAL: Duration = Duration::from_millis(100); +const EVICTION_RECLAIM_RETRY_MAX: Duration = Duration::from_secs(1); +const EVICTION_RECLAIM_MAX_RETRY_COUNT: u32 = 5; + +fn should_restore_after_retry(retry_count: u32) -> bool { + retry_count >= EVICTION_RECLAIM_MAX_RETRY_COUNT +} + +fn eviction_reclaim_retry_delay(retry_count: u32) -> Duration { + let multiplier = 1u32 << retry_count.saturating_sub(1).min(16); + EVICTION_RECLAIM_RETRY_INITIAL + .saturating_mul(multiplier) + .min(EVICTION_RECLAIM_RETRY_MAX) +} + +#[cfg(test)] +mod timeout_contract_tests { + use super::*; + use crate::p2p::msg_pack::validate_explicit_rpc_timeout; + + #[test] + fn owner_reclaim_timeout_satisfies_rpc_contract() { + validate_explicit_rpc_timeout(Some(OWNER_RECLAIM_RPC_TIMEOUT)).unwrap(); + } + + #[test] + fn eviction_reclaim_retry_restoration_is_bounded() { + assert!(!should_restore_after_retry( + EVICTION_RECLAIM_MAX_RETRY_COUNT - 1 + )); + assert!(should_restore_after_retry(EVICTION_RECLAIM_MAX_RETRY_COUNT)); + assert!(should_restore_after_retry(u32::MAX)); + } + + #[test] + fn eviction_reclaim_retry_paces_restore_view_holders() { + assert_eq!(eviction_reclaim_retry_delay(1), Duration::from_millis(100)); + assert_eq!(eviction_reclaim_retry_delay(2), Duration::from_millis(200)); + assert_eq!(eviction_reclaim_retry_delay(3), Duration::from_millis(400)); + assert_eq!(eviction_reclaim_retry_delay(4), Duration::from_millis(800)); + assert_eq!( + eviction_reclaim_retry_delay(u32::MAX), + Duration::from_secs(1) + ); + } +} + +#[derive(Clone, Debug)] +pub(crate) struct EvictionReclaimRequest { + pub owner_node_id: NodeIDString, + pub key: String, + pub desc: NodeValueReplicaDesc, + pub retry_count: u32, +} + +fn route_item( + view: &MasterKvRouterView, + owner_node_id: &NodeID, + key: &str, + expected_put_id: Option<(u64, u32)>, + required_slot_size: Option, + reason: OwnerReclaimReason, + epoch: u64, +) -> Option { + let route = view.master_kv_router().inner().kv_routes.get(key)?.clone(); + if expected_put_id.is_some_and(|put_id| put_id != route.put_id) || route.lease_id.is_some() { + return None; + } + let replicas = route.nodes_replicas.read(); + let target = replicas.get(owner_node_id)?; + if target.tomb_tag.is_tomb() { + return None; + } + let backing = match &target.backing { + KvReplicaBacking::Allocation(_) if required_slot_size.is_none() => { + if target.owner_local_indexed { + OwnerReclaimBacking::Allocation + } else { + OwnerReclaimBacking::UnindexedAllocation + } + } + KvReplicaBacking::Allocation(_) => return None, + KvReplicaBacking::CommittedSlot(slot) + if slot.owner_node_id == *owner_node_id + && required_slot_size.map_or(true, |slot_size| slot.slot_size == slot_size) => + { + OwnerReclaimBacking::CommittedSlot { + grant_id: slot.grant_id, + slot_index: slot.slot_index, + slot_size: slot.slot_size, + } + } + KvReplicaBacking::CommittedSlot(_) => return None, + }; + let has_other_live_replica = replicas + .iter() + .any(|(node_id, replica)| node_id != owner_node_id && !replica.tomb_tag.is_tomb()); + drop(replicas); + if reason == OwnerReclaimReason::Reserve { + let normally_recoverable = has_other_live_replica + && (view + .master_kv_router() + .owner_cache_allows_unrecoverable_eviction(owner_node_id.as_ref()) + || { + let desc = NodeValueReplicaDesc { + weight_bytes: 0, + put_id: route.put_id, + }; + view.master_kv_router() + .eviction_cache_entry_recoverable_status(owner_node_id.as_ref(), key, &desc) + == super::RecoverableReplicaStatus::Recoverable + }); + if !normally_recoverable + && !view + .master_kv_router() + .owner_cache_allows_unrecoverable_reserve_pressure_eviction(owner_node_id.as_ref()) + { + return None; + } + } + Some(OwnerReclaimItem { + key: key.to_string(), + put_id: route.put_id, + epoch, + backing, + reason, + }) +} + +fn master_has_holder(view: &MasterKvRouterView, key: &str) -> bool { + view.master_kv_router() + .inner() + .get_holding + .inner() + .iter() + .any(|entry| entry.value().key == key) +} + +fn item_still_valid(view: &MasterKvRouterView, owner: &NodeID, item: &OwnerReclaimItem) -> bool { + if !view + .master_kv_router() + .inner() + .key_activity + .reclaim_matches(item) + { + return false; + } + route_item( + view, + owner, + &item.key, + Some(item.put_id), + match &item.backing { + OwnerReclaimBacking::Allocation | OwnerReclaimBacking::UnindexedAllocation => None, + OwnerReclaimBacking::CommittedSlot { slot_size, .. } => Some(*slot_size), + }, + item.reason, + item.epoch, + ) + .is_some_and(|current| current.backing == item.backing && current.reason == item.reason) +} + +async fn call_owner_phase( + view: &MasterKvRouterView, + owner: &NodeID, + phase: OwnerReclaimPhase, + items: Vec, +) -> Result, String> { + if items.is_empty() { + return Ok(Vec::new()); + } + debug_assert!( + items + .iter() + .all(|item| item.backing != OwnerReclaimBacking::UnindexedAllocation) + ); + let caller = RPCCaller::::new(); + caller.regist(view.p2p_module()); + let resp = caller + .call( + view.p2p_module(), + owner.clone(), + MsgPack { + serialize_part: BatchOwnerReclaimReq { + phase, + items: items.clone(), + }, + raw_bytes: Vec::new(), + }, + Some(OWNER_RECLAIM_RPC_TIMEOUT), + 1, + ) + .await + .map_err(|err| format!("{err:?}"))?; + if resp.serialize_part.error_code != OK { + return Err(format!( + "code={} error={}", + resp.serialize_part.error_code, resp.serialize_part.error_json + )); + } + if resp.serialize_part.items.len() != items.len() { + return Err(format!( + "owner reclaim response length mismatch: phase={phase:?} expected={} got={}", + items.len(), + resp.serialize_part.items.len() + )); + } + for (request, response) in items.iter().zip(resp.serialize_part.items.iter()) { + if request.key != response.key || request.epoch != response.epoch { + return Err(format!( + "owner reclaim response identity mismatch: phase={phase:?} request=({}, {}) response=({}, {})", + request.key, request.epoch, response.key, response.epoch + )); + } + } + Ok(resp.serialize_part.items) +} + +fn clear_master_fence(view: &MasterKvRouterView, item: &OwnerReclaimItem) { + let cleared = view + .master_kv_router() + .inner() + .key_activity + .clear_reclaim(item); + if !cleared { + tracing::warn!( + "owner reclaim master fence did not match during cleanup: key={} epoch={}", + item.key, + item.epoch + ); + } +} + +async fn abort_prepared( + view: &MasterKvRouterView, + owner: &NodeID, + items: Vec, +) -> Vec { + if items.is_empty() { + return Vec::new(); + } + match call_owner_phase(view, owner, OwnerReclaimPhase::Abort, items.clone()).await { + Ok(responses) => { + let mut already_committed = Vec::new(); + for (item, response) in items.into_iter().zip(responses.into_iter()) { + match response.state { + OwnerReclaimItemState::Committed => already_committed.push(item), + OwnerReclaimItemState::Aborted + | OwnerReclaimItemState::Stale + | OwnerReclaimItemState::Finalized => clear_master_fence(view, &item), + state => tracing::warn!( + "owner reclaim abort returned unresolved state: key={} epoch={} state={:?} detail={}", + item.key, + item.epoch, + state, + response.detail + ), + } + } + already_committed + } + Err(err) => { + tracing::warn!( + "owner reclaim abort RPC failed; retaining master fences: owner={} keys={} err={}", + owner, + items.len(), + err + ); + spawn_abort_retry(view.clone(), owner.clone(), items); + Vec::new() + } + } +} + +fn spawn_abort_retry(view: MasterKvRouterView, owner: NodeID, items: Vec) { + if items.is_empty() { + return; + } + let spawn_view = view.clone(); + let _ = spawn_view.spawn("owner_reclaim_abort_retry", async move { + let mut pending = items; + let mut committed = Vec::new(); + let mut delay = Duration::from_millis(25); + for _attempt in 1..=8 { + tokio::time::sleep(delay).await; + match call_owner_phase(&view, &owner, OwnerReclaimPhase::Abort, pending.clone()).await { + Ok(responses) => { + let mut next = Vec::new(); + for (item, response) in pending.into_iter().zip(responses.into_iter()) { + match response.state { + OwnerReclaimItemState::Committed => committed.push(item), + OwnerReclaimItemState::Aborted + | OwnerReclaimItemState::Stale + | OwnerReclaimItemState::Finalized => clear_master_fence(&view, &item), + _ => next.push(item), + } + } + pending = next; + if pending.is_empty() { + break; + } + } + Err(err) => tracing::warn!( + "owner reclaim abort retry failed: owner={} keys={} err={}", + owner, + pending.len(), + err + ), + } + delay = (delay * 2).min(Duration::from_secs(1)); + } + if !committed.is_empty() { + let _ = finish_committed(&view, &owner, committed).await; + } + if !pending.is_empty() { + tracing::error!( + "owner reclaim abort retry exhausted; fences retained: owner={} keys={}", + owner, + pending.len() + ); + } + }); +} + +fn reclaim_backing_matches(replica: &super::KvRouteInfo, expected: &OwnerReclaimBacking) -> bool { + match (&replica.backing, expected) { + (KvReplicaBacking::Allocation(_), OwnerReclaimBacking::Allocation) => { + replica.owner_local_indexed + } + (KvReplicaBacking::Allocation(_), OwnerReclaimBacking::UnindexedAllocation) => { + !replica.owner_local_indexed + } + ( + KvReplicaBacking::CommittedSlot(slot), + OwnerReclaimBacking::CommittedSlot { + grant_id, + slot_index, + slot_size, + }, + ) => { + slot.grant_id == *grant_id + && slot.slot_index == *slot_index + && slot.slot_size == *slot_size + } + _ => false, + } +} + +fn remove_reclaimed_replica( + view: &MasterKvRouterView, + owner: &NodeID, + item: &OwnerReclaimItem, +) -> bool { + if !view + .master_kv_router() + .inner() + .key_activity + .reclaim_matches(item) + { + return false; + } + let _route_guard = view.master_kv_router().inner().route_lifetime_lock.lock(); + let Some(route) = view + .master_kv_router() + .inner() + .kv_routes + .get(&item.key) + .map(|route| route.clone()) + else { + return true; + }; + if route.put_id != item.put_id { + return true; + } + let removed = { + let mut replicas = route.nodes_replicas.write(); + let Some(replica) = replicas.get(owner) else { + return true; + }; + if !reclaim_backing_matches(replica, &item.backing) { + // This backing is no longer advertised by the fenced route version. + return true; + } + replicas.remove(owner).is_some() + }; + if !removed { + return true; + } + + if route.nodes_replicas.read().is_empty() { + let route_removed = view + .master_kv_router() + .inner() + .kv_routes + .remove_if(&item.key, |_, current| current.put_id == item.put_id) + .is_some(); + if route_removed && view.master_kv_router().prefix_index_enabled() { + let view_task = view.clone(); + let key = item.key.clone(); + let put_id = item.put_id; + let spawn_view = view.clone(); + let _ = spawn_view.spawn("owner_reclaim_remove_prefix", async move { + let mut tree = view_task + .master_kv_router() + .inner() + .prefix_index + .write() + .await; + tree.remove(&key, put_id); + }); + } + } + if let Some(cache) = view + .master_kv_router() + .get_node_cache_controller(owner.as_ref()) + { + let _ = cache.remove(&item.key); + } + view.master_kv_router() + .remove_node_writeback_tier1_entry(owner.as_ref(), &item.key); + true +} + +fn finish_unindexed_allocations( + view: &MasterKvRouterView, + owner: &NodeID, + items: Vec, +) -> u32 { + let mut reclaimed = 0u32; + for item in items { + debug_assert_eq!(item.backing, OwnerReclaimBacking::UnindexedAllocation); + if remove_reclaimed_replica(view, owner, &item) { + clear_master_fence(view, &item); + reclaimed = reclaimed.saturating_add(1); + } else { + tracing::error!( + "unindexed allocation reclaim backing could not be removed from master route: owner={} key={} epoch={}", + owner, + item.key, + item.epoch + ); + } + } + reclaimed +} + +fn partition_reclaim_coordination( + items: Vec, +) -> (Vec, Vec) { + items + .into_iter() + .partition(|item| item.backing == OwnerReclaimBacking::UnindexedAllocation) +} + +async fn finish_committed( + view: &MasterKvRouterView, + owner: &NodeID, + items: Vec, +) -> u32 { + let mut removed = Vec::new(); + for item in items { + if remove_reclaimed_replica(view, owner, &item) { + removed.push(item); + } else { + tracing::error!( + "owner reclaim backing could not be removed from master route: owner={} key={} epoch={}", + owner, + item.key, + item.epoch + ); + } + } + if removed.is_empty() { + return 0; + } + match call_owner_phase(view, owner, OwnerReclaimPhase::Finalize, removed.clone()).await { + Ok(responses) => { + let mut finalized = 0u32; + let mut retry = Vec::new(); + for (item, response) in removed.into_iter().zip(responses.into_iter()) { + if response.state == OwnerReclaimItemState::Finalized { + clear_master_fence(view, &item); + finalized = finalized.saturating_add(1); + } else { + tracing::warn!( + "owner reclaim finalize returned unresolved state: owner={} key={} epoch={} state={:?} detail={}", + owner, + item.key, + item.epoch, + response.state, + response.detail + ); + retry.push(item); + } + } + spawn_finalize_retry(view.clone(), owner.clone(), retry); + finalized + } + Err(err) => { + tracing::warn!( + "owner reclaim finalize RPC failed; retaining both fences: owner={} keys={} err={}", + owner, + removed.len(), + err + ); + spawn_finalize_retry(view.clone(), owner.clone(), removed); + 0 + } + } +} + +fn spawn_finalize_retry(view: MasterKvRouterView, owner: NodeID, items: Vec) { + if items.is_empty() { + return; + } + let spawn_view = view.clone(); + let _ = spawn_view.spawn("owner_reclaim_finalize_retry", async move { + let mut pending = items; + let mut delay = Duration::from_millis(25); + for _attempt in 1..=8 { + tokio::time::sleep(delay).await; + match call_owner_phase(&view, &owner, OwnerReclaimPhase::Finalize, pending.clone()) + .await + { + Ok(responses) => { + let mut next = Vec::new(); + for (item, response) in pending.into_iter().zip(responses.into_iter()) { + if response.state == OwnerReclaimItemState::Finalized { + clear_master_fence(&view, &item); + } else { + next.push(item); + } + } + pending = next; + if pending.is_empty() { + return; + } + } + Err(err) => tracing::warn!( + "owner reclaim finalize retry failed: owner={} keys={} err={}", + owner, + pending.len(), + err + ), + } + delay = (delay * 2).min(Duration::from_secs(1)); + } + tracing::error!( + "owner reclaim finalize retry exhausted; fences retained: owner={} keys={}", + owner, + pending.len() + ); + }); +} + +async fn reclaim_items( + view: &MasterKvRouterView, + owner: &NodeID, + candidates: Vec, +) -> u32 { + let counters = view + .master_kv_router() + .eviction_reclaim_counters(owner.as_ref()); + let mut fenced = Vec::new(); + for item in candidates { + if master_has_holder(view, &item.key) { + // A completed get holder keeps an Allocation alive after its route disappears. It is + // not a reclaim exclusion: owner Prepare is the authority that fences the local index + // and rejects reclaim only while a real MemoryInfo reader is still active. + counters + .master_get_holder_observed + .fetch_add(1, Ordering::Relaxed); + } + match view + .master_kv_router() + .inner() + .key_activity + .try_install_reclaim(&item) + { + Ok(()) => { + if item_still_valid(view, owner, &item) { + fenced.push(item); + } else { + counters.route_changed.fetch_add(1, Ordering::Relaxed); + clear_master_fence(view, &item); + } + } + Err(activity) => { + counters + .master_activity_deferred + .fetch_add(1, Ordering::Relaxed); + tracing::trace!( + "owner reclaim deferred by master activity: owner={} key={} puts={} gets={} replicas={} reclaim_installed={}", + owner, + item.key, + activity.puts, + activity.gets, + activity.replicas, + activity.reclaim_installed + ); + } + } + } + if fenced.is_empty() { + return 0; + } + + let (master_only, owner_coordinated) = partition_reclaim_coordination(fenced); + let master_reclaimed = finish_unindexed_allocations(view, owner, master_only); + if owner_coordinated.is_empty() { + counters + .completed + .fetch_add(u64::from(master_reclaimed), Ordering::Relaxed); + return master_reclaimed; + } + + let prepare_responses = match call_owner_phase( + view, + owner, + OwnerReclaimPhase::Prepare, + owner_coordinated.clone(), + ) + .await + { + Ok(responses) => responses, + Err(err) => { + tracing::warn!( + "owner reclaim prepare RPC failed; aborting batch: owner={} keys={} err={}", + owner, + owner_coordinated.len(), + err + ); + let _ = abort_prepared(view, owner, owner_coordinated).await; + counters + .completed + .fetch_add(u64::from(master_reclaimed), Ordering::Relaxed); + return master_reclaimed; + } + }; + let mut prepared = Vec::new(); + let mut committed = Vec::new(); + for (item, response) in owner_coordinated + .into_iter() + .zip(prepare_responses.into_iter()) + { + match response.state { + OwnerReclaimItemState::Prepared => prepared.push(item), + OwnerReclaimItemState::Committed => committed.push(item), + OwnerReclaimItemState::Busy => { + if response.detail == "owner local memory still has active holders" { + counters + .owner_holder_deferred + .fetch_add(1, Ordering::Relaxed); + } else { + counters + .owner_other_deferred + .fetch_add(1, Ordering::Relaxed); + } + clear_master_fence(view, &item); + } + _ => { + counters + .owner_other_deferred + .fetch_add(1, Ordering::Relaxed); + clear_master_fence(view, &item); + } + } + } + + let mut invalid_prepared = Vec::new(); + prepared.retain(|item| { + if master_has_holder(view, &item.key) { + counters + .master_get_holder_observed + .fetch_add(1, Ordering::Relaxed); + } + let valid = item_still_valid(view, owner, item); + if !valid { + counters.route_changed.fetch_add(1, Ordering::Relaxed); + invalid_prepared.push(item.clone()); + } + valid + }); + committed.extend(abort_prepared(view, owner, invalid_prepared).await); + + if !prepared.is_empty() { + match call_owner_phase(view, owner, OwnerReclaimPhase::Commit, prepared.clone()).await { + Ok(responses) => { + let mut unresolved = Vec::new(); + for (item, response) in prepared.into_iter().zip(responses.into_iter()) { + if response.state == OwnerReclaimItemState::Committed { + committed.push(item); + } else { + unresolved.push(item); + } + } + committed.extend(abort_prepared(view, owner, unresolved).await); + } + Err(err) => { + tracing::warn!( + "owner reclaim commit RPC failed; resolving with abort: owner={} keys={} err={}", + owner, + prepared.len(), + err + ); + committed.extend(abort_prepared(view, owner, prepared).await); + } + } + } + let reclaimed = master_reclaimed.saturating_add(finish_committed(view, owner, committed).await); + counters + .completed + .fetch_add(u64::from(reclaimed), Ordering::Relaxed); + reclaimed +} + +fn collect_reserve_candidates( + view: &MasterKvRouterView, + owner: &NodeID, + slot_size: u64, + limit: usize, +) -> Vec { + let mut candidates = Vec::new(); + // Moka iteration may synchronously drain cache maintenance and eviction listeners. Under + // pressure that made a 256-item candidate lookup take seconds. Route metadata is the + // reclaim authority, so snapshot its keys and validate candidates directly instead. + let route_keys = view + .master_kv_router() + .inner() + .kv_routes + .iter() + .map(|route| route.key().clone()) + .collect::>(); + for key in route_keys { + if candidates.len() >= limit { + break; + } + if !view + .master_kv_router() + .inner() + .key_activity + .is_quiescent(&key) + { + continue; + } + if let Some(item) = route_item( + view, + owner, + &key, + None, + Some(slot_size), + OwnerReclaimReason::Reserve, + view.master_kv_router().next_owner_reclaim_epoch(), + ) { + candidates.push(item); + } + } + candidates +} + +async fn reclaim_reserve_candidate_batches( + candidates: Vec, + required_free_slots: u32, + mut reclaim_batch: F, +) -> (u32, usize) +where + F: FnMut(Vec) -> Fut, + Fut: Future, +{ + let mut reclaimed = 0u32; + let mut scanned_candidates = 0usize; + while reclaimed < required_free_slots && scanned_candidates < candidates.len() { + let remaining_slots = required_free_slots.saturating_sub(reclaimed); + let batch_len = usize::try_from(remaining_slots) + .unwrap_or(usize::MAX) + .min(candidates.len() - scanned_candidates); + let batch_end = scanned_candidates + batch_len; + let batch = candidates[scanned_candidates..batch_end].to_vec(); + scanned_candidates = batch_end; + + let batch_size = u32::try_from(batch.len()).unwrap_or(u32::MAX); + let batch_reclaimed = reclaim_batch(batch).await; + debug_assert!(batch_reclaimed <= batch_size); + reclaimed = reclaimed.saturating_add(batch_reclaimed.min(batch_size)); + } + (reclaimed, scanned_candidates) +} + +#[cfg(test)] +mod reserve_scan_tests { + use super::{ + OwnerReclaimBacking, OwnerReclaimItem, OwnerReclaimReason, partition_reclaim_coordination, + reclaim_reserve_candidate_batches, + }; + use std::future::ready; + + fn candidate(index: u32) -> OwnerReclaimItem { + OwnerReclaimItem { + key: format!("candidate-{index}"), + put_id: (u64::from(index), 0), + epoch: u64::from(index), + backing: OwnerReclaimBacking::CommittedSlot { + grant_id: u64::from(index), + slot_index: index, + slot_size: 8 * 1024 * 1024, + }, + reason: OwnerReclaimReason::Reserve, + } + } + + #[test] + fn only_unindexed_allocations_skip_owner_coordination() { + let mut indexed_allocation = candidate(1); + indexed_allocation.backing = OwnerReclaimBacking::Allocation; + indexed_allocation.reason = OwnerReclaimReason::CapacityEviction; + let mut unindexed_allocation = candidate(2); + unindexed_allocation.backing = OwnerReclaimBacking::UnindexedAllocation; + unindexed_allocation.reason = OwnerReclaimReason::CapacityEviction; + let committed_slot = candidate(3); + + let (master_only, owner_coordinated) = partition_reclaim_coordination(vec![ + indexed_allocation, + unindexed_allocation.clone(), + committed_slot, + ]); + + assert_eq!(master_only, vec![unindexed_allocation]); + assert_eq!(owner_coordinated.len(), 2); + assert!( + owner_coordinated + .iter() + .all(|item| item.backing != OwnerReclaimBacking::UnindexedAllocation) + ); + } + + #[limit_thirdparty::tokio::test] + async fn reserve_scan_continues_after_busy_first_batch() { + let candidates = (0..12).map(candidate).collect::>(); + let mut batches = Vec::new(); + let mut call_count = 0usize; + + let (reclaimed, scanned_candidates) = + reclaim_reserve_candidate_batches(candidates, 5, |batch: Vec| { + call_count += 1; + batches.push( + batch + .iter() + .map(|item| item.key.clone()) + .collect::>(), + ); + ready(if call_count == 1 { + 0 + } else { + u32::try_from(batch.len()).unwrap() + }) + }) + .await; + + assert_eq!(reclaimed, 5); + assert_eq!(scanned_candidates, 10); + assert_eq!(batches.len(), 2); + assert_eq!(batches[0][0], "candidate-0"); + assert_eq!(batches[0][4], "candidate-4"); + assert_eq!(batches[1][0], "candidate-5"); + assert_eq!(batches[1][4], "candidate-9"); + } + + #[limit_thirdparty::tokio::test] + async fn reserve_scan_shrinks_next_batch_after_partial_reclaim() { + let candidates = (0..10).map(candidate).collect::>(); + let mut batch_lengths = Vec::new(); + let mut call_count = 0usize; + + let (reclaimed, scanned_candidates) = + reclaim_reserve_candidate_batches(candidates, 5, |batch| { + call_count += 1; + batch_lengths.push(batch.len()); + ready(if call_count == 1 { 2 } else { 3 }) + }) + .await; + + assert_eq!(reclaimed, 5); + assert_eq!(scanned_candidates, 8); + assert_eq!(batch_lengths, vec![5, 3]); + } +} + +#[cfg(test)] +mod owner_get_holding_reclaim_tests { + use super::{OwnerReclaimBacking, OwnerReclaimReason, reclaim_items, route_item}; + use crate::client_kv_api::PutOptionalArgs; + use crate::kvcore_test_lib::{ + integration_test_lock, start_master_and_client, stop_master_and_client, + }; + use crate::memholder::{MemholderManagerTrait, NodeHolderKey}; + use std::time::{Duration, Instant}; + + #[limit_thirdparty::tokio::test(flavor = "multi_thread", worker_threads = 8)] + async fn completed_get_holding_does_not_block_two_sided_owner_reclaim() { + let _test_guard = integration_test_lock().await; + let (master, client) = + start_master_and_client("reclaim_get_holding_master", "reclaim_get_holding_owner") + .await; + let key = "completed_get_holding_reclaim_key"; + let owner_view = client.client_kv_api_view(); + let owner_api = owner_view.client_kv_api(); + owner_api + .inner() + .put(key, &[7u8; 4096], PutOptionalArgs::default()) + .await + .expect("owner put"); + let (holder, _get_info) = owner_api + .inner() + .get(key) + .await + .expect("owner get") + .expect("owner get should hit"); + + let owner_id = client + .cluster_manager_view() + .cluster_manager() + .get_self_info() + .id; + let holding_key = NodeHolderKey::new(owner_id.clone(), holder.holder_id()); + let master_view = master.master_kv_router_view().clone(); + assert!( + master_view + .master_kv_router() + .inner() + .get_holding + .inner() + .contains_key(&holding_key), + "get_done must install the Allocation lifetime holder" + ); + + assert!( + master_view + .master_kv_router() + .inner() + .key_activity + .is_quiescent(key), + "completed get must release its master key-activity lease" + ); + let owner_node = owner_id.clone().into(); + let busy_item = route_item( + &master_view, + &owner_node, + key, + None, + None, + OwnerReclaimReason::CapacityEviction, + master_view.master_kv_router().next_owner_reclaim_epoch(), + ) + .expect("active-holder owner route should be reclaimable after the reader exits"); + assert_eq!( + reclaim_items(&master_view, &owner_node, vec![busy_item]).await, + 0, + "owner Prepare must reject reclaim while the user holder is live" + ); + + drop(holder); + limit_thirdparty::tokio::time::sleep(Duration::from_millis(50)).await; + assert!( + master_view + .master_kv_router() + .inner() + .get_holding + .inner() + .contains_key(&holding_key), + "the committed local index intentionally keeps MemoryInfo and its ACK holder alive" + ); + + let item = route_item( + &master_view, + &owner_node, + key, + None, + None, + OwnerReclaimReason::CapacityEviction, + master_view.master_kv_router().next_owner_reclaim_epoch(), + ) + .expect("current owner route should be reclaimable"); + assert_eq!( + item.backing, + OwnerReclaimBacking::Allocation, + "reuse-replica get_done must publish the owner-local index on the route" + ); + assert_eq!( + reclaim_items(&master_view, &owner_node, vec![item]).await, + 1 + ); + + let wait_started = Instant::now(); + while master_view + .master_kv_router() + .inner() + .get_holding + .inner() + .contains_key(&holding_key) + { + assert!( + wait_started.elapsed() < Duration::from_secs(5), + "owner reclaim must drop MemoryInfo and deliver its delete ACK" + ); + limit_thirdparty::tokio::time::sleep(Duration::from_millis(20)).await; + } + assert!( + !master_view + .master_kv_router() + .inner() + .kv_routes + .contains_key(key), + "the reclaimed last replica route must be removed" + ); + + stop_master_and_client(master, client).await; + } +} + +pub(crate) async fn reclaim_owner_slots_for_reserve( + view: &MasterKvRouterView, + owner_node_id: &NodeID, + slot_size: u64, + required_free_slots: u32, +) -> u32 { + if slot_size == 0 || required_free_slots == 0 { + return 0; + } + let scan_started = Instant::now(); + let candidates = + collect_reserve_candidates(view, owner_node_id, slot_size, OWNER_RECLAIM_MAX_BATCH); + let candidate_scan_us = scan_started.elapsed().as_micros(); + let candidate_count = candidates.len(); + let (reclaimed, scanned_candidate_count) = + reclaim_reserve_candidate_batches(candidates, required_free_slots, |batch| { + reclaim_items(view, owner_node_id, batch) + }) + .await; + tracing::info!( + "owner reserve reclaim completed: owner={} slot_size={} requested_slots={} candidates={} scanned_candidates={} reclaimed={} candidate_scan_us={}", + owner_node_id, + slot_size, + required_free_slots, + candidate_count, + scanned_candidate_count, + reclaimed, + candidate_scan_us + ); + reclaimed +} + +fn spawn_eviction_reclaim_retry(view: MasterKvRouterView, requests: Vec) { + if requests.is_empty() { + return; + } + let mut delayed = Vec::with_capacity(requests.len()); + let mut restored_count = 0usize; + let mut restored_weight = 0u64; + for mut request in requests { + request.retry_count = request.retry_count.saturating_add(1); + let counters = view + .master_kv_router() + .eviction_reclaim_counters(&request.owner_node_id); + let weight = u64::from(request.desc.weight_bytes); + if !view.master_kv_router().eviction_cache_entry_is_current( + &request.owner_node_id, + &request.key, + &request.desc, + ) { + view.master_kv_router() + .complete_eviction_reclaim_weight(&request.owner_node_id, weight); + counters.route_changed.fetch_add(1, Ordering::Relaxed); + counters.retry_completed.fetch_add(1, Ordering::Relaxed); + continue; + } + if should_restore_after_retry(request.retry_count) { + let restored = view + .master_kv_router() + .restore_eviction_cache_entry_if_current( + &request.owner_node_id, + request.key.clone(), + request.desc.clone(), + ); + if restored { + view.master_kv_router() + .complete_eviction_reclaim_weight(&request.owner_node_id, weight); + counters.retry_restored.fetch_add(1, Ordering::Relaxed); + counters.retry_completed.fetch_add(1, Ordering::Relaxed); + restored_count += 1; + restored_weight = restored_weight.saturating_add(weight); + continue; + } + if !view.master_kv_router().eviction_cache_entry_is_current( + &request.owner_node_id, + &request.key, + &request.desc, + ) { + view.master_kv_router() + .complete_eviction_reclaim_weight(&request.owner_node_id, weight); + counters.route_changed.fetch_add(1, Ordering::Relaxed); + counters.retry_completed.fetch_add(1, Ordering::Relaxed); + continue; + } + } + counters.retry_queued.fetch_add(1, Ordering::Relaxed); + delayed.push(request); + } + if restored_count != 0 { + tracing::info!( + "safe eviction reclaim restored current cache entries after bounded retry: entries={} weight_bytes={} max_retry_count={}", + restored_count, + restored_weight, + EVICTION_RECLAIM_MAX_RETRY_COUNT + ); + } + if delayed.is_empty() { + return; + } + let max_retry_count = delayed + .iter() + .map(|request| request.retry_count) + .max() + .unwrap_or(1); + let retry_delay = eviction_reclaim_retry_delay(max_retry_count); + let spawn_view = view.clone(); + let _ = spawn_view.spawn("eviction_reclaim_retry", async move { + tokio::time::sleep(retry_delay).await; + let tx = view.master_kv_router().inner().eviction_reclaim_tx.clone(); + for request in delayed { + let weight = u64::from(request.desc.weight_bytes); + let counters = view + .master_kv_router() + .eviction_reclaim_counters(&request.owner_node_id); + if !view.master_kv_router().eviction_cache_entry_is_current( + &request.owner_node_id, + &request.key, + &request.desc, + ) { + view.master_kv_router() + .complete_eviction_reclaim_weight(&request.owner_node_id, weight); + counters.route_changed.fetch_add(1, Ordering::Relaxed); + counters.retry_completed.fetch_add(1, Ordering::Relaxed); + continue; + } + let restore_request = request.clone(); + if tx.send(request).await.is_err() { + view.master_kv_router() + .complete_eviction_reclaim_weight(&restore_request.owner_node_id, weight); + let restored = view + .master_kv_router() + .restore_eviction_cache_entry_if_current( + &restore_request.owner_node_id, + restore_request.key, + restore_request.desc, + ); + counters.retry_completed.fetch_add(1, Ordering::Relaxed); + if restored { + counters.retry_restored.fetch_add(1, Ordering::Relaxed); + } + tracing::warn!( + "safe eviction reclaim retry queue closed: owner={} restored={}", + restore_request.owner_node_id, + restored + ); + } + } + }); +} + +pub(crate) fn spawn_eviction_reclaim_actor( + view: MasterKvRouterView, + mut rx: limit_thirdparty::tokio::sync::ampsc::Receiver, +) { + let view_task = view.clone(); + let _ = view.spawn("eviction_reclaim_actor", async move { + let mut shutdown_waiter = view_task.register_shutdown_waiter(); + loop { + let first = tokio::select! { + _ = shutdown_waiter.wait() => break, + request = rx.recv() => { + let Some(request) = request else { break; }; + request + } + }; + let mut batch = Vec::with_capacity(OWNER_RECLAIM_MAX_BATCH); + batch.push(first); + let mut merge_window = Box::pin(tokio::time::sleep(OWNER_RECLAIM_MERGE_WINDOW)); + while batch.len() < OWNER_RECLAIM_MAX_BATCH { + tokio::select! { + _ = &mut merge_window => break, + request = rx.recv() => { + let Some(request) = request else { break; }; + batch.push(request); + } + } + } + + let mut groups: HashMap> = HashMap::new(); + for request in batch { + groups + .entry(request.owner_node_id.clone()) + .or_default() + .push(request); + } + for (owner_node_id, requests) in groups { + let owner: NodeID = owner_node_id.clone().into(); + let counters = view_task + .master_kv_router() + .eviction_reclaim_counters(&owner_node_id); + let mut seen = HashSet::new(); + let mut items = Vec::new(); + let mut unique_requests = Vec::new(); + let mut completed_weight = 0u64; + for request in requests { + if !seen.insert((request.key.clone(), request.desc.put_id)) { + completed_weight = completed_weight + .saturating_add(u64::from(request.desc.weight_bytes)); + continue; + } + if let Some(item) = route_item( + &view_task, + &owner, + &request.key, + Some(request.desc.put_id), + None, + OwnerReclaimReason::CapacityEviction, + view_task.master_kv_router().next_owner_reclaim_epoch(), + ) { + items.push(item); + } + unique_requests.push(request); + } + let candidate_count = items.len(); + let reclaimed = reclaim_items(&view_task, &owner, items).await; + let mut retry_requests = Vec::new(); + for request in unique_requests { + if view_task + .master_kv_router() + .eviction_cache_entry_is_current( + &owner_node_id, + &request.key, + &request.desc, + ) + { + retry_requests.push(request); + } else { + completed_weight = completed_weight + .saturating_add(u64::from(request.desc.weight_bytes)); + counters.route_changed.fetch_add(1, Ordering::Relaxed); + if request.retry_count != 0 { + counters.retry_completed.fetch_add(1, Ordering::Relaxed); + } + } + } + view_task.master_kv_router().complete_eviction_reclaim_weight( + &owner_node_id, + completed_weight, + ); + let retry_count = retry_requests.len(); + spawn_eviction_reclaim_retry(view_task.clone(), retry_requests); + tracing::trace!( + "batched safe eviction reclaim completed: owner={} candidates={} reclaimed={} retry_deferred={} completed_weight={}", + owner_node_id, + candidate_count, + reclaimed, + retry_count, + completed_weight + ); + } + } + }); +} diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/route_maintenance.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/route_maintenance.rs new file mode 100644 index 0000000..b1c0932 --- /dev/null +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/route_maintenance.rs @@ -0,0 +1,349 @@ +use super::{MasterKvRouterView, NodeValueReplicaDesc, put::PutIDForAKey}; +use crate::cluster_manager::NodeID; +use limit_thirdparty::tokio; +use std::collections::{HashMap, HashSet}; +use std::time::Duration; + +const POST_ROUTE_MAINTENANCE_MAX_BATCH: usize = 512; +const POST_ROUTE_MAINTENANCE_MERGE_WINDOW: Duration = Duration::from_millis(2); + +#[derive(Clone, Copy)] +enum RoutePublishKind { + PrimaryPut, + ReplicaAppend, +} + +pub(super) struct RoutePublishEvent { + kind: RoutePublishKind, + key: String, + put_id: PutIDForAKey, + lease_id: Option, + node_id: NodeID, + capacity_bytes: u64, +} + +impl RoutePublishEvent { + pub(super) fn primary_put( + key: String, + put_id: PutIDForAKey, + lease_id: Option, + node_id: NodeID, + capacity_bytes: u64, + ) -> Self { + Self { + kind: RoutePublishKind::PrimaryPut, + key, + put_id, + lease_id, + node_id, + capacity_bytes, + } + } + + pub(super) fn replica_append( + key: String, + put_id: PutIDForAKey, + lease_id: Option, + node_id: NodeID, + capacity_bytes: u64, + ) -> Self { + Self { + kind: RoutePublishKind::ReplicaAppend, + key, + put_id, + lease_id, + node_id, + capacity_bytes, + } + } +} + +fn saturating_moka_weight_bytes(key: &str, put_id: PutIDForAKey, capacity_bytes: u64) -> u32 { + if capacity_bytes > u32::MAX as u64 { + tracing::warn!( + "moka weight saturation after route publish: key={} put_id=({},{}) cap={}B exceeds u32::MAX; weight set to u32::MAX", + key, + put_id.0, + put_id.1, + capacity_bytes + ); + u32::MAX + } else { + capacity_bytes as u32 + } +} + +fn projected_batch_weight(current_weight: u64, replaced_weight: u64, incoming_weight: u64) -> u64 { + current_weight + .saturating_sub(replaced_weight) + .saturating_add(incoming_weight) +} + +fn deduplicate_owner_events( + events: Vec<(usize, String, NodeValueReplicaDesc)>, +) -> Vec<(String, NodeValueReplicaDesc)> { + let mut latest_by_key = HashMap::with_capacity(events.len()); + for (sequence, key, desc) in events { + latest_by_key.insert(key, (sequence, desc)); + } + let mut latest = latest_by_key.into_iter().collect::>(); + latest.sort_unstable_by_key(|(_, (sequence, _))| *sequence); + latest + .into_iter() + .map(|(key, (_, desc))| (key, desc)) + .collect() +} + +/// Applies index and cache work after route guards have been released. +async fn apply_post_route_maintenance_batch( + view: &MasterKvRouterView, + events: Vec, +) { + if view.master_kv_router().prefix_index_enabled() + && events + .iter() + .any(|event| matches!(event.kind, RoutePublishKind::PrimaryPut)) + { + let inner = view.master_kv_router().inner(); + let mut tree = inner.prefix_index.write().await; + for event in &events { + if matches!(event.kind, RoutePublishKind::PrimaryPut) { + let event_is_current = inner.kv_routes.get(&event.key).is_some_and(|route| { + route.put_id == event.put_id + && route + .nodes_replicas + .read() + .values() + .any(|replica| !replica.tomb_tag.is_tomb()) + }); + if event_is_current { + tree.insert(&event.key, event.put_id); + } + } + } + } + + if !view.master_kv_router().replica_cache_enabled() { + return; + } + let mut events_by_owner = HashMap::>::new(); + for (sequence, event) in events.into_iter().enumerate() { + if event.lease_id.is_some() { + continue; + } + let weight_bytes = + saturating_moka_weight_bytes(&event.key, event.put_id, event.capacity_bytes); + let desc = NodeValueReplicaDesc { + weight_bytes, + put_id: event.put_id, + }; + if !view.master_kv_router().eviction_cache_entry_is_current( + event.node_id.as_ref(), + &event.key, + &desc, + ) { + continue; + } + events_by_owner + .entry(event.node_id.as_ref().to_string()) + .or_default() + .push((sequence, event.key, desc)); + } + + for (owner_node_id, owner_events) in events_by_owner { + let entries = deduplicate_owner_events(owner_events); + let Some(cache) = view + .master_kv_router() + .get_node_cache_controller(&owner_node_id) + else { + tracing::warn!( + "No cache controller found for node: {}, node is not ready", + owner_node_id + ); + continue; + }; + + // Drain prior writes once, then admit this owner batch as one unit. This exposes the + // aggregate incoming weight to the explicit resident-capacity policy. + cache.run_pending_tasks(); + let weighted_size_before = cache.weighted_size(); + let replaced_weight = entries + .iter() + .filter_map(|(key, _)| cache.get(key)) + .map(|existing| u64::from(existing.weight_bytes)) + .fold(0u64, u64::saturating_add); + let incoming_weight = entries + .iter() + .map(|(_, desc)| u64::from(desc.weight_bytes)) + .fold(0u64, u64::saturating_add); + let projected_weight = + projected_batch_weight(weighted_size_before, replaced_weight, incoming_weight); + let node_space_size = view + .master_seg_manager() + .get_node_space_size(&owner_node_id); + let capacity = view + .master_kv_router() + .replica_cache_effective_capacity(&owner_node_id, node_space_size); + let requested_weight = projected_weight.saturating_sub(capacity); + let incoming_keys = entries + .iter() + .map(|(key, _)| key.clone()) + .collect::>(); + + let recoverable_selected_weight = view + .master_kv_router() + .evict_recoverable_cache_weight_excluding( + &owner_node_id, + requested_weight, + &incoming_keys, + ); + let fallback_requested_weight = + requested_weight.saturating_sub(recoverable_selected_weight); + let fallback_selected_weight = if view + .master_kv_router() + .owner_cache_allows_unrecoverable_eviction(&owner_node_id) + { + cache.evict_some_if(fallback_requested_weight, |key, _desc| { + !incoming_keys.contains(key) + }) + } else { + 0 + }; + if requested_weight != 0 { + tracing::debug!( + "recoverable-first batch admission: owner={} entries={} weighted_size_before={} replaced_weight={} incoming_weight={} projected_weight={} capacity={} requested_weight={} recoverable_selected_weight={} fallback_requested_weight={} fallback_selected_weight={} shortfall_weight={}", + owner_node_id, + entries.len(), + weighted_size_before, + replaced_weight, + incoming_weight, + projected_weight, + capacity, + requested_weight, + recoverable_selected_weight, + fallback_requested_weight, + fallback_selected_weight, + fallback_requested_weight.saturating_sub(fallback_selected_weight), + ); + } + + let tier1_cache = view + .master_kv_router() + .get_node_writeback_tier1_controller(&owner_node_id); + for (key, desc) in entries { + tracing::debug!("Inserting key: {:?} into cache", key); + cache.insert(key.clone(), desc.clone()); + if let Some(tier1_cache) = tier1_cache.as_ref() { + tier1_cache.insert(key.clone(), desc); + } + tracing::debug!( + "Inserted key: {:?} into cache, current cache size: {}", + key, + cache.weighted_size() + ); + } + } +} + +pub(super) fn spawn_post_route_maintenance_actor( + view: MasterKvRouterView, + mut rx: tokio::sync::ampsc::Receiver, +) { + let view_task = view.clone(); + view.spawn("post_route_maintenance_actor", async move { + tracing::info!( + "post-route maintenance actor started: max_batch={} merge_window_ms={}", + POST_ROUTE_MAINTENANCE_MAX_BATCH, + POST_ROUTE_MAINTENANCE_MERGE_WINDOW.as_millis(), + ); + let mut shutdown_waiter = view_task.register_shutdown_waiter(); + loop { + let first = tokio::select! { + _ = shutdown_waiter.wait() => break, + event = rx.recv() => { + let Some(event) = event else { break; }; + event + } + }; + let mut events = Vec::with_capacity(POST_ROUTE_MAINTENANCE_MAX_BATCH); + events.push(first); + let mut merge_window = + Box::pin(tokio::time::sleep(POST_ROUTE_MAINTENANCE_MERGE_WINDOW)); + while events.len() < POST_ROUTE_MAINTENANCE_MAX_BATCH { + tokio::select! { + _ = &mut merge_window => break, + event = rx.recv() => { + let Some(event) = event else { break; }; + events.push(event); + } + } + } + apply_post_route_maintenance_batch(&view_task, events).await; + } + tracing::info!("post-route maintenance actor stopped"); + }); +} + +/// Queues index and cache work with bounded backpressure after route publication. +pub(super) async fn enqueue_post_route_maintenance( + view: &MasterKvRouterView, + event: RoutePublishEvent, +) { + let update_prefix_index = matches!(event.kind, RoutePublishKind::PrimaryPut) + && view.master_kv_router().prefix_index_enabled(); + let insert_replica_cache = + event.lease_id.is_none() && view.master_kv_router().replica_cache_enabled(); + if !update_prefix_index && !insert_replica_cache { + return; + } + view.master_kv_router() + .inner() + .post_route_maintenance_tx + .send(event) + .await + .expect("post-route maintenance actor stopped while master is serving requests"); +} + +#[cfg(test)] +mod tests { + use super::{deduplicate_owner_events, projected_batch_weight, saturating_moka_weight_bytes}; + use crate::master_kv_router::NodeValueReplicaDesc; + + #[test] + fn moka_weight_saturates_without_truncating() { + assert_eq!( + saturating_moka_weight_bytes("key", (1, 2), u32::MAX as u64), + u32::MAX + ); + assert_eq!( + saturating_moka_weight_bytes("key", (1, 2), u32::MAX as u64 + 1), + u32::MAX + ); + } + + #[test] + fn projected_weight_accounts_for_batch_replacements_once() { + assert_eq!(projected_batch_weight(90, 30, 50), 110); + assert_eq!(projected_batch_weight(10, 20, 5), 5); + } + + #[test] + fn owner_batch_keeps_only_the_last_event_for_each_key() { + let desc = |weight_bytes, put_id| NodeValueReplicaDesc { + weight_bytes, + put_id, + }; + let events = vec![ + (0, "a".to_string(), desc(10, (1, 0))), + (1, "b".to_string(), desc(20, (1, 0))), + (2, "a".to_string(), desc(30, (2, 0))), + ]; + + let deduplicated = deduplicate_owner_events(events); + assert_eq!(deduplicated.len(), 2); + assert_eq!(deduplicated[0].0, "b"); + assert_eq!(deduplicated[1].0, "a"); + assert_eq!(deduplicated[1].1.weight_bytes, 30); + assert_eq!(deduplicated[1].1.put_id, (2, 0)); + } +} diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/tiered_writeback.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/tiered_writeback.rs new file mode 100644 index 0000000..97ebfd1 --- /dev/null +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/tiered_writeback.rs @@ -0,0 +1,224 @@ +use super::{MasterKvRouterView, NodeValueReplicaDesc}; +use crate::cluster_manager::{NodeID, NodeIDString}; +use crate::master_kv_router::msg_pack::{BatchEnqueueReplicaTaskReq, EnqueueReplicaTaskItem}; +use crate::p2p::msg_pack::{MIN_EXPLICIT_RPC_TIMEOUT_SECS, MsgPack, RPCCaller}; +use crate::rpcresp_kvresult_convert::msg_and_error::OK; +use limit_thirdparty::tokio; +use std::collections::HashMap; +use std::time::Duration; + +const TIER1_WRITEBACK_RPC_TIMEOUT: Duration = Duration::from_secs(MIN_EXPLICIT_RPC_TIMEOUT_SECS); +const TIER1_WRITEBACK_MAX_BATCH: usize = 256; +const TIER1_WRITEBACK_MERGE_WINDOW: Duration = Duration::from_millis(2); + +#[derive(Clone, Debug)] +pub(crate) struct Tier1WritebackRequest { + pub source_node_id: NodeIDString, + pub key: String, + pub desc: NodeValueReplicaDesc, +} + +async fn dispatch_owner_batch( + view: &MasterKvRouterView, + source_node_id: NodeIDString, + requests: Vec, +) { + let mut current = Vec::with_capacity(requests.len()); + for request in requests { + if view.master_kv_router().tier1_writeback_entry_is_current( + &request.source_node_id, + &request.key, + &request.desc, + ) { + current.push(request); + } else { + view.master_kv_router() + .finish_tier1_writeback_request(request); + } + } + if current.is_empty() { + return; + } + + let items = current + .iter() + .map(|request| EnqueueReplicaTaskItem { + key: request.key.clone(), + put_id: request.desc.put_id, + }) + .collect::>(); + let caller = RPCCaller::::new(); + caller.regist(view.p2p_module()); + let result = caller + .call( + view.p2p_module(), + NodeID::from(source_node_id.clone()), + MsgPack { + serialize_part: BatchEnqueueReplicaTaskReq { items }, + raw_bytes: Vec::new(), + }, + Some(TIER1_WRITEBACK_RPC_TIMEOUT), + 1, + ) + .await; + + let response = match result { + Ok(response) + if response.serialize_part.error_code == OK + && response.serialize_part.items.len() == current.len() => + { + response.serialize_part.items + } + Ok(response) => { + tracing::warn!( + "tier1 write-back owner response rejected: owner={} requested={} returned={} code={} error={}", + source_node_id, + current.len(), + response.serialize_part.items.len(), + response.serialize_part.error_code, + response.serialize_part.error_json + ); + view.master_kv_router().record_tier1_writeback_failed( + &source_node_id, + u64::try_from(current.len()).unwrap_or(u64::MAX), + ); + for request in current { + view.master_kv_router() + .finish_tier1_writeback_request(request); + } + return; + } + Err(err) => { + tracing::warn!( + "tier1 write-back owner RPC failed: owner={} requested={} err={:?}", + source_node_id, + current.len(), + err + ); + view.master_kv_router().record_tier1_writeback_failed( + &source_node_id, + u64::try_from(current.len()).unwrap_or(u64::MAX), + ); + for request in current { + view.master_kv_router() + .finish_tier1_writeback_request(request); + } + return; + } + }; + + let requested = current.len(); + let mut accepted = 0usize; + for (request, item) in current.into_iter().zip(response.into_iter()) { + let identity_matches = request.key == item.key && request.desc.put_id == item.put_id; + if identity_matches && item.accepted { + accepted += 1; + continue; + } + view.master_kv_router() + .record_tier1_writeback_failed(&source_node_id, 1); + if !identity_matches { + tracing::warn!( + "tier1 write-back owner response identity mismatch: owner={} request_key={} request_put_id=({},{}) response_key={} response_put_id=({},{})", + source_node_id, + request.key, + request.desc.put_id.0, + request.desc.put_id.1, + item.key, + item.put_id.0, + item.put_id.1 + ); + } + view.master_kv_router() + .finish_tier1_writeback_request(request); + } + view.master_kv_router() + .record_tier1_writeback_owner_accepted( + &source_node_id, + u64::try_from(accepted).unwrap_or(u64::MAX), + ); + tracing::debug!( + "tier1 write-back owner batch dispatched: owner={} requested={} accepted={}", + source_node_id, + requested, + accepted + ); +} + +pub(crate) fn spawn_tier1_writeback_actor( + view: MasterKvRouterView, + mut rx: tokio::sync::ampsc::Receiver, +) { + let view_task = view.clone(); + let _ = view.spawn("tier1_writeback_actor", async move { + let mut shutdown_waiter = view_task.register_shutdown_waiter(); + loop { + let first = tokio::select! { + _ = shutdown_waiter.wait() => break, + request = rx.recv() => { + let Some(request) = request else { break; }; + request + } + }; + let mut batch = Vec::with_capacity(TIER1_WRITEBACK_MAX_BATCH); + batch.push(first); + let mut merge_window = Box::pin(tokio::time::sleep(TIER1_WRITEBACK_MERGE_WINDOW)); + while batch.len() < TIER1_WRITEBACK_MAX_BATCH { + tokio::select! { + _ = &mut merge_window => break, + request = rx.recv() => { + let Some(request) = request else { break; }; + batch.push(request); + } + } + } + + let mut groups: HashMap> = HashMap::new(); + for request in batch { + groups + .entry(request.source_node_id.clone()) + .or_default() + .push(request); + } + for (source_node_id, requests) in groups { + dispatch_owner_batch(&view_task, source_node_id, requests).await; + } + } + }); +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::p2p::msg_pack::validate_explicit_rpc_timeout; + + #[test] + fn tier1_writeback_timeout_satisfies_rpc_contract() { + validate_explicit_rpc_timeout(Some(TIER1_WRITEBACK_RPC_TIMEOUT)).unwrap(); + } + + #[test] + fn inclusive_hot_tier_does_not_reduce_resident_capacity() { + let build = |capacity| { + moka::sync::SegmentedCache::builder(1) + .max_capacity(capacity) + .weigher(Box::new(|_key: &String, weight: &u32| *weight)) + .build() + }; + let resident = build(100); + let tier1 = build(60); + + for key in ["a", "b", "c"] { + resident.insert(key.to_string(), 30); + tier1.insert(key.to_string(), 30); + } + resident.run_pending_tasks(); + tier1.run_pending_tasks(); + + assert_eq!(resident.policy().max_capacity(), Some(100)); + assert_eq!(resident.weighted_size(), 90); + assert_eq!(tier1.policy().max_capacity(), Some(60)); + assert!(tier1.weighted_size() <= 60); + assert!(resident.entry_count() > tier1.entry_count()); + } +} diff --git a/fluxon_rs/fluxon_kv/src/memholder/memholder_test.rs b/fluxon_rs/fluxon_kv/src/memholder/memholder_test.rs index d4a6549..eee9dc0 100644 --- a/fluxon_rs/fluxon_kv/src/memholder/memholder_test.rs +++ b/fluxon_rs/fluxon_kv/src/memholder/memholder_test.rs @@ -59,6 +59,8 @@ fn new_master_config( pprof_duration_seconds: None, master_ui: None, replica_task_placement: ReplicaTaskPlacementConfig::default(), + replica_cache_capacity_ratio: crate::config::DEFAULT_REPLICA_CACHE_CAPACITY_RATIO, + replica_writeback_tier1_capacity_ratio: None, test_spec_config: TestSpecConfig::default(), } } @@ -89,6 +91,7 @@ fn new_client_config_with_size( rdma_device_names: None, }, pprof_duration_seconds: None, + replica_writeback_hot_capacity_ratio: None, redis_compat_listen_addr: None, fluxonkv_spec: FluxonKvSpec { etcd_addresses: vec![etcd.to_string()], @@ -124,6 +127,7 @@ fn new_zero_contribution_client_config( rdma_device_names: None, }, pprof_duration_seconds: None, + replica_writeback_hot_capacity_ratio: None, redis_compat_listen_addr: None, fluxonkv_spec: FluxonKvSpec { etcd_addresses: Vec::new(), @@ -242,6 +246,7 @@ pub mod test_memholder { new_master_config, new_zero_contribution_client_config, read_etcd, unique_cluster_name, wait_node_allocators, wait_weak_drop, }; + use crate::memholder::{MemholderManagerTrait, NodeHolderKey}; use crate::{ConfigArg, run_client, run_master}; use std::time::{Duration, Instant}; use tokio::time::sleep; @@ -588,10 +593,16 @@ pub mod test_memholder { .unwrap() .unwrap(); let ext_hold_holder_id = eh1.holder_id; - // Note: master's get_holding is keyed by the requesting node of the inner owner get - // for external GET, the owner performs an inner get, so the node is the owner + let ext_hold_owner_holder_id = owner_api + .inner() + .external_get_holding + .inner_map() + .get(&NodeHolderKey::new(external_id.clone(), ext_hold_holder_id)) + .expect("capture ext_hold owner holding") + .memory_info + .holder_id; let ext_hold_weak = - capture_master_holding_allocation(&master_view, &owner_id, ext_hold_holder_id) + capture_master_holding_allocation(&master_view, &owner_id, ext_hold_owner_holder_id) .expect("capture ext_hold weak"); drop(eh2); @@ -608,9 +619,19 @@ pub mod test_memholder { .unwrap() .unwrap(); let ext_release_holder_id = er1.holder_id; - // Similar rationale as above: use owner_id when capturing master's holding entry + let ext_release_owner_holder_id = owner_api + .inner() + .external_get_holding + .inner_map() + .get(&NodeHolderKey::new( + external_id.clone(), + ext_release_holder_id, + )) + .expect("capture ext_release owner holding") + .memory_info + .holder_id; let ext_release_weak = - capture_master_holding_allocation(&master_view, &owner_id, ext_release_holder_id) + capture_master_holding_allocation(&master_view, &owner_id, ext_release_owner_holder_id) .expect("capture ext_release weak"); drop(er1); drop(er2); // drop all for release key diff --git a/fluxon_rs/fluxon_kv/src/memholder/mod.rs b/fluxon_rs/fluxon_kv/src/memholder/mod.rs index 37f2d81..0cd6a6f 100755 --- a/fluxon_rs/fluxon_kv/src/memholder/mod.rs +++ b/fluxon_rs/fluxon_kv/src/memholder/mod.rs @@ -26,6 +26,7 @@ use bitcode::{Decode, Encode}; #[derive(Clone, Debug)] pub enum MemoryInfoDropAction { + None, OwnerDeleteAck, ReleaseLocalReserveResidentSlot { slot_size: u64, @@ -231,7 +232,22 @@ impl MemoryInfo { grant_id, slot_index, } => Some((slot_size, grant_id, slot_index)), - MemoryInfoDropAction::OwnerDeleteAck => None, + MemoryInfoDropAction::None | MemoryInfoDropAction::OwnerDeleteAck => None, + } + } + + pub(crate) fn take_local_reserve_resident_slot_ref(&mut self) -> Option<(u64, u64, u32)> { + let action = std::mem::replace(&mut self.drop_action, MemoryInfoDropAction::None); + match action { + MemoryInfoDropAction::ReleaseLocalReserveResidentSlot { + slot_size, + grant_id, + slot_index, + } => Some((slot_size, grant_id, slot_index)), + other => { + self.drop_action = other; + None + } } } } @@ -240,6 +256,7 @@ impl MemoryInfo { impl Drop for MemoryInfo { fn drop(&mut self) { match &self.drop_action { + MemoryInfoDropAction::None => {} MemoryInfoDropAction::OwnerDeleteAck => { let ctx = OwnerDeleteAckCtx { view: self.view.clone(), diff --git a/fluxon_rs/fluxon_kv/src/p2p/msg_pack.rs b/fluxon_rs/fluxon_kv/src/p2p/msg_pack.rs index 6f774ca..a057609 100644 --- a/fluxon_rs/fluxon_kv/src/p2p/msg_pack.rs +++ b/fluxon_rs/fluxon_kv/src/p2p/msg_pack.rs @@ -1,6 +1,7 @@ pub use fluxon_commu::p2p::rpc::{ - MIN_EXPLICIT_RPC_TIMEOUT_SECS, MsgPack, MsgPackSerializePart, RPCCaller, RPCHandler, RPCReq, - RPCResponsor, Responser, RpcCallObserveTrace, RpcCallObservedOutput, call_rpc, - call_rpc_observed, + MIN_EXPLICIT_RPC_TIMEOUT_MS, MIN_EXPLICIT_RPC_TIMEOUT_SECS, MsgPack, MsgPackSerializePart, + RPCCaller, RPCHandler, RPCReq, RPCResponsor, Responser, RpcCallObserveTrace, + RpcCallObservedOutput, call_rpc, call_rpc_observed, validate_explicit_rpc_timeout, + validate_explicit_rpc_timeout_ms, }; pub use fluxon_commu::p2p::{MsgId, MsgPackHeadMeta, MsgPackRelay, TaskId, WireMessageBody}; diff --git a/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/msg_and_error.rs b/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/msg_and_error.rs index 75fe736..d771141 100644 --- a/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/msg_and_error.rs +++ b/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/msg_and_error.rs @@ -71,6 +71,12 @@ pub enum MsgId { BatchPreparePutKeysResp = 3056, BatchReleasePutKeyReservationsReq = 3057, BatchReleasePutKeyReservationsResp = 3058, + BatchOwnerReclaimReq = 3059, + BatchOwnerReclaimResp = 3060, + BatchEnqueueReplicaTaskReq = 3061, + BatchEnqueueReplicaTaskResp = 3062, + GroupedBatchPutDoneReq = 3063, + GroupedBatchPutDoneResp = 3064, ExternalGetReq = 4001, ExternalGetResp = 4002, ExternalPutStartReq = 4003, diff --git a/fluxon_rs/fluxon_kv/src/user_api/rpc.rs b/fluxon_rs/fluxon_kv/src/user_api/rpc.rs index eff064f..dfbda39 100644 --- a/fluxon_rs/fluxon_kv/src/user_api/rpc.rs +++ b/fluxon_rs/fluxon_kv/src/user_api/rpc.rs @@ -44,16 +44,7 @@ pub trait UserRpcServer: Send + Sync { pub type UserRpcFlatDictFuture = Pin> + Send + 'static>>; pub(crate) fn validate_timeout_ms(timeout_ms: u64) -> KvResult<()> { - if timeout_ms < user_rpc::USER_RPC_MIN_TIMEOUT_MS { - return Err(KvError::Api(ApiError::InvalidArgument { - detail: format!( - "timeout_ms must be >= {} (got {})", - user_rpc::USER_RPC_MIN_TIMEOUT_MS, - timeout_ms - ), - })); - } - Ok(()) + user_rpc::validate_timeout_ms(timeout_ms) } pub(crate) struct FluxonUserRpcImpl { diff --git a/fluxon_rs/fluxon_kv/src/user_rpc.rs b/fluxon_rs/fluxon_kv/src/user_rpc.rs index 7bff55b..e9587ac 100644 --- a/fluxon_rs/fluxon_kv/src/user_rpc.rs +++ b/fluxon_rs/fluxon_kv/src/user_rpc.rs @@ -2,10 +2,10 @@ use std::time::Duration; use std::time::Instant; use fluxon_commu::p2p::rpc::{ - USER_RPC_OBSERVE_TRACE_RAW_BYTES_INDEX, USER_RPC_OWNER1_OBSERVE_TRACE_RAW_BYTES_INDEX, - UserRpcObserveTrace, UserRpcOwner1ObserveTrace, UserRpcTransportPathKind, - current_cross_process_monotonic_us, decode_user_rpc_observe_trace, - decode_user_rpc_owner1_observe_trace, + MIN_EXPLICIT_RPC_TIMEOUT_MS, USER_RPC_OBSERVE_TRACE_RAW_BYTES_INDEX, + USER_RPC_OWNER1_OBSERVE_TRACE_RAW_BYTES_INDEX, UserRpcObserveTrace, UserRpcOwner1ObserveTrace, + UserRpcTransportPathKind, current_cross_process_monotonic_us, decode_user_rpc_observe_trace, + decode_user_rpc_owner1_observe_trace, validate_explicit_rpc_timeout_ms, }; use prost::bytes::Bytes; @@ -15,7 +15,34 @@ use crate::p2p::p2p_module::UserRpcReq; use crate::rpcresp_kvresult_convert; use crate::rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, KvResult}; -pub const USER_RPC_MIN_TIMEOUT_MS: u64 = 10_000; +pub const USER_RPC_MIN_TIMEOUT_MS: u64 = MIN_EXPLICIT_RPC_TIMEOUT_MS; + +pub fn validate_timeout_ms(timeout_ms: u64) -> KvResult<()> { + validate_explicit_rpc_timeout_ms(timeout_ms).map_err(KvError::from) +} + +#[cfg(test)] +mod timeout_validation_tests { + use super::*; + use fluxon_commu::p2p::P2pError; + + #[test] + fn invalid_user_rpc_timeout_preserves_typed_p2p_error() { + let timeout_ms = USER_RPC_MIN_TIMEOUT_MS - 1; + let err = validate_timeout_ms(timeout_ms).unwrap_err(); + match err { + KvError::P2p(P2pError::InvalidRpcTimeout { + timeout_ms: actual_timeout_ms, + min_timeout_ms, + .. + }) => { + assert_eq!(actual_timeout_ms, timeout_ms); + assert_eq!(min_timeout_ms, USER_RPC_MIN_TIMEOUT_MS); + } + other => panic!("expected typed InvalidRpcTimeout, got {other:?}"), + } + } +} #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] pub enum UserRpcOwnerPathKind { @@ -140,14 +167,7 @@ pub async fn user_rpc_call_observed( payload: Vec, timeout_ms: u64, ) -> KvResult { - if timeout_ms < USER_RPC_MIN_TIMEOUT_MS { - return Err(KvError::Api(ApiError::InvalidArgument { - detail: format!( - "timeout_ms must be >= {} (got {})", - USER_RPC_MIN_TIMEOUT_MS, timeout_ms - ), - })); - } + validate_timeout_ms(timeout_ms)?; let path_for_error = path.clone(); let req = MsgPack { diff --git a/fluxon_rs/fluxon_pyo3/src/error.rs b/fluxon_rs/fluxon_pyo3/src/error.rs index 06246dc..3848124 100644 --- a/fluxon_rs/fluxon_pyo3/src/error.rs +++ b/fluxon_rs/fluxon_pyo3/src/error.rs @@ -379,7 +379,8 @@ pub(crate) fn py_error_from_kv_error( prefix: &str, ) -> PyObject { use fluxon_kv::rpcresp_kvresult_convert::msg_and_error::{ - ApiError as CoreApiError, KvError, LeaseMgrError, TransferEngineError, + ApiError as CoreApiError, KvError, LeaseMgrError, P2pError as CoreP2pError, + TransferEngineError, }; let msg = format!("{}: {}", prefix, e); match e { @@ -412,6 +413,9 @@ pub(crate) fn py_error_from_kv_error( KvError::Api(CoreApiError::InvalidArgument { detail }) => { new_invalid_argument_error(py, &format!("{}: Invalid argument: {}", prefix, detail)) } + KvError::P2p(CoreP2pError::InvalidRpcTimeout { .. }) => { + new_invalid_argument_error(py, &msg) + } KvError::Api(CoreApiError::FileWriteError { path, offset, diff --git a/fluxon_rs/fluxon_pyo3/src/lib.rs b/fluxon_rs/fluxon_pyo3/src/lib.rs index 1b89d76..693e873 100644 --- a/fluxon_rs/fluxon_pyo3/src/lib.rs +++ b/fluxon_rs/fluxon_pyo3/src/lib.rs @@ -29,7 +29,10 @@ use fluxon_kv::cluster_manager::ClusterManagerViewTrait; use fluxon_kv::cluster_manager::app_logic_ext::ClusterManagerAppLogicExt; use fluxon_kv::config::{ClientConfigYaml, MasterConfigYaml}; use fluxon_kv::external_client_api::ExternalClientApiViewTrait; -use fluxon_kv::master_kv_router::msg_pack::{BatchPreparePutKeyItemReq, PutDoneCommittedSlot}; +use fluxon_kv::master_kv_router::msg_pack::{ + BatchPreparePutKeyItemReq, PutDoneCommittedSlot, ReserveLocalGrantOutcome, + build_put_atomic_group_assignments, +}; use fluxon_kv::master_lease_manager::msg_pack::{AllocateClientLeaseReq, ClientLeaseKeepaliveReq}; use fluxon_kv::memholder::kvclient_encode::{BorrowedFlatKvValueRange, flat_kv_decode_borrowed}; use fluxon_kv::memholder::{ @@ -2078,6 +2081,25 @@ struct FluxonGetViewsPlan { _holders: Vec, } +fn defer_drop_to_runtime(runtime: Option<&Runtime>, value: T) +where + T: Send + 'static, +{ + if let Some(runtime) = runtime { + // Dropping a read plan can release hundreds of ExternalMemHolder + // instances. Each holder schedules its delete ACK, so doing the full + // drop on the Python scheduler thread adds milliseconds to every + // restore completion. The CUDA consumer has already finished before + // release_views is called; removing the plan from the registry makes + // the pointer invalid immediately, while the actual holder release can + // safely run on Tokio's blocking pool. + let _join = runtime.spawn_blocking(move || drop(value)); + } else { + // A post-close caller has no runtime on which to defer cleanup. + drop(value); + } +} + enum StagedGetViewHolder { Owner { _holder: Arc }, External { _holder: Arc }, @@ -2106,6 +2128,8 @@ struct StagedOwnerPutPlanData { value_len: u64, key_reservation_ids: Vec, slot_lease: OwnerLocalReserveSlotLease, + make_replica_task_mask: Vec, + atomic_group_lens: Vec, } #[derive(Clone)] @@ -3086,6 +3110,105 @@ pub struct KvClient { locality_counters: Arc, } +fn build_put_optional_args( + lease_id: Option, + reject_if_inflight_same_key: bool, + reject_if_exist_same_key: bool, + write_through: bool, + make_replica_task: bool, +) -> fluxon_kv::client_kv_api::PutOptionalArgs { + let mut opts = fluxon_kv::client_kv_api::PutOptionalArgs::new(); + if let Some(id) = lease_id { + opts.0 + .push(fluxon_kv::client_kv_api::PutOptionalArg::LeaseId(id)); + } + if reject_if_inflight_same_key { + opts.0 + .push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfInflightSameKey); + } + if reject_if_exist_same_key { + opts.0 + .push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfExistSameKey); + } + if write_through || !make_replica_task { + opts.0 + .push(fluxon_kv::client_kv_api::PutOptionalArg::SkipMakeReplicaTask); + } + opts +} + +fn resolve_make_replica_task_mask( + key_count: usize, + write_through: bool, + make_replica_task: bool, + requested_mask: Option>, + atomic_group_lens: &[usize], +) -> Result, String> { + let requested_mask = match requested_mask { + Some(mask) => { + if mask.len() != key_count { + return Err(format!( + "make_replica_task_mask length must match keys length; keys={} mask={}", + key_count, + mask.len() + )); + } + mask + } + None => vec![true; key_count], + }; + let mut offset = 0usize; + for (group_index, group_len) in atomic_group_lens.iter().copied().enumerate() { + let end = offset + group_len; + let group_mask = &requested_mask[offset..end]; + if group_mask[1..].iter().any(|item| *item != group_mask[0]) { + return Err(format!( + "make_replica_task_mask must be uniform within each atomic group; group_index={} offset={} len={}", + group_index, offset, group_len + )); + } + offset = end; + } + let enabled = !write_through && make_replica_task; + Ok(requested_mask + .into_iter() + .map(|requested| enabled && requested) + .collect()) +} + +fn normalize_put_atomic_group_lens( + key_count: usize, + requested_group_lens: Option>, +) -> Result, String> { + let Some(group_lens) = requested_group_lens else { + return Ok(vec![1; key_count]); + }; + if group_lens.is_empty() { + return Err("atomic_group_lens must be non-empty when provided".to_string()); + } + if let Some((index, _)) = group_lens + .iter() + .enumerate() + .find(|(_, length)| **length == 0) + { + return Err(format!( + "atomic_group_lens entries must be > 0; index={} got=0", + index + )); + } + let group_sum = group_lens + .iter() + .try_fold(0usize, |sum, length| sum.checked_add(*length)) + .ok_or_else(|| "atomic_group_lens sum overflowed usize".to_string())?; + if group_sum != key_count { + return Err(format!( + "atomic_group_lens must sum to keys length; sum={} keys={}", + group_sum, key_count + )); + } + Ok(group_lens) +} + #[pymethods] impl KvClient { /// Create a new KV client @@ -3358,7 +3481,7 @@ impl KvClient { .client_kv_api_view() .client_kv_api() .inner() - .reserve_local_grant() + .reserve_local_grant(0, 0, false) .await }) }) { @@ -3371,9 +3494,22 @@ impl KvClient { } }; match reserve_resp { - Ok(resp) => ApiResult::new_success( - (resp.grant_id, resp.addr, resp.base_addr, resp.len).into_py(py), - ), + Ok(ReserveLocalGrantOutcome::Granted { + grant_id, + node_id: _, + addr, + base_addr, + len, + }) => ApiResult::new_success((grant_id, addr, base_addr, len).into_py(py)), + Ok(ReserveLocalGrantOutcome::Reclaimed { .. }) => { + ApiResult::new_error(new_general_error( + py, + "raw reserve_local_grant request unexpectedly reclaimed class slots", + )) + } + Ok(ReserveLocalGrantOutcome::None) => { + unreachable!("reserve_local_grant filters empty successful outcomes") + } Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( py, &err, @@ -3446,13 +3582,17 @@ impl KvClient { release_local_grant_blocking_inner(self, grant_id, py).into_py_object(py) } - #[pyo3(signature = (keys, value_len, reject_if_inflight_same_key=false, reject_if_exist_same_key=false))] + #[pyo3(signature = (keys, value_len, reject_if_inflight_same_key=false, reject_if_exist_same_key=false, write_through=true, make_replica_task=true, make_replica_task_mask=None, atomic_group_lens=None))] fn local_fast_put_start( &self, keys: Vec, value_len: u64, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, + write_through: bool, + make_replica_task: bool, + make_replica_task_mask: Option>, + atomic_group_lens: Option>, py: Python, ) -> PyObject { fn local_fast_put_start_inner( @@ -3461,6 +3601,10 @@ impl KvClient { value_len: u64, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, + write_through: bool, + make_replica_task: bool, + make_replica_task_mask: Option>, + atomic_group_lens: Option>, py: Python, ) -> ApiResult { if keys.is_empty() { @@ -3481,6 +3625,25 @@ impl KvClient { "local_fast_put_start value_len exceeds u32 limit", )); } + let atomic_group_lens = + match normalize_put_atomic_group_lens(keys.len(), atomic_group_lens) { + Ok(group_lens) => group_lens, + Err(detail) => { + return ApiResult::new_error(new_invalid_argument_error(py, &detail)); + } + }; + let make_replica_task_mask = match resolve_make_replica_task_mask( + keys.len(), + write_through, + make_replica_task, + make_replica_task_mask, + &atomic_group_lens, + ) { + Ok(mask) => mask, + Err(detail) => { + return ApiResult::new_error(new_invalid_argument_error(py, &detail)); + } + }; let framework = match require_kv_framework_api(client, py) { Ok(v) => v, Err(e) => return ApiResult::new_error(e), @@ -3497,6 +3660,8 @@ impl KvClient { if framework.is_external_mode() { let framework_for_start = framework.clone(); let keys_for_req = keys.clone(); + let make_replica_task_mask_for_req = make_replica_task_mask.clone(); + let atomic_group_lens_for_req = atomic_group_lens.clone(); let external_start_result = match py.allow_threads(|| { runtime.run_async_from_sync(async move { let external_api_view = framework_for_start.external_client_api_view(); @@ -3508,15 +3673,17 @@ impl KvClient { .external_batch_put_start_rpc(ExternalBatchPutStartReq { items: keys_for_req .iter() - .map(|key| ExternalBatchPutStartItemReq { + .zip(make_replica_task_mask_for_req.iter()) + .map(|(key, make_replica_task)| ExternalBatchPutStartItemReq { key: key.clone(), len: value_len, reject_if_inflight_same_key, reject_if_exist_same_key, - make_replica_task: true, + make_replica_task: *make_replica_task, preferred_sub_cluster: None, }) .collect(), + atomic_group_lens: Some(atomic_group_lens_for_req), started_time, }) .await?; @@ -3681,6 +3848,13 @@ impl KvClient { return ApiResult::new_success((plan_ptr as u64).into_py(py)); } + if write_through { + return ApiResult::new_error(new_invalid_argument_error( + py, + "local_fast_put_start write_through=true requires external mode", + )); + } + let key_count = keys.len(); let framework_for_start = framework.clone(); let prepare_items = keys @@ -3772,6 +3946,8 @@ impl KvClient { value_len, key_reservation_ids, slot_lease, + make_replica_task_mask, + atomic_group_lens, }, ))), }); @@ -3790,6 +3966,10 @@ impl KvClient { value_len, reject_if_inflight_same_key, reject_if_exist_same_key, + write_through, + make_replica_task, + make_replica_task_mask, + atomic_group_lens, py, ) .into_py_object(py) @@ -3931,12 +4111,15 @@ impl KvClient { let inner = client_kv_api_view.client_kv_api().inner(); let slot_refs = owner_data.slot_lease.slots.clone(); let slot_size = owner_data.slot_lease.slot_size; - if slot_refs.len() != owner_data.keys.len() { + if slot_refs.len() != owner_data.keys.len() + || owner_data.make_replica_task_mask.len() != owner_data.keys.len() + { let err = CoreKvError::Api(CoreApiError::Unknown { detail: format!( - "local_fast_put_commit slot/key length mismatch: keys={} slots={}", + "local_fast_put_commit staged length mismatch: keys={} slots={} replica_mask={}", owner_data.keys.len(), - slot_refs.len() + slot_refs.len(), + owner_data.make_replica_task_mask.len() ), }); let _ = release_staged_put_resources( @@ -3971,7 +4154,44 @@ impl KvClient { }; let mut publish_items = Vec::with_capacity(owner_data.keys.len()); let mut ret_codes = Vec::with_capacity(owner_data.keys.len()); - for (key, slot_ref) in owner_data.keys.iter().zip(slot_refs.iter()) { + let put_ids = owner_data + .keys + .iter() + .map(|_| inner.next_owner_local_first_put_id()) + .collect::>(); + let keys_and_put_ids = owner_data + .keys + .iter() + .cloned() + .zip(put_ids.iter().copied()) + .collect::>(); + let atomic_groups = match build_put_atomic_group_assignments( + &keys_and_put_ids, + &owner_data.atomic_group_lens, + ) { + Ok(groups) => groups, + Err(detail) => { + let err = + CoreKvError::Api(CoreApiError::InvalidArgument { detail }); + let _ = release_staged_put_resources( + inner, + owner_data.key_reservation_ids, + owner_data.slot_lease, + ) + .await; + return ApiResult::new_success(vec![ + kv_error_to_ret_code(&err); + owner_data.keys.len() + ]); + } + }; + for (idx, ((key, slot_ref), make_replica_task)) in owner_data + .keys + .iter() + .zip(slot_refs.iter()) + .zip(owner_data.make_replica_task_mask.iter()) + .enumerate() + { let memory_info = inner .build_local_reserve_resident_memory_info( key, @@ -3986,12 +4206,13 @@ impl KvClient { key, memory_info.clone(), ); - let put_id = inner.next_owner_local_first_put_id(); + let put_id = put_ids[idx]; let promote = inner .promote_precommit_local_reserve_resident_slot_if_same( key, put_id, memory_info.clone(), + atomic_groups[idx].as_ref(), ); match promote { Ok(()) => { @@ -4009,8 +4230,9 @@ impl KvClient { base_addr: slot_ref.base_addr, len: owner_data.value_len, }, - make_replica_task: true, + make_replica_task: *make_replica_task, preferred_sub_cluster: None, + atomic_group: atomic_groups[idx].clone(), }); ret_codes.push(0); } @@ -4292,7 +4514,8 @@ impl KvClient { guard.remove(&plan_ptr_usize) }; match removed { - Some(FluxonPlanRegistryEntry::Get(_plan)) => { + Some(FluxonPlanRegistryEntry::Get(plan)) => { + defer_drop_to_runtime(client.runtime.as_ref(), plan); ApiResult::new_success(0i32.into_py(py)) } Some(FluxonPlanRegistryEntry::Put(_)) => ApiResult::new_error( @@ -4692,7 +4915,7 @@ impl KvClient { /// on the caller to keep the pointed-to memory alive until the async call completes. /// /// The backend encoding/copy runs on the Rust runtime without holding the Python GIL. - #[pyo3(signature = (key, ptrs, lease_id=None, reject_if_inflight_same_key=false, reject_if_exist_same_key=false, callback=None))] + #[pyo3(signature = (key, ptrs, lease_id=None, reject_if_inflight_same_key=false, reject_if_exist_same_key=false, callback=None, write_through=true, make_replica_task=true))] fn put( &self, key: &str, @@ -4701,6 +4924,8 @@ impl KvClient { reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, callback: Option, + write_through: bool, + make_replica_task: bool, py: Python, ) -> PyObject { fn put_inner( @@ -4711,6 +4936,8 @@ impl KvClient { reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, callback: Option, + write_through: bool, + make_replica_task: bool, py: Python, ) -> ApiResult { if ptrs.len() > (u32::MAX as usize) { @@ -4730,19 +4957,13 @@ impl KvClient { )); } }; - let put_opts = { - let mut o = fluxon_kv::client_kv_api::PutOptionalArgs::new(); - if let Some(id) = lease_id { - o.0.push(fluxon_kv::client_kv_api::PutOptionalArg::LeaseId(id)); - } - if reject_if_inflight_same_key { - o.0.push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfInflightSameKey); - } - if reject_if_exist_same_key { - o.0.push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfExistSameKey); - } - o - }; + let put_opts = build_put_optional_args( + lease_id, + reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, + make_replica_task, + ); let future = async move { let result = unsafe { framework.kv_put_ptrs(&key, ptrs, put_opts).await }; @@ -4802,13 +5023,15 @@ impl KvClient { reject_if_inflight_same_key, reject_if_exist_same_key, callback, + write_through, + make_replica_task, py, ) .into_py_object(py) } /// Put a key-value pair and wait for completion before returning. - #[pyo3(signature = (key, ptrs, lease_id=None, reject_if_inflight_same_key=false, reject_if_exist_same_key=false))] + #[pyo3(signature = (key, ptrs, lease_id=None, reject_if_inflight_same_key=false, reject_if_exist_same_key=false, write_through=true, make_replica_task=true))] fn put_blocking( &self, key: &str, @@ -4816,6 +5039,8 @@ impl KvClient { lease_id: Option, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, + write_through: bool, + make_replica_task: bool, py: Python, ) -> PyObject { fn put_blocking_inner( @@ -4825,6 +5050,8 @@ impl KvClient { lease_id: Option, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, + write_through: bool, + make_replica_task: bool, py: Python, ) -> ApiResult { if ptrs.len() > (u32::MAX as usize) { @@ -4845,22 +5072,13 @@ impl KvClient { } }; let framework = borrow_stable_owner(&framework); - let mut put_opts = fluxon_kv::client_kv_api::PutOptionalArgs::new(); - if let Some(id) = lease_id { - put_opts - .0 - .push(fluxon_kv::client_kv_api::PutOptionalArg::LeaseId(id)); - } - if reject_if_inflight_same_key { - put_opts - .0 - .push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfInflightSameKey); - } - if reject_if_exist_same_key { - put_opts - .0 - .push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfExistSameKey); - } + let put_opts = build_put_optional_args( + lease_id, + reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, + make_replica_task, + ); let result = match py.allow_threads(|| { runtime.run_async_from_sync(async { unsafe { framework.kv_put_ptrs(&key, ptrs, put_opts).await } @@ -4909,6 +5127,8 @@ impl KvClient { lease_id, reject_if_inflight_same_key, reject_if_exist_same_key, + write_through, + make_replica_task, py, ) .into_py_object(py) @@ -4917,7 +5137,7 @@ impl KvClient { /// Put a batch of key-value pairs and wait for completion before returning. /// /// Each item uses the same flatdict encoding contract as `put_blocking()`. - #[pyo3(signature = (keys, ptrs_groups, lease_id=None, reject_if_inflight_same_key=false, reject_if_exist_same_key=false, concurrency=None))] + #[pyo3(signature = (keys, ptrs_groups, lease_id=None, reject_if_inflight_same_key=false, reject_if_exist_same_key=false, concurrency=None, write_through=true, make_replica_task=true))] fn batch_put_blocking( &self, keys: Vec, @@ -4926,6 +5146,8 @@ impl KvClient { reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, concurrency: Option, + write_through: bool, + make_replica_task: bool, py: Python, ) -> PyObject { fn batch_put_blocking_inner( @@ -4936,6 +5158,8 @@ impl KvClient { reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, concurrency: Option, + write_through: bool, + make_replica_task: bool, py: Python, ) -> ApiResult { if keys.len() != ptrs_groups.len() { @@ -4974,22 +5198,13 @@ impl KvClient { let framework = borrow_stable_owner(&framework); let keys_for_results = keys; - let mut put_opts = fluxon_kv::client_kv_api::PutOptionalArgs::new(); - if let Some(id) = lease_id { - put_opts - .0 - .push(fluxon_kv::client_kv_api::PutOptionalArg::LeaseId(id)); - } - if reject_if_inflight_same_key { - put_opts - .0 - .push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfInflightSameKey); - } - if reject_if_exist_same_key { - put_opts - .0 - .push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfExistSameKey); - } + let put_opts = build_put_optional_args( + lease_id, + reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, + make_replica_task, + ); if !framework.is_external_mode() { let framework_for_backend = framework.clone(); @@ -5156,6 +5371,8 @@ impl KvClient { reject_if_inflight_same_key, reject_if_exist_same_key, concurrency, + write_through, + make_replica_task, py, ) .into_py_object(py) @@ -5206,7 +5423,7 @@ impl KvClient { } /// Native blocking batch put path for payload pointers. - #[pyo3(signature = (keys, payload_ptrs, payload_sizes, lease_id=None, reject_if_inflight_same_key=false, reject_if_exist_same_key=false))] + #[pyo3(signature = (keys, payload_ptrs, payload_sizes, lease_id=None, reject_if_inflight_same_key=false, reject_if_exist_same_key=false, write_through=true, make_replica_task=true))] fn batch_put_from( &self, keys: Vec, @@ -5215,6 +5432,8 @@ impl KvClient { lease_id: Option, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, + write_through: bool, + make_replica_task: bool, py: Python, ) -> PyObject { fn batch_put_from_inner( @@ -5225,6 +5444,8 @@ impl KvClient { lease_id: Option, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, + write_through: bool, + make_replica_task: bool, py: Python, ) -> ApiResult { if keys.len() != payload_ptrs.len() || keys.len() != payload_sizes.len() { @@ -5284,22 +5505,13 @@ impl KvClient { drop(registered); let framework = borrow_stable_owner(&framework); - let mut put_opts = fluxon_kv::client_kv_api::PutOptionalArgs::new(); - if let Some(id) = lease_id { - put_opts - .0 - .push(fluxon_kv::client_kv_api::PutOptionalArg::LeaseId(id)); - } - if reject_if_inflight_same_key { - put_opts - .0 - .push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfInflightSameKey); - } - if reject_if_exist_same_key { - put_opts - .0 - .push(fluxon_kv::client_kv_api::PutOptionalArg::RejectIfExistSameKey); - } + let put_opts = build_put_optional_args( + lease_id, + reject_if_inflight_same_key, + reject_if_exist_same_key, + write_through, + make_replica_task, + ); let keys_for_backend = keys.clone(); let ptrs_groups = keys_for_backend @@ -5419,6 +5631,8 @@ impl KvClient { lease_id, reject_if_inflight_same_key, reject_if_exist_same_key, + write_through, + make_replica_task, py, ) .into_py_object(py) @@ -6359,14 +6573,11 @@ impl KvClient { timeout_ms: u64, py: Python, ) -> ApiResult { - if timeout_ms < fluxon_kv::user_rpc::USER_RPC_MIN_TIMEOUT_MS { - return ApiResult::new_error(new_invalid_argument_error( + if let Err(err) = fluxon_kv::user_rpc::validate_timeout_ms(timeout_ms) { + return ApiResult::new_error(crate::error::py_error_from_kv_error( py, - &format!( - "timeout_ms must be >= {} (got {})", - fluxon_kv::user_rpc::USER_RPC_MIN_TIMEOUT_MS, - timeout_ms - ), + &err, + "Invalid RPC timeout", )); } @@ -6482,14 +6693,13 @@ impl KvClient { timeout_ms: u64, py: Python, ) -> ApiResult { - const MIN_TIMEOUT_MS: u64 = 10_000; - if timeout_ms < MIN_TIMEOUT_MS { - return ApiResult::new_error(new_invalid_argument_error( + if let Err(err) = fluxon_kv::p2p::msg_pack::validate_explicit_rpc_timeout_ms(timeout_ms) + { + let err = CoreKvError::from(err); + return ApiResult::new_error(crate::error::py_error_from_kv_error( py, - &format!( - "timeout_ms must be >= {} (got {})", - MIN_TIMEOUT_MS, timeout_ms - ), + &err, + "Invalid RPC timeout", )); } if target_instance_key.trim().is_empty() { @@ -6981,6 +7191,10 @@ fn run_master_blocking(config: Option<&Bound<'_, PyAny>>, py: Python) -> PyObjec #[pyo3(name = "fluxon_pyo3")] fn fluxon_pyo3(m: &Bound<'_, PyModule>) -> PyResult<()> { init_dynamic_libraries()?; + m.add( + "MIN_EXPLICIT_RPC_TIMEOUT_MS", + fluxon_kv::p2p::msg_pack::MIN_EXPLICIT_RPC_TIMEOUT_MS, + )?; m.add_class::()?; m.add_class::()?; m.add_class::()?; @@ -7014,18 +7228,151 @@ fn fluxon_pyo3(m: &Bound<'_, PyModule>) -> PyResult<()> { #[cfg(test)] mod tests { use super::{ - bundled_driver_names_from_entries, configure_bundled_rdmav_driver_env, + build_put_optional_args, bundled_driver_names_from_entries, + configure_bundled_rdmav_driver_env, defer_drop_to_runtime, discover_bundled_ibverbs_driver_config, extract_fluxon_pyo3_libs_root_from_loaded_library_line, loaded_fluxon_pyo3_libs_roots, - parse_bundled_ibverbs_driver_name, sanitize_bundled_ld_library_path_entries, + normalize_put_atomic_group_lens, parse_bundled_ibverbs_driver_name, + resolve_make_replica_task_mask, sanitize_bundled_ld_library_path_entries, set_authoritative_bundled_ld_library_path, validate_single_fluxon_pyo3_libs_root, }; use std::path::{Path, PathBuf}; - use std::sync::{Mutex, OnceLock}; - use std::time::{SystemTime, UNIX_EPOCH}; + use std::sync::atomic::{AtomicUsize, Ordering}; + use std::sync::{Arc, Mutex, OnceLock}; + use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; static ENV_LOCK: OnceLock> = OnceLock::new(); + struct DropProbe(Arc); + + impl Drop for DropProbe { + fn drop(&mut self) { + self.0.fetch_add(1, Ordering::SeqCst); + } + } + + #[test] + fn defer_drop_to_runtime_eventually_drops_value() { + let runtime = tokio::runtime::Runtime::new().unwrap(); + let dropped = Arc::new(AtomicUsize::new(0)); + defer_drop_to_runtime(Some(&runtime), DropProbe(dropped.clone())); + + let deadline = Instant::now() + Duration::from_secs(2); + while dropped.load(Ordering::SeqCst) == 0 && Instant::now() < deadline { + std::thread::sleep(Duration::from_millis(1)); + } + assert_eq!(dropped.load(Ordering::SeqCst), 1); + } + + #[test] + fn defer_drop_without_runtime_is_synchronous() { + let dropped = Arc::new(AtomicUsize::new(0)); + defer_drop_to_runtime(None, DropProbe(dropped.clone())); + assert_eq!(dropped.load(Ordering::SeqCst), 1); + } + + #[test] + fn put_options_control_async_replica_task() { + let write_through = build_put_optional_args(None, false, false, true, true); + let write_back = build_put_optional_args(None, false, false, false, true); + let local_only = build_put_optional_args(None, false, false, false, false); + + assert!(!write_through.make_replica_task()); + assert!(write_back.make_replica_task()); + assert!(!local_only.make_replica_task()); + } + + #[test] + fn local_fast_put_replica_mask_broadcasts_scalar() { + assert_eq!( + resolve_make_replica_task_mask(3, false, true, None, &[1, 1, 1]).unwrap(), + vec![true, true, true] + ); + assert_eq!( + resolve_make_replica_task_mask(3, false, false, None, &[1, 1, 1]).unwrap(), + vec![false, false, false] + ); + } + + #[test] + fn local_fast_put_replica_mask_selects_items() { + assert_eq!( + resolve_make_replica_task_mask( + 4, + false, + true, + Some(vec![true, false, true, false]), + &[1, 1, 1, 1], + ) + .unwrap(), + vec![true, false, true, false] + ); + } + + #[test] + fn local_fast_put_replica_mask_respects_global_gates() { + let requested = Some(vec![true, false, true]); + assert_eq!( + resolve_make_replica_task_mask(3, true, true, requested.clone(), &[1, 1, 1]).unwrap(), + vec![false, false, false] + ); + assert_eq!( + resolve_make_replica_task_mask(3, false, false, requested, &[1, 1, 1]).unwrap(), + vec![false, false, false] + ); + } + + #[test] + fn local_fast_put_replica_mask_rejects_length_mismatch() { + let err = + resolve_make_replica_task_mask(3, false, true, Some(vec![true, false]), &[1, 1, 1]) + .unwrap_err(); + assert_eq!( + err, + "make_replica_task_mask length must match keys length; keys=3 mask=2" + ); + } + + #[test] + fn local_fast_put_atomic_groups_accept_valid_partition() { + assert_eq!( + normalize_put_atomic_group_lens(5, Some(vec![2, 3])).unwrap(), + vec![2, 3] + ); + assert_eq!( + normalize_put_atomic_group_lens(3, None).unwrap(), + vec![1, 1, 1] + ); + } + + #[test] + fn local_fast_put_atomic_groups_reject_zero_and_sum_mismatch() { + assert_eq!( + normalize_put_atomic_group_lens(3, Some(vec![1, 0, 2])).unwrap_err(), + "atomic_group_lens entries must be > 0; index=1 got=0" + ); + assert_eq!( + normalize_put_atomic_group_lens(3, Some(vec![1, 1])).unwrap_err(), + "atomic_group_lens must sum to keys length; sum=2 keys=3" + ); + } + + #[test] + fn local_fast_put_replica_mask_rejects_split_atomic_group() { + let err = resolve_make_replica_task_mask( + 5, + false, + true, + Some(vec![true, true, false, true, true]), + &[2, 3], + ) + .unwrap_err(); + assert_eq!( + err, + "make_replica_task_mask must be uniform within each atomic group; group_index=1 offset=2 len=3" + ); + } + struct EnvSnapshot { key: &'static str, value: Option, diff --git a/fluxon_rs/fluxon_util/src/log.rs b/fluxon_rs/fluxon_util/src/log.rs index 4db4ae4..b941ed5 100644 --- a/fluxon_rs/fluxon_util/src/log.rs +++ b/fluxon_rs/fluxon_util/src/log.rs @@ -226,20 +226,6 @@ fn setup_global_log_guards(file_guard: WorkerGuard, console_guard: WorkerGuard) let _ = GLOBAL_CONSOLE_LOG_GUARD.set(console_guard); } -fn workspace_targets_filter( - workspace_level: filter::LevelFilter, - non_workspace_default: filter::LevelFilter, -) -> filter::Targets { - let mut targets = filter::Targets::new().with_default(non_workspace_default); - for c in generated_crates::OUR_CRATES { - targets = targets.with_target(*c, workspace_level); - } - for c in RDMA_DEBUG_TARGETS { - targets = targets.with_target(*c, workspace_level); - } - targets -} - fn third_party_log_target_overrides( enable_iceoryx_logs: bool, default_level: filter::LevelFilter, @@ -480,11 +466,16 @@ where } if let Some(level) = crate_level { - // Use build-time generated workspace member list. - let our_crates: &[&str] = generated_crates::OUR_CRATES; + // Use build-time generated workspace members plus the explicit RDMA + // diagnostic targets. A bare level remains one canonical setting for + // console, file, and exporter layers. + let our_crates = generated_crates::OUR_CRATES + .iter() + .copied() + .chain(RDMA_DEBUG_TARGETS.iter().copied()); let mut changed = removed_bare_debug; for c in our_crates { - if !existing_targets.contains(&c.to_string()) { + if !existing_targets.contains(c) { new_parts.push(format!("{}={}", c, level)); changed = true; } @@ -516,8 +507,9 @@ where } } - // File log keeps workspace crates at DEBUG; non-workspace crates default to WARN. - // This avoids dumping verbose dependency debug logs (e.g. h2/tower) into file output. + // All sinks follow the canonical RUST_LOG/FLUXON_LOG filter. Keeping a fixed DEBUG + // file layer here makes an `info` or `error` runtime silently continue formatting + // and writing high-volume debug events. let file_path = current_daily_log_file_path(log_path, instance_key); // Keep a copy for the whole process lifetime; collectors can clone it. if let Some(prev) = GLOBAL_LOG_FILE_PATH.get() { @@ -542,18 +534,17 @@ where .map(|v| v.trim().to_ascii_lowercase()), Some(v) if !matches!(v.as_str(), "" | "0" | "false" | "no") ); - let file_filter = - workspace_targets_filter(filter::LevelFilter::DEBUG, filter::LevelFilter::WARN); + let file_filter = EnvFilter::from_default_env(); let file_layer = tracing_subscriber::fmt::layer() .with_timer(UtcSecondTimer) .with_writer(file_writer) .with_ansi(false) - .with_filter(file_filter.clone().or(third_party_log_target_overrides( + .with_filter(file_filter.or(third_party_log_target_overrides( enable_iceoryx_logs, filter::LevelFilter::WARN, ))); - // Console logging follows user config (RUST_LOG/FLUXON_LOG); file logging ignores it. + // Console logging follows the same user config as file output. let (console_writer, console_guard) = non_blocking(io::stdout()); let console_env_filter = EnvFilter::from_default_env(); let console_layer = tracing_subscriber::fmt::layer() @@ -561,9 +552,8 @@ where .with_filter(console_env_filter); // Register layers. - // `extra_layer` follows the same target filtering as file output (workspace=DEBUG, deps=WARN) - // to avoid exporting noisy dependency debug logs by default. - let extra_layer = extra_layer.with_filter(file_filter.clone().or( + // Exporters follow the same canonical user filter as local sinks. + let extra_layer = extra_layer.with_filter(EnvFilter::from_default_env().or( third_party_log_target_overrides(enable_iceoryx_logs, filter::LevelFilter::WARN), )); let _ = tracing_subscriber::registry() diff --git a/fluxon_rs/fluxon_util/src/vallocator/mod.rs b/fluxon_rs/fluxon_util/src/vallocator/mod.rs index 2f56285..14d7dfd 100644 --- a/fluxon_rs/fluxon_util/src/vallocator/mod.rs +++ b/fluxon_rs/fluxon_util/src/vallocator/mod.rs @@ -4,6 +4,7 @@ pub use frame::*; pub mod test; use parking_lot::RwLock; +use std::collections::{BTreeMap, BTreeSet}; crate::define_error_code_enum_with_from! { #[repr(i32)] @@ -42,6 +43,7 @@ impl std::fmt::Display for AllocError { impl std::error::Error for AllocError {} pub const ORDER: usize = 64; +const CONTIGUOUS_ALLOCATION_ALIGNMENT: u64 = 4096; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct AllocRegion { @@ -49,8 +51,138 @@ pub struct AllocRegion { pub size: u64, } +#[derive(Debug)] +struct ContiguousRangeAllocator { + free_by_start: BTreeMap, + free_by_size: BTreeSet<(u64, u64)>, + allocated: u64, + total: u64, +} + +impl ContiguousRangeAllocator { + fn new(total: u64) -> Self { + let mut allocator = Self { + free_by_start: BTreeMap::new(), + free_by_size: BTreeSet::new(), + allocated: 0, + total, + }; + if total != 0 { + allocator.insert_free_range(0, total); + } + allocator + } + + fn aligned_capacity(size: u64) -> Option { + size.checked_add(CONTIGUOUS_ALLOCATION_ALIGNMENT - 1) + .map(|value| value / CONTIGUOUS_ALLOCATION_ALIGNMENT * CONTIGUOUS_ALLOCATION_ALIGNMENT) + } + + fn insert_free_range(&mut self, start: u64, len: u64) { + if len == 0 { + return; + } + assert!(self.free_by_start.insert(start, len).is_none()); + assert!(self.free_by_size.insert((len, start))); + } + + fn remove_free_range(&mut self, start: u64, len: u64) { + assert_eq!(self.free_by_start.remove(&start), Some(len)); + assert!(self.free_by_size.remove(&(len, start))); + } + + fn alloc(&mut self, requested: u64) -> Option<(u64, u64)> { + let capacity = Self::aligned_capacity(requested)?; + let (range_len, range_start) = self.free_by_size.range((capacity, 0)..).next().copied()?; + self.remove_free_range(range_start, range_len); + let remaining = range_len - capacity; + if remaining != 0 { + self.insert_free_range(range_start + capacity, remaining); + } + self.allocated = self.allocated.checked_add(capacity)?; + Some((range_start, capacity)) + } + + fn free(&mut self, start: u64, capacity: u64) -> Result { + let end = start.checked_add(capacity).ok_or_else(|| AllocError { + code: AllocErrorCode::InvalidAddress, + message: format!("Allocation range overflows: start={start} capacity={capacity}"), + })?; + if capacity == 0 + || capacity % CONTIGUOUS_ALLOCATION_ALIGNMENT != 0 + || start % CONTIGUOUS_ALLOCATION_ALIGNMENT != 0 + || end > self.total + { + return Err(AllocError { + code: AllocErrorCode::InvalidAddress, + message: format!( + "Invalid aligned allocation range: start={start} capacity={capacity} total={}", + self.total + ), + }); + } + + let previous = self + .free_by_start + .range(..start) + .next_back() + .map(|(&range_start, &range_len)| (range_start, range_len)); + if previous + .is_some_and(|(range_start, range_len)| range_start.saturating_add(range_len) > start) + { + return Err(AllocError { + code: AllocErrorCode::DoubleFree, + message: format!( + "Range overlaps previous free range: start={start} capacity={capacity}" + ), + }); + } + let next = self + .free_by_start + .range(start..) + .next() + .map(|(&range_start, &range_len)| (range_start, range_len)); + if next.is_some_and(|(range_start, _)| range_start < end) { + return Err(AllocError { + code: AllocErrorCode::DoubleFree, + message: format!( + "Range overlaps next free range: start={start} capacity={capacity}" + ), + }); + } + + let mut merged_start = start; + let mut merged_len = capacity; + if let Some((previous_start, previous_len)) = previous + && previous_start + previous_len == start + { + self.remove_free_range(previous_start, previous_len); + merged_start = previous_start; + merged_len += previous_len; + } + if let Some((next_start, next_len)) = next + && end == next_start + { + self.remove_free_range(next_start, next_len); + merged_len += next_len; + } + self.insert_free_range(merged_start, merged_len); + self.allocated = self + .allocated + .checked_sub(capacity) + .ok_or_else(|| AllocError { + code: AllocErrorCode::DoubleFree, + message: format!( + "Allocated byte counter underflow: allocated={} capacity={capacity}", + self.allocated + ), + })?; + Ok(capacity) + } +} + pub struct VirtualAllocator { - inner: RwLock>, + inner: RwLock, } impl std::fmt::Debug for VirtualAllocator { @@ -65,11 +197,8 @@ impl std::fmt::Debug for VirtualAllocator { impl VirtualAllocator { pub fn new(total_size: u64) -> Result { - let mut allocator = FrameAllocator::::new(); - allocator.add_frame(0, total_size); - Ok(Self { - inner: RwLock::new(allocator), + inner: RwLock::new(ContiguousRangeAllocator::new(total_size)), }) } @@ -95,8 +224,7 @@ impl VirtualAllocator { } let mut allocator = self.inner.write(); - let (addr_opt, actual_size) = allocator.alloc(size); - if let Some(addr) = addr_opt { + if let Some((addr, actual_size)) = allocator.alloc(size) { if actual_size < size { return Err(AllocError { code: AllocErrorCode::AllocationFailed, @@ -127,7 +255,7 @@ impl VirtualAllocator { } let mut allocator = self.inner.write(); - let freed_size = allocator.dealloc(ptr, size); + let freed_size = allocator.free(ptr, size)?; if freed_size != size { return Err(AllocError { code: AllocErrorCode::DeallocationException, diff --git a/fluxon_rs/fluxon_util/src/vallocator/test.rs b/fluxon_rs/fluxon_util/src/vallocator/test.rs index 132879f..07a92b1 100644 --- a/fluxon_rs/fluxon_util/src/vallocator/test.rs +++ b/fluxon_rs/fluxon_util/src/vallocator/test.rs @@ -1,5 +1,40 @@ use crate::vallocator::VirtualAllocator; +#[test] +fn virtual_allocator_keeps_sglang_pages_exact_instead_of_power_of_two_rounding() { + const PAGE_BYTES: u64 = 4_718_592; + let allocator = VirtualAllocator::new(PAGE_BYTES * 3).unwrap(); + let first = allocator.alloc(PAGE_BYTES).unwrap(); + let second = allocator.alloc(PAGE_BYTES).unwrap(); + let third = allocator.alloc(PAGE_BYTES).unwrap(); + + assert_eq!(first.size, PAGE_BYTES); + assert_eq!(second.size, PAGE_BYTES); + assert_eq!(third.size, PAGE_BYTES); + assert_eq!(allocator.get_allocated_size(), PAGE_BYTES * 3); + assert!(allocator.alloc(PAGE_BYTES).is_err()); + + allocator.free(second.start_addr, second.size).unwrap(); + allocator.free(first.start_addr, first.size).unwrap(); + allocator.free(third.start_addr, third.size).unwrap(); + assert_eq!(allocator.get_allocated_size(), 0); + + let whole = allocator.alloc(PAGE_BYTES * 3).unwrap(); + assert_eq!(whole.start_addr, 0); + assert_eq!(whole.size, PAGE_BYTES * 3); +} + +#[test] +fn virtual_allocator_rounds_only_to_transfer_page_alignment() { + let allocator = VirtualAllocator::new(16 * 1024).unwrap(); + let region = allocator.alloc(4097).unwrap(); + assert_eq!(region.start_addr, 0); + assert_eq!(region.size, 8192); + assert_eq!(allocator.get_allocated_size(), 8192); + allocator.free(region.start_addr, region.size).unwrap(); + assert_eq!(allocator.get_allocated_size(), 0); +} + #[test] fn test_empty_frame_allocator() { let mut frame = crate::vallocator::frame::FrameAllocator::<32>::new(); diff --git a/fluxon_rs/fluxon_util/tests/log_mgmt.rs b/fluxon_rs/fluxon_util/tests/log_mgmt.rs index f459337..a458c47 100644 --- a/fluxon_rs/fluxon_util/tests/log_mgmt.rs +++ b/fluxon_rs/fluxon_util/tests/log_mgmt.rs @@ -63,8 +63,11 @@ fn kv_log_shards_roll_and_cleanup_with_test_window() { TEST_LOG_SHARD_ANCHOR_UNIX_SECONDS_ENV, (now - 2).to_string(), ); + let _rust_log_guard = EnvVarGuard::set("RUST_LOG", "info"); + let _fluxon_log_guard = EnvVarGuard::set("FLUXON_LOG", "info"); fluxon_util::init_log(log_path, instance_key); + tracing::debug!(target: "fluxon_util", "[kv-log-mgmt][debug-must-be-filtered]"); tracing::info!(target: "fluxon_util", "[kv-log-mgmt][phase=before] ts={}", now); std::thread::sleep(Duration::from_millis(300)); std::thread::sleep(Duration::from_secs(11)); @@ -107,6 +110,11 @@ fn kv_log_shards_roll_and_cleanup_with_test_window() { !shard_2_text.contains("[kv-log-mgmt][phase=before]"), "second shard should not contain the before marker" ); + assert!( + !shard_1_text.contains("[kv-log-mgmt][debug-must-be-filtered]") + && !shard_2_text.contains("[kv-log-mgmt][debug-must-be-filtered]"), + "file output must honor the canonical info filter" + ); assert_eq!(DEFAULT_DAILY_LOG_RETENTION_DAYS, 31); } From ec63dc3de0cae961058303c82892e38daacd0dae Mon Sep 17 00:00:00 2001 From: zTz01 <1773266173@qq.com> Date: Fri, 17 Jul 2026 20:41:37 +0800 Subject: [PATCH 04/10] backup --- ...00\345\214\226\345\210\206\346\236\220.md" | 469 +++ ...06\346\210\220\350\256\276\350\256\241.md" | 458 ++- ...45\345\205\245\350\247\204\345\210\222.md" | 565 +++ .../closed_sdk/lib/libfluxon_commu_core.so | Bin 15433576 -> 17060408 bytes .../fluxon_kv/src/client_kv_api/delete.rs | 17 +- .../src/client_kv_api/external_api.rs | 3028 +++++++++++----- fluxon_rs/fluxon_kv/src/client_kv_api/get.rs | 509 ++- .../client_kv_api/local_reserve_rebalance.rs | 405 ++- fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs | 2709 ++++++++++---- fluxon_rs/fluxon_kv/src/client_kv_api/put.rs | 1784 ++++++++-- .../fluxon_kv/src/client_kv_api/reclaim.rs | 175 +- .../fluxon_kv/src/master_kv_router/delete.rs | 27 +- .../fluxon_kv/src/master_kv_router/get.rs | 946 ++++- .../fluxon_kv/src/master_kv_router/mod.rs | 3138 ++++++++++------- .../src/master_kv_router/msg_pack.rs | 213 +- .../fluxon_kv/src/master_kv_router/put.rs | 1147 +++--- .../fluxon_kv/src/master_kv_router/reclaim.rs | 1701 +++++++-- .../src/master_kv_router/route_maintenance.rs | 166 +- .../src/master_lease_manager/lease.rs | 9 + .../lease_manager_test.rs | 30 + .../master_lease_manager.rs | 15 + .../fluxon_kv/src/master_seg_manager/mod.rs | 96 +- .../master_seg_manager/one_seg_allocator.rs | 9 + fluxon_rs/fluxon_kv/src/memholder/lifetime.rs | 88 +- fluxon_rs/fluxon_kv/src/memholder/mod.rs | 24 + .../rpcresp_kvresult_convert/msg_and_error.rs | 6 + fluxon_rs/fluxon_pyo3/src/lib.rs | 86 +- pegaflow | 1 + scripts/preview_doc_html.py | 547 +++ 29 files changed, 13786 insertions(+), 4582 deletions(-) create mode 100644 "fluxon_doc_cn/design/sglang_fluxon_kv_PegaFlow\345\257\271\347\205\247\344\270\216Get\350\267\257\345\276\204\347\256\200\345\214\226\345\210\206\346\236\220.md" create mode 100644 "fluxon_doc_cn/design/teststack_2_Benchmark\347\233\221\346\216\247\345\267\245\345\205\267\351\223\276\344\270\216AIPerf\346\216\245\345\205\245\350\247\204\345\210\222.md" create mode 160000 pegaflow create mode 100755 scripts/preview_doc_html.py diff --git "a/fluxon_doc_cn/design/sglang_fluxon_kv_PegaFlow\345\257\271\347\205\247\344\270\216Get\350\267\257\345\276\204\347\256\200\345\214\226\345\210\206\346\236\220.md" "b/fluxon_doc_cn/design/sglang_fluxon_kv_PegaFlow\345\257\271\347\205\247\344\270\216Get\350\267\257\345\276\204\347\256\200\345\214\226\345\210\206\346\236\220.md" new file mode 100644 index 0000000..95e9aab --- /dev/null +++ "b/fluxon_doc_cn/design/sglang_fluxon_kv_PegaFlow\345\257\271\347\205\247\344\270\216Get\350\267\257\345\276\204\347\256\200\345\214\226\345\210\206\346\236\220.md" @@ -0,0 +1,469 @@ +# Fluxon Batch Get / singleflight:PegaFlow 对照与路径简化分析 + +本文评审当前工作区新增的 owner 侧 Batch Get / per-key singleflight 路径,并与 PegaFlow 的 prefix query、prefetch、lease 和批量传输实现对照。评审范围从 `ExternalBatchGetStartReq` 进入 owner 开始,到 master `BatchGetStart`、payload transfer、`BatchGetDone` / `BatchGetRevoke` 以及 external handle 消费结束。 + +原始评审基于 2026-07-16 的 Fluxon 工作区和 PegaFlow `master` 的提交 +`939363f198a0ffded9e3f30d8af9cdd74439f16c`。2026-07-17 已按当前工作树回填实现状态; +没有把尚未执行的性能对比写成实测结论。 + +## 2026-07-17 实现回填(当前权威状态) + +| 原问题 | 当前实现 | 状态 | +| --- | --- | --- | +| exact-batch 与 per-key 两层 shared op | exact-batch phase/waiter/result cache 已删除;`ExternalGetStartEntry` 直接持请求自己的 `keys + Local/Interest items` | 已解决 | +| `decision_registered` 手工归还 | `ExternalGetKeyInterest` 在 Drop 中归还 `undecided`,prefix decision 由 guard ownership 表达 | 已解决 | +| process-wide `owner_key_control` 扫完整 batch/global states | 改为 256-shard `OwnerKeyControlTable`;local/join/leader 每个 key 独立线性化,任何同步锁均不跨 batch 或 `.await`;metrics 使用独立 Weak flight index | 已解决 | +| 规划等待 Revoke 时取消会遗留未启动 leader | `ExternalGetPlanningLeadersGuard` 在 BatchGetStart handoff 前拥有新 leader;Drop 将仍为 `Starting` 的 op 发布为 safe miss、按 Arc identity 清 marker 并唤醒 joiner | 已解决 | +| prepared slot 在 start/revoke 异常路径失去 owner | claim guard、同 operation identity Revoke retry 与 local slot release guard 已覆盖;响应不确定不猜测释放 | 已解决(仍需端到端故障注入) | +| external handle 无界遗留 | handle sweeper 已接入,超时与显式 cancel 复用 plan Drop/interest release 路径 | 已解决(仍需进程死亡测试) | +| payload 每 key 一次 transfer submission | 控制面仍批量,payload backend submission 仍需运行期计数与 benchmark 后决定是否扩展 descriptor batch API | 未解决/待测 | + +下文 §2~§4 保留为“2026-07-16 修复前快照”,用于解释为什么做上述改动;其中出现的 +“当前实现”均指该历史快照,不得覆盖本节和集成设计主文档的当前规约。 + +## 原始结论(2026-07-16 修复前) + +**per-key singleflight 的目标应当保留,当前“两层共享操作”应当收缩。** 重叠但不完全相同的 batch 确实需要按 key 选出 local、joiner 和 leader,同时继续批量执行 master RPC。当前实现又在它外面保留了 exact-batch `ExternalGetStartSharedOp`,因此一次请求同时支付 exact-batch 去重和 per-key 去重的状态、锁、通知、结果缓存与生命周期成本。完全相同的 batch 本来就会自然 join 同一组 per-key flight;第二层去重没有形成独立的正确性边界。 + +**当前首要风险是取消安全。** 常数级性能排在生命周期闭环之后。`decision_registered: bool`、`undecided`、`retained` 和 `waiter_count` 都依赖后续代码手工归还。future 在计数增加后的任一 `.await` 被取消时,没有 `Drop` guard 关闭这次 interest。静态控制流已经足以证明计数可能永久不归零,进而让 leader task、相同 batch、reclaim fence 或 exact-batch registry 一直等待。 + +**结构性 overhead 已经存在,但实际延迟幅度仍需 benchmark。** 当前路径包含多份 key 向量和结果向量复制、每个新 leader key 的独立共享对象、两层 `Mutex + Notify`、通常两个后台 task、全局 owner key fence 内的线性扫描,以及每个远端 key 一次 `transfer_data_no_copy` 调用。它们在短 value、高并发、大 batch 场景更可能可见;没有 allocator、锁等待和端到端延迟数据前,不应写成“已经造成 X% 回退”。 + +**PegaFlow 最值得学习的是所有权与生命周期的组织方式。** 它没有解决不同请求之间重叠 block 的 per-key singleflight,算法不能直接搬到 Fluxon。可借鉴的是:一次 prefix scan 直接取得 `Arc` pin、一个 ready prefix 对应一个 opaque lease、资源计数由 RAII / TTL 收口、request-level prefetch 只保留一个 task,以及数据面先汇总 descriptor 再提交。PegaFlow 当前 `QueryPrefetch` 在 probe 阶段就 pin、active prefetch 只按 `req_id` 标识、lease TTL 为 600 秒,这些都不应直接复制到 Fluxon。 + +建议按以下顺序推进: + +1. **P0,先封闭生命周期**:把 decision、waiter、prepared slot 和 handle 改成 cancellation-safe guard;为 owner handle / operation 增加有界 TTL 或 generation cleanup;补齐取消与 revoke 不确定性测试。 +2. **P1,删除 exact-batch shared-op 层**:每个 external handle 直接持有一个 `BatchPlan`,其中的 item 引用 local holder 或 per-key flight。保留当前公开的 `get_start -> get_transfer | cancel` 契约。 +3. **P2,补全 master 收敛语义**:现有 `(key, requester)` RAII fence 保留,但把通用 `KeyBeingWritten`、`InvalidArgument`、`Unknown` 收敛成有限且可处理的 leader / join / already-committed / stale 结果。 +4. **P3,依据数据继续收缩**:若 per-key 对象和 wakeup 仍是热点,再把同一 leader cohort 折叠成一个 `BatchFlight`;若 suffix start / revoke 成本显著,再评估 side-effect-free probe 与 reserve 分离。 + +## 1. 评审边界与证据等级 + +本文沿三条轴评估当前路径,后文也按同样的轴给出验收条件: + +| 评估轴 | 覆盖内容 | 本文不声称的内容 | +| --- | --- | --- | +| 正确性与生命周期 | leader / joiner 归属、取消、revoke、prepared slot、master fence、reclaim 交互 | 不证明未检查模块的全系统回收行为 | +| 控制面与数据面成本 | 对象、复制、锁、task、future、RPC 和 transfer 提交边界 | 不把静态计数换算成延迟或 QPS 百分比 | +| 可验证性 | 并发测试、故障注入、metrics 和 benchmark 维度 | 不以单轮最终 QPS 代替路径级证据 | + +文中的判断分为三类: + +- **实现事实**:可由当前符号和控制流直接确认。 +- **风险推断**:由 Rust future 取消、所有权或锁作用域推导,仍需测试复现和量化影响。 +- **待测结论**:只能通过 benchmark、fault injection 或运行期 metrics 判断。 + +PegaFlow 对照只用于提炼设计模式。它的 cache 层次、vLLM 接口和跨节点协议与 Fluxon 不同,因此本文不会从 PegaFlow 的局部实现推出 Fluxon 的全路径性能结论。 + +## 2. 修复前 Fluxon 路径快照 + +### 2.1 两层共享状态(已删除 exact-batch 层) + +修复前 owner 同时维护下列共享状态: + +| 层次 | 主要类型或容器 | 去重粒度 | 持有的状态 | +| --- | --- | --- | --- | +| external handle | `external_get_start_registry` / `ExternalGetStartEntry` | 一个返回给 external 的 handle | `req_node_id` 和 exact-batch shared op | +| exact-batch | `external_get_start_by_key` / `ExternalGetStartSharedOp` | `keys + atomic_group_lens + prefix_best_effort` 完全相同 | `Starting/Running/Ready/Failed`、`waiter_count`、完整 dedup key、prefix、keys、items、`Mutex`、`Notify` | +| per-key | `OwnerKeyControlState.external_get` / `ExternalGetKeySharedOp` | owner 内单个 key | `Starting/Started/Finishing/Revoking/Ready/Failed`、`undecided`、`retained`、key、`Mutex`、`Notify` | +| master fence | `PreparedGetRequesterTable` / `PreparedGetRequesterLease` | `(key, requester)` | active `get_id` 和 RAII release | +| prepared memory | `OwnerLocalReserveSlotState::Prepared` | 一个 local-reserve slot | 精确 grant、slot、地址和大小 | + +其中 master 的 `(key, requester)` fence 是这轮更新里已经落地的有效改进。它允许不同 GPU owner 同时 materialize 同一 key,同时阻止同一 requester 的两个 prepared Get 并行发布。当前不足是冲突结果仍不可 join,也不能直接取得已经提交的 canonical holder。 + +### 2.2 修复前调用与数据流 + +```mermaid +flowchart TD + A[ExternalBatchGetStartReq] --> B{exact-batch DashMap} + B -->|已有| C[waiter_count + 1
等待同一 ExternalGetStartSharedOp] + B -->|新建| D[创建 exact-batch shared op] + D --> E[owner_key_control 下逐 key 扫描] + E --> F[Local: clone MemoryInfo] + E --> G[Join: per-key undecided + 1] + E --> H[Leader: 创建 per-key shared op] + H --> I[一次 BatchGetStart 处理 leader keys] + I --> J[task 1: external_get_key_singleflight] + J --> K{每个 key 的 prefix interest} + K -->|retained > 0| L[per-key transfer + BatchGetDone] + K -->|retained = 0| M[BatchGetRevoke + 释放 slot] + L --> N[per-key Ready] + M --> N + F --> O[task 2: external_get_start_transfer] + G --> O + N --> O + O --> P[复制为 exact-batch Ready keys/items] + C --> Q[返回独立 handle] + P --> Q + Q --> R[get_transfer 再复制 Ready keys/items
并安装 external holdings] +``` + +这里的 batch 化只覆盖部分边界: + +- owner 到 master 使用一次 `BatchGetStart`、一次 `BatchGetDone` 或 `BatchGetRevoke` RPC。 +- master 的 `handle_batch_get_start`、`handle_batch_get_done` 和 `handle_batch_get_revoke` 仍在进程内逐 item 调用单 key handler。 +- payload 阶段的 `batch_get_finish_started` 为每个需要传输的 key 创建一个 future;每个 future 调用一次 `transfer_data_no_copy`。该调用继续形成一次 closed-runtime transfer 请求。当前代码没有在这个边界先按 peer / transport 合并 descriptor。 + +因此,“RPC 是 batch”不能直接推广成“payload 提交和底层 DMA 已经是一个 batch”。底层 backend 可能还有自己的优化,但不在本次已追踪到的调用链内。 + +### 2.3 当前资源终止路径 + +| 资源或计数 | 获得位置 | 正常终止 | 当前取消或不确定性缺口 | +| --- | --- | --- | --- | +| per-key `undecided` | `plan_external_get_key_items` 看到 `Starting/Started` | `decide_external_get_key_item` | 计数与 `decision_registered: bool` 分离;future Drop 不会自动 decide / abandon | +| per-key `retained` | prefix 计算后手工增加 | leader finish / revoke 后发布 terminal | 依赖所有 `undecided` 先归零;一个丢失 decision 会阻塞整个 cohort | +| exact-batch `waiter_count` | exact-batch 命中或创建 | transfer / cancel 末尾 `release_external_get_start_waiter` | start 或 transfer RPC future 中途取消时没有 guard | +| external handle entry | `get_start` 返回前插入 `external_get_start_registry` | `get_transfer` 或 `cancel` remove | 容器没有 TTL;调用方进程死亡或消息丢失时没有本层兜底 | +| prepared local slot | leader `BatchGetStart` 前 claim | Done commit,或 Revoke 成功后 release | `OwnerLocalReserveSlotLease` 没有 Drop cleanup;claim 后的 future 取消和 Revoke RPC 不确定性都可能失去释放路径 | +| master requester fence | master 接受 prepared Get | `InflightGetInfo` Drop | 已有 RAII,且 inflight cache 有 60 秒 TTL;它不能替 owner 归还本地 `Prepared` slot | + +## 3. 正确性与生命周期发现 + +### 3.1 手工 decision 不是 cancellation-safe 所有权 + +`plan_external_get_key_items` 在 owner key fence 内先增加 `undecided`,随后调用链至少会经过 master RPC、逐 key start-code 等待和 prefix 计算。`ExternalGetStartOwnerItem::Shared` 只保存一个 `decision_registered: bool`,没有在 `Drop` 中减少计数。 + +如果 future 在增加计数后、执行 `decide_external_get_key_item` 或 `abandon_external_get_key_decisions` 前被取消: + +1. `undecided` 永久保留本次 interest。 +2. `classify_external_get_key_leader` 一直等待 `undecided == 0`。 +3. `finish_external_get_key_leaders` 按 leader 顺序 await;一个 key 卡住会阻止同 cohort 后续 key 进入 finish / revoke。 +4. per-key marker 继续占用 owner key fence,reclaim 对该 key 返回 `Busy`。 +5. exact-batch creator 仍可能停在 `Starting`,相同 batch 后续全部等待同一未完成操作。 + +这是 P0 正确性问题。修复应让“interest 存在”对应一个实际拥有 Drop 语义的 guard;bool 与计数器的约定不再承担所有权。 + +同一问题也覆盖 prepared slot。`batch_get_start_with_local_reserve_targets` 先取得 `OwnerLocalReserveSlotLease`,再 `.await` master RPC;返回 `Err` 的显式分支会释放 lease,但 future 在 await 中被 Drop 时不会执行该分支。`OwnerLocalReserveSlotLease` 本身没有 `Drop` cleanup,所以本次 claim 的 slots 可能继续停在 `Prepared`。per-key leader task 又是在该 RPC 成功返回后才 spawn;若请求在 await 中被取消,master 可能已经接受操作,owner 却没有 executor 接管它。同步计数可以直接在 Drop 中归还;需要 RPC 的 cleanup 应由 Drop 把工作提交给一个有界、可观测的 owner cleanup actor,并由 TTL 处理 actor 或进程失效,不能依赖一个无所有者的临时 task。 + +### 3.2 exact-batch waiter 和 handle 也存在同类缺口 + +exact-batch 层的 `waiter_count` 同样依赖显式 release: + +- `external_batch_get_start` 注册 waiter 后可能在 prepare 或等待 prefix 时被取消。 +- `external_batch_get_transfer` 先从 handle registry remove,再等待 shared result;等待期间被取消后,调用方已经没有 handle 可以补发 cancel,函数尾部的 waiter release 也不会执行。 +- terminal exact-batch op 只有在 `waiter_count == 0` 时才从 `external_get_start_by_key` 删除。 + +因此这一层不仅增加常数成本,也增加了一个独立的泄漏和永久等待面。删除该层会直接减少一种必须证明正确的生命周期。 + +### 3.3 exact-batch 的收益有限,参数归属也不清晰 + +exact-batch 层并非完全没有收益。它能让 100% 相同的并发请求只计算一次 prefix、只注册一次 per-key decision,并共享聚合后的 result vector。删除它以后,每个 handle 都需要构造自己的轻量 `BatchPlan`,因此必须把 100% identical workload 纳入 benchmark。 + +这项收益没有形成独立的正确性边界:真正避免重复 slot、master Start 和 payload transfer 的仍是 per-key flight。exact-batch 层为节省重复 plan 工作,引入了第二套 phase、waiter、result cache 和 cleanup 协议。对当前重点覆盖的“前缀大量重叠但 batch 长度或 atomic groups 不完全相同”场景,它又无法命中。 + +当前参数归属也暴露了这层抽象的歧义:`ExternalGetStartDedupKey` 不包含 `transfer_concurrency`,`ExternalGetStartSharedOp` 却保存第一个 creator 的值。相同 batch 使用不同 `transfer_concurrency` 时,后来的显式参数不会决定共享工作的并发度。per-key sharing 本身也意味着 shared keys 服从各自 leader cohort 的并发策略。这里需要保留一个规范契约:优先把 transfer concurrency 变成 owner / transport 的统一策略;如果仍保留请求参数,文档必须明确它只影响本请求新建的 leader cohort,不能维持未说明的 first-creator-wins 行为。 + +### 3.4 Revoke 不确定性没有 owner 侧闭环 + +当 suffix key 无人 retain 时,leader 进入 `Revoking`。`BatchGetRevoke` 成功后,代码才释放精确 prepared target。RPC 返回错误时,当前实现发布 per-key `Failed` 并清除 marker,但没有保存可重试的 `get_id` 和 target,也没有为 owner `Prepared` slot 建立 TTL。 + +master 的 `InflightGetInfo` 过期后会 Drop `PreparedGetRequesterLease`,所以 master fence 最迟可以重新开放。owner 本地 slot 是否最终返回 `Free`,无法从当前路径证明:释放它所需的精确 target 已经随 terminal op 丢失。更安全的状态应保留 `Revoking { get_id, target, next_retry }`,直到满足下列有限终态之一: + +- master 明确确认 Revoke,owner 释放 slot; +- master 返回 Done 已胜出,owner 按 canonical committed backing 收敛; +- master operation TTL 明确过期,owner 核对 generation 后释放 slot; +- owner generation 结束,整个 pool 随进程生命周期销毁。 + +在终态前清除 per-key marker 会把“master 是否仍在执行”和“owner slot 是否仍被占用”重新变成两个失去关联的状态。 + +### 3.5 master 防重已经部分完成,收敛语义仍缺失 + +当前 `PreparedGetRequesterTable` 已正确使用 `(key, requester)` 作为 identity,并通过 `PreparedGetRequesterLease::Drop` 释放。这一部分应保留。 + +仍需收敛的分支包括: + +| 场景 | 当前行为 | 需要的有限结果 | +| --- | --- | --- | +| 同 requester 已有 prepared Get | `KeyBeingWritten` | `Join { operation_id, immutable_start_item }`,或明确可重试的 transient 结果 | +| requester 已有同版本 live replica | `InvalidArgument: cannot replace a live replica` | `AlreadyCommitted`,释放新 slot 后取得 canonical local holder | +| GetDone 时同版本 route 已被另一个操作发布 | `Unknown: could not publish current route` | `AlreadyCommitted`,输家不覆盖 backing | +| GetDone 的 `put_id` 已落后 | 依赖通用错误路径 | `Stale`,revoke / release 后重新 probe | + +owner singleflight 可以是主要的快速路径,但不能成为唯一能解释冲突的正确性边界。master 已经维护唯一性 fence,下一步应返回可枚举、可测试的结果,避免 owner 从错误字符串猜测状态。 + +## 4. 修复前控制面与数据面成本 + +下表只描述当前源码可以确认的成本。最后一列中的性能影响仍需测量。 + +| 成本维度 | 当前实现事实 | 随什么增长 | 判断 | +| --- | --- | --- | --- | +| key 所有权复制 | exact-batch DashMap key 和 `ExternalGetStartSharedOp.dedup_key` 各自拥有完整 key 向量;transfer prefix 又被构造并在 `Running` / task 间复制;每个 per-key op 还拥有自己的 `String` | batch key 数和 key 长度 | 明确存在,可通过删除 exact-batch 层减少;延迟占比待测 | +| 共享对象 | 每个新 leader key 有一个 `Arc`、`Mutex`、独立 `Arc` 和 terminal result;每个 exact batch 再有一套 shared op | leader key 数和并发 batch 数 | 对短 value / 高并发更敏感,实际 allocator 成本待测 | +| 全局 fence | `owner_key_control` 在同一临界区内先扫描 revoking keys,再逐 key 做 local / join / leader 规划,并穿插 per-key state lock 和索引查询 | required key 数及并发请求数 | 可能形成 p99 lock contention;需要 lock-wait histogram | +| per-key lock / wakeup | start publish、decision、classification、terminal publish 和每个 waiter 都访问 per-key state;exact-batch 又有第二层 lock / notify | joiner 数和状态变化次数 | 两层 wakeup 没有独立语义,优先删除外层 | +| task | 非全 local 的 creator 通常生成 `external_get_key_singleflight` 和 `external_get_start_transfer` 两个 task | creator batch 数 | 第二个 task 只聚合 per-key terminal 到 exact-batch terminal,可删除 | +| waiter future | `finish_external_get_start_transfer` 对 transferable items 建立 `join_all` future;revoke 等待也按 key 建 future | transferable / revoking key 数 | 调度与 wakeup 成本明确,幅度待测 | +| result materialize | per-key `Ready` 保存结果;聚合 task 再构造 exact-batch `Ready`;每个 handle transfer 再 clone `keys/items` | transferable key 数和相同 batch waiter 数 | exact-batch result cache 造成额外向量与 `Arc` refcount 流量 | +| payload 提交 | `batch_get_finish_started` 为每个远端 key 调用一次 `transfer_data_no_copy`;每次继续形成独立 closed-runtime transfer request | 远端 hit key 数 | 控制面 RPC 已 batch,transfer 提交尚未在该边界合并 | +| master batch handler | `BatchGetStart/Done/Revoke` handler 在 master 内逐 item await 单 key handler | leader / terminal key 数 | 网络 RPC 数受控,master 本地调度仍为 O(keys) | +| suffix speculation | 所有 leader 先 Start,prefix 计算后再按 `retained` 选择 Finish 或 Revoke | raw hit 之后的 leader suffix | 避免 probe RPC,但增加 slot claim、master work 和 revoke;需和 probe/reserve 实测比较 | + +当前优先级更高的风险依次是取消后不终止、全局 fence 临界区、双层状态 wakeup 和逐 key transfer submission。key clone 也明确存在,但不应先为它引入新的缓存或兼容层。 + +## 5. PegaFlow 可以借鉴的设计模式 + +PegaFlow 对照源码固定在提交 `939363f198a0ffded9e3f30d8af9cdd74439f16c`: + +| PegaFlow 模式 | 实现证据 | 对 Fluxon 的启发 | +| --- | --- | --- | +| 一次 prefix scan 取得稳定引用 | [`ReadCache::get_prefix_blocks`](https://github.com/novitalabs/pegaflow/blob/939363f198a0ffded9e3f30d8af9cdd74439f16c/pegaflow-core/src/storage/read_cache.rs#L35-L50) 在一个 cache mutex 下按序扫描并 clone `Arc` | Fluxon 的 local branch 已在 owner fence 下 clone `MemoryInfo`;让 `BatchPlan` 直接拥有这些 pin 即可,无需再包装 exact-batch state | +| 一个 ready prefix 对应一个 opaque lease | [`QueryLeaseManager`](https://github.com/novitalabs/pegaflow/blob/939363f198a0ffded9e3f30d8af9cdd74439f16c/pegaflow-core/src/lease.rs#L42-L184) 让 lease 持有整个 `Vec>`,支持 consume、release、consumer count 和 sweep | Fluxon handle 应拥有整批 plan / lease,并在 transfer 或 cancel 时一次消费;进程死亡由 TTL 收口 | +| request-level prefetch state | [`PrefetchState`](https://github.com/novitalabs/pegaflow/blob/939363f198a0ffded9e3f30d8af9cdd74439f16c/pegaflow-core/src/storage/prefetch.rs#L79-L155) 用一个 `HashMap` 和一个 mutex 管理后台任务 | per-key singleflight 只保留跨请求去重真正需要的状态;请求级聚合不要再复制一套 phase machine | +| probe 与 commit 分离 | [`vllm-request-state-machine.md`](https://github.com/novitalabs/pegaflow/blob/939363f198a0ffded9e3f30d8af9cdd74439f16c/docs/vllm-request-state-machine.md#L318-L461) 明确提出 `QueryPrefetch -> ReserveLoadBlocks -> Load -> ReleaseReservation -> TTL` | Fluxon 可用 side-effect-free probe 先确定 prefix,再只 reserve transferable prefix;是否值得多一次 RPC 必须 benchmark | +| 取消安全的资源 guard | [`TransferLockGuard`](https://github.com/novitalabs/pegaflow/blob/939363f198a0ffded9e3f30d8af9cdd74439f16c/pegaflow-core/src/backing/transfer_lock_guard.rs#L13-L70) 和 [`SsdPrefetchReservation`](https://github.com/novitalabs/pegaflow/blob/939363f198a0ffded9e3f30d8af9cdd74439f16c/pegaflow-core/src/storage/prefetch.rs#L141-L155) 都在 `Drop` 中归还资源 | `undecided`、waiter、slot 和 master operation retry ownership 都应由 guard 表达 | +| descriptor-first 的批量数据面 | [`transfer`](https://github.com/novitalabs/pegaflow/blob/939363f198a0ffded9e3f30d8af9cdd74439f16c/pegaflow-core/src/transfer/mod.rs#L1-L16) 与 [`gpu_worker`](https://github.com/novitalabs/pegaflow/blob/939363f198a0ffded9e3f30d8af9cdd74439f16c/pegaflow-core/src/gpu_worker.rs#L350-L496) 先收集所有 layer / segment descriptor,再交给一次 backend batch 并同步一次 | Fluxon 应统计并减少实际 transfer submission,而不只统计 BatchGet RPC 数 | +| 路径契约测试和 metrics | [`prefix_semantics`](https://github.com/novitalabs/pegaflow/blob/939363f198a0ffded9e3f30d8af9cdd74439f16c/pegaflow-core/tests/prefix_semantics.rs)、[`prefetch_lease`](https://github.com/novitalabs/pegaflow/blob/939363f198a0ffded9e3f30d8af9cdd74439f16c/pegaflow-core/tests/prefetch_lease.rs) 和 [`test_connector_fault_tolerance`](https://github.com/novitalabs/pegaflow/blob/939363f198a0ffded9e3f30d8af9cdd74439f16c/python/tests/test_connector_fault_tolerance.py) 分别覆盖 prefix、lease consumer、失败与 cleanup | Fluxon 需要把 overlap、取消和资源归零作为 merge gate,纯 prefix helper 不足以覆盖生命周期 | + +### 5.1 不应照搬的部分 + +- **PegaFlow 没有跨请求 per-block singleflight**:active prefetch 按 `req_id` 组织;两个不同请求的重叠 block 仍不共享同一个 per-block future。 +- **当前 probe 仍有副作用**:`QueryPrefetch` 已经 pin ready blocks。PegaFlow 自己的设计文档也把 probe / reserve 分离列为未来协议。 +- **`req_id` 不是完整 identity**:同一请求在 preemption 或调度重试后可能对应不同 hash slice;PegaFlow 文档建议加入 `digest(block_hashes)`。 +- **600 秒 lease TTL 不适合直接复制**:Fluxon prepared local-reserve slot 是稀缺资源,TTL 应由 slot 容量、最大合法 transfer 时长和故障恢复目标决定。 +- **语义边界不同**:PegaFlow 的简单 prefix cache scan 不承担 Fluxon 的 atomic group、master route、owner reclaim fence 和跨 requester 唯一性。 + +## 6. 建议的收缩设计 + +### 6.1 第一阶段:handle 直接持有 `BatchPlan` + +第一阶段保留现有 per-key shared op,先删除 exact-batch shared op。内部结构可以收敛为: + +```rust +struct ExternalGetBatchPlan { + req_node_id: String, + keys: Vec, + prefix: ExternalGetStartPrefixResult, + items: Vec, +} + +enum ExternalGetPlanItem { + Local(Arc), + Shared(ExternalGetInterest), +} +``` + +这只是内部设计草图,名称应在实现时与仓库现有命名统一。关键契约是: + +- `ExternalGetInterest` 由 RAII guard 表达。创建时注册一次 prefix decision;prefix 计算会把它消费成 abandon 或 plan 持有的 result interest。未决定就 Drop 时自动 abandon;进入 `Finishing` 后的 Drop 只释放 waiter,不回滚已经提交的数据面终态。 +- `external_get_start_registry` 直接持有 `BatchPlan`,不再间接持有 `ExternalGetStartSharedOp`。 +- `get_transfer` 消费 plan 并等待其中的 per-key terminal;`cancel` Drop plan。两个入口共享同一条释放路径。 +- 完全相同的两个 batch 仍会在 per-key registry 中 join 相同 flight,因此不会重复 Start / transfer。 +- leader cohort 的现有后台 task 已经负责 transfer 和 Done。删除 `external_get_start_transfer` 聚合 task 不会失去 start 与 GPU allocation 的重叠,只会删除第二次等待和结果 materialize。 +- handle registry 需要 TTL / generation cleanup。TTL 回调与显式 cancel 必须调用同一个幂等终止函数。 + +可以删除的重复 surface 包括: + +- `ExternalGetStartDedupKey` +- `ExternalGetStartSharedOp`、`ExternalGetStartSharedState`、`ExternalGetStartSharedPhase` +- `external_get_start_by_key` +- `register_external_get_start_waiter`、`release_external_get_start_waiter` +- `wait_external_get_start_prefix`、`wait_external_get_start_transfer` +- `publish_external_get_start_ready` 及第二份 batch terminal result +- `external_get_start_transfer` 聚合 task + +`ExternalGetStartSharedItemResult` 此后只属于 per-key terminal,应改成唯一且明确的 `ExternalGetKeyResult`,避免名字继续暗示 exact-batch sharing。 + +```mermaid +flowchart LR + A[ExternalBatchGetStartReq] --> B[owner fence 下构造 BatchPlan] + B --> C[Local
Arc MemoryInfo] + B --> D[Join
KeyInterest guard] + B --> E[Leader cohort] + E --> F[一次 BatchGetStart] + F --> G[一个 cohort task
transfer + Done/Revoke] + G --> H[per-key terminal] + C --> I[handle registry
BatchPlan + TTL] + D --> I + H --> I + I -->|get_transfer| J[消费 plan,安装 holdings] + I -->|cancel / TTL| K[幂等 Drop plan] +``` + +### 6.2 第二阶段:有数据再折叠成 `BatchFlight` + +删除 exact-batch 层后,如果 metrics 证明 per-key `Arc + Mutex + Notify` 仍是热点,可以让同一次扫描产生的 leader keys 共用一个 `BatchFlight`: + +- key registry 保存 `(Weak, slot_index, generation)`。 +- `BatchFlight` 持有一个 slots 数组、一个 mutex、一个 notify 和一个 cohort task。 +- joiner 只保存 `Arc + slot_index + InterestGuard`。 +- 每个 slot 有独立 outcome 和 interest count,但同步原语属于整个 cohort。 +- registry 删除必须同时校验 key、flight identity、slot 和 generation,旧 waiter 的 Drop 不能删除后来创建的 flight。 + +这一步能把同步对象从 O(leader keys) 降到 O(leader cohorts),代价是一个 notify 可能唤醒同 cohort 的无关 slot waiter。应先测 per-key 对象和 wakeup 是否真的占主导,再决定是否接受该 trade-off。不要在删除重复层之前再叠加第三套 batch state machine。 + +### 6.3 master 返回可收敛的有限结果 + +master 的 prepared Get start 应返回一个可穷举结果集合。下面只描述分支语义,不是当前已存在的 Rust 类型: + +```text +Leader { start_item } +Join { operation_id, immutable_start_item } +AlreadyCommitted { put_id, backing_identity } +Stale +``` + +具体 wire 类型需要单独设计,但分支必须保持有限: + +- `Leader` 获得本次 prepared target 的唯一提交权。 +- `Join` 返回足够重建原 operation 的 immutable start 信息。owner 仍只能选出一个 transfer executor,其他 waiter 观察同一终态。 +- `AlreadyCommitted` 返回 version 和 backing identity,让 owner 释放候选 slot,并在 reclaim fence 下取得 canonical local holder。 +- `Stale` 终止旧 operation,重新读取当前 route / version。 + +master fence 的 RAII lease 和 60 秒兜底可以继续保留,但 owner slot 的终止不能只依赖 master cache Drop。 + +### 6.4 probe / reserve 作为可选协议,不先假设它更快 + +当前 speculative Start 的优点是少一次网络往返,并能尽早开始远端 materialization;成本是 raw prefix 之后的 key 也 claim slot、进入 master、再走 Revoke,还需要 `undecided/retained/Revoking` 协调多个 batch 的 prefix interest。 + +可选的两阶段协议为: + +1. `BatchGetProbe(keys)`:只返回每个 key 的 local / route 可用性和 version,不占 prepared slot。 +2. owner 按原始顺序和 atomic groups 算出 `transferable_len`。 +3. `BatchGetReserve(keys[..transferable_len], versions)`:全量成功或返回 stale / retry,不留下部分 reservation。 +4. transfer 消费 reservation;cancel / failure / TTL 释放 reservation。 + +该协议能删除大部分 suffix revoke 和 decision accounting,但多一次 RPC,并引入 probe 与 reserve 之间的 eviction / version race。正确处理方式是 reserve 时原子复核,把 race 降级为 cache miss / retry。是否采用,应比较: + +- 当前 speculative Start + suffix Revoke; +- probe + reserve; +- 不同 batch 长度、miss 位置、overlap ratio 和 RTT 下的端到端结果。 + +### 6.5 保留 batch 语义,并把 batch 延伸到 transfer submission + +无论控制面采用 per-key op 还是 `BatchFlight`,都应维持: + +1. owner 以逐 key/shard 短 fence 完成 required batch 的 local / join / leader 分类;不得用 + process-wide lock 取得整批快照,也不得让任何同步锁跨 `.await`; +2. leader keys 压缩成一次 `BatchGetStart`; +3. terminal 使用一次 `BatchGetDone` 或 `BatchGetRevoke` 收敛; +4. 结果按原 index scatter,再计算 raw prefix 和 atomic-group prefix; +5. payload descriptor 先按 peer、方向和 transport 能力分组,再调用 batch transfer surface。 + +PegaFlow 的 descriptor-first 做法适合借鉴到第 5 步。Fluxon 至少应新增 `transfer_submissions`、`descriptors_per_submission` 和 `bytes_per_submission`,先确认当前每 key 调用是否真的成为瓶颈,再设计 batch transfer API。 + +## 7. 迁移顺序 + +| 阶段 | 改动 | 完成判据 | +| --- | --- | --- | +| P0 生命周期 | 引入 decision / waiter / prepared operation guard;统一显式 cancel、future Drop、TTL cleanup;保留 revoke retry identity | fault injection 取消任一 await 后,active handle、interest、marker 和 prepared slot 都回到基线 | +| P1 删除重复层 | handle 改持 `BatchPlan`;删除 exact-batch map、phase、notify、waiter 和聚合 task | identical / overlapping batch 的 leader Start 数不增加;公开 API 不变 | +| P2 master 收敛 | wire 层增加有限 outcome;owner 实现 join、already-committed 和 stale 分支 | 同 requester 冲突不再暴露通用 `KeyBeingWritten` / `InvalidArgument` / `Unknown` | +| P3 数据驱动优化 | 测量并选择 `BatchFlight`、probe/reserve、batch transfer submission | 每个新增机制都有对应热点证据和独立回退对照 | + +截至 2026-07-17,P0 的 Interest/planning leader/prepared-slot guard、P1 exact-batch 删除、 +P2 的 `(key, requester)` fence 与 overlap/ABA 防线已进入当前工作树并通过定向单元测试; +P2 的完整有限 outcome 仍需故障注入确认。P3 的 +payload descriptor batch 仍未实现,必须由部署后的 submission metrics/QPS 决定,不能仅凭 +静态结构继续加层。 + +P0 与 P1 可以先在现有 per-key 实现上完成。不要为了等待理想的 `BatchFlight` 一次性重写而继续保留已知的取消缺口。 + +## 8. 测试、观测与验收门槛 + +### 8.1 必须补齐的测试 + +最新更新已经增加三类有价值的 unit test:两个非完全相同 batch 复用同一 per-key marker、旧 marker cleanup 不删除新 generation,以及 master `(key, requester)` fence 的同 owner / 跨 owner 与 ABA 行为。它们验证了同步注册和 identity 规则,但没有启动真实 RPC / transfer / cancel 生命周期。下列测试仍需直接运行 async 流程,显式检查 exit code / timeout 和资源终态: + +| 场景 | 必须断言 | +| --- | --- | +| overlap:`[a,b,c]` 与 `[b,c,d]` | `b/c` 对同 owner 各只有一个 leader Start 和一份 committed backing;两个 batch 各自 prefix 正确 | +| identical batch | 删除 exact-batch 层后仍只产生一组 per-key leader;两个 handle 可独立 transfer / cancel | +| duplicate key:`[a,a,b]` | `a` 只有一个 flight;两个原 index 都得到一致结果;interest 不下溢或泄漏 | +| atomic-group suffix | group 不被切开;suffix local pin、join interest 和 leader prepared slot 全部释放 | +| task cancellation matrix | 在注册 decision、Start 前后、等待 prefix、等待 result、handle remove 后逐点 abort;后续同 key 请求可在 deadline 内完成 | +| Revoke 响应丢失 | owner 保留 retry identity;master TTL / terminal query 后 slot 最终回到 `Free`,不会直接清 marker 丢状态 | +| Done / Revoke race | 只有一个终态释放资源;Done 胜出时 Revoke 不释放 committed slot | +| reclaim race | Local、Starting、Finishing、Revoking 和 terminal 各阶段与 reclaim 并发,不出现地址复用或永久 `Busy` | +| master requester fence | 同 requester 第二个 Get 返回 join / already;不同 requester 可以同时成为 leader | +| stale version | 旧 `put_id` 不覆盖新 route;候选 slot 被回收并重新 probe | +| owner / external generation change | 旧 handle、旧 flight 和旧 cleanup 不能删除或消费新 generation 状态 | + +### 8.2 必须暴露的路径 metrics + +| 类别 | 指标 | +| --- | --- | +| 分类 | `required_keys`、`local_pinned`、`inflight_joined`、`leader_started`、`duplicate_indices` | +| 去重收益 | `get_start_avoided`、`transfer_avoided`、`identical_batch_joined` | +| 生命周期 | active handles / flights / interests / prepared slots、各自 age、cancel / TTL / Drop cleanup 次数 | +| suffix | local pin drop、join interest drop、leader revoke、revoke retry、revoke unknown | +| master 收敛 | leader、join、already-committed、stale、TTL expired,按结果分别计数 | +| 等待与锁 | owner fence wait / hold、join wait、flight lifetime 的 histogram | +| 数据面 | BatchGet RPC items、transfer submissions、descriptors / bytes per submission、Done / Revoke batch size | + +所有 gauge 都必须能在 workload 结束后的有界时间内回到基线。只增加累计 counter 无法发现永久挂住的 handle、interest 或 prepared slot。 + +### 8.3 benchmark 矩阵 + +至少比较三个实现:变更前的 batch path、当前双层 shared-op path、删除 exact-batch 层后的 `BatchPlan` path。输入矩阵应覆盖: + +- key 数:`1 / 16 / 64 / 256`; +- overlap ratio:`0% / 50% / 90% / 100%`; +- first miss:首部、中部、尾部和 all-hit; +- 并发:单请求、同 owner 多请求、多个 requester owner; +- value / page 大小:控制面占主导的小 value,以及数据面占主导的实际 KV page; +- local / same-host / remote transport; +- fault-free、cancel storm 和 Revoke 响应延迟 / 丢失。 + +采集 `get_start` p50 / p99、完整 transfer p50 / p99、CPU、allocation bytes / count、task spawn、lock wait、RPC items、transfer submission 和最终 slot / handle gauge。验收时先检查语义计数和资源归零,再比较延迟;最终 QPS 只能作为补充结果。 + +## 9. Fluxon 证据索引 + +| 事实 | 当前代码位置 | +| --- | --- | +| per-key flight 与 request plan 类型 | `fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs`:`ExternalGetKeySharedOp`、`ExternalGetKeyInterest`、`ExternalGetStartEntry` | +| per-key 规划和 RAII decision | `fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs`:`plan_external_get_key_items`、`ExternalGetKeyInterest::decide/Drop` | +| leader finish / revoke | 同文件:`classify_external_get_key_leader`、`finish_external_get_key_leaders` | +| request plan handle(无 exact-batch shared-op) | 同文件:`external_batch_get_start`、`finish_external_get_start_transfer`、`external_batch_get_transfer` | +| per-key payload transfer submission | `fluxon_rs/fluxon_kv/src/client_kv_api/get.rs`:`batch_get_finish_started` | +| transfer closed-runtime 边界 | `fluxon_rs/fluxon_commu/src/facade/transfer_engine.rs`:`transfer_data_no_copy` | +| external Get 与 reclaim fence | `fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs`:`prepare_one` | +| master requester fence 与 TTL | `fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs`:`PreparedGetRequesterTable`、`PreparedGetRequesterLease`、`inflight_gets` | +| master 冲突和 batch handler | `fluxon_rs/fluxon_kv/src/master_kv_router/get.rs`:`handle_get_start`、`handle_get_done`、`handle_batch_get_start` | +| 已有 overlap / ABA unit tests | `external_get_start_batch_tests::overlapping_nonidentical_batches_share_each_key_but_keep_leaders_batched`、`old_singleflight_cleanup_cannot_remove_new_generation`、`prepared_get_singleflight_is_same_owner_only_and_aba_safe` | +| 原设计要求 | `fluxon_doc_cn/design/sglang_fluxon_kv集成设计.md`:`Batch Get 的逐 key 交集、pin 与 singleflight` | + +## 10. 决策记录 + +- **接受** owner 侧 per-key overlap 去重和 master 侧 `(key, requester)` 防御性唯一性。 +- **接受** BatchGetStart / transfer / Done 在数据流上的 cohort 概念。 +- **拒绝** exact-batch shared op 与 per-key shared op 长期并存。 +- **拒绝** 用 bool 和手工 counter 表达跨 `.await` 的资源所有权。 +- **暂缓** `BatchFlight` 和 probe/reserve 协议,直到 P0 / P1 完成且 metrics 指向对应热点。 +- **要求** 在把该路径视为完成前,补齐取消、overlap、Revoke 不确定性、reclaim race、master 收敛测试和资源归零观测。 + +## 11. 2026-07-16 实现跟进 + +本分析提出的 P0/P1 已进入工作区实现: + +- 删除 `ExternalGetStartDedupKey`、`ExternalGetStartSharedOp`、 + `external_get_start_by_key`、request-level waiter/phase/result cache 和 + `external_get_start_transfer` 聚合 task;handle 直接拥有自己的 keys/items plan。 +- `ExternalGetKeyInterest` 以 RAII 表达 prefix decision;未决定的 request future 被取消时, + Drop 自动减少 `undecided`。leader cohort 在第一个 master RPC await 前交给注册后台 task, + 因而请求取消不会丢失 Start/Finish/Revoke executor。 +- prepared slot claim 使用 Drop cleanup guard;明确接受的 slots 才逐项 disarm。external + handle 增加 360 秒 TTL 和统一 Drop 回收,覆盖当前对齐 workload 的 300 秒合法请求窗口。 +- `Revoking` 保存完整 start item;BatchGetRevoke 的 transport、响应长度和 identity 不确定性 + 保留 marker/slot 并重试,只有明确 Revoke 成功才释放 target。transfer/install 失败的 + cleanup 也在独立注册 task 中持有 get ids 和 targets,调用方取消不再丢失清理 ownership。 +- overlap/ABA 测试之外新增了 pending Interest Drop 和真实 task abort 测试;当前仍需用真实 RPC + fault injection 覆盖 Done response 丢失、owner generation 切换和完整 transfer cancellation matrix。 +- BatchGetDone 不再固定重试三次后遗留 pending-visible slot,而是使用同一组 get ids 幂等重试, + 严格校验响应长度和逐项 identity,直到明确终态或 owner shutdown。BatchGetStart 没有响应的 + 未知提交点会将 prepared slots 隔离 65 秒,覆盖 master 60 秒 inflight TTL;已知 get ids 的 + 异常响应则移交独立 Revoke cleanup。 +- owner 周期快照增加 active handle、per-key flight 阶段、undecided/retained interest 和 + Free/Prepared/Pending/Committed local-reserve slot 计数,用于三机 workload 后资源归零验收。 + +这次跟进没有宣称 payload 已成为单次底层 DMA batch。控制面 cohort 仍是一次 +BatchGetStart/Done/Revoke,但 `transfer_data_no_copy` 的 descriptor-first 合并仍属于后续 P3, +必须由 submission metrics 和 benchmark 决定接口形态。 + +2026-07-17 使用宝宝盘 `CARGO_TARGET_DIR` 和单并发构建做了最新工作树回归。 +Clippy 在仅放行仓库既有 `uninit_vec` 的前提下强制 +`-D clippy::await_holding_lock` 通过;master-router、owner-hot、local-reserve、 +member-left 和 `test_memholder_pin` 分别为 `28/28`、`9/9`、`8/8`、`5/5`、`1/1`。 +`fluxon_kv --lib` 全量为 `176 passed, 0 failed`,旧的 `test_memholder_pin` 失败已不再复现。 +上述结果不替代真实 RPC fault injection 和三机生命周期验证;尤其仍需主动丢弃 +Start/Done/Revoke 响应并检查快照临时态回到基线。 diff --git "a/fluxon_doc_cn/design/sglang_fluxon_kv\351\233\206\346\210\220\350\256\276\350\256\241.md" "b/fluxon_doc_cn/design/sglang_fluxon_kv\351\233\206\346\210\220\350\256\276\350\256\241.md" index 475adab..9c38aa5 100644 --- "a/fluxon_doc_cn/design/sglang_fluxon_kv\351\233\206\346\210\220\350\256\276\350\256\241.md" +++ "b/fluxon_doc_cn/design/sglang_fluxon_kv\351\233\206\346\210\220\350\256\276\350\256\241.md" @@ -27,6 +27,50 @@ - 因果链:SGLang KVCache restore 不是普通逐 key `get`,而是面向一批有序 page keys 的 prefix restore。它需要一次性回答“这一批最多恢复到哪里”,并且不能切开一个 radix node 对应的 atomic group。batch 化还能减少逐 key 调用、查表、锁和跨边界调度开销。 - 本设计落点:Fluxon hostless get 以 batch 为单位计算 `raw_prefix_hit_len`、`transferable_len` 和 `prefix_hit_groups`。`get_start` 合并存在性 / prefix 判断和可恢复前缀的数据拉取启动,返回 handle 和 prefix;`get_transfer` 再消费 handle,把可恢复前缀转换成 readable `plan_ptr(value_ptrs)`。 +### 关键设计倾向与强制规约 + +本文使用 `MUST`、`MUST NOT`、`SHOULD` 和 `MAY` 区分正确性规约与性能倾向: + +- `MUST / MUST NOT` 是内存、版本、可见性或批量语义的硬不变量;即使某个实现能得到更高 + QPS,违反它也不得验收。 +- `SHOULD` 是默认性能方向;偏离时必须给出可重复的对照实验和没有破坏硬不变量的证据。 +- `MAY` 表示在不改变外部契约时可替换的内部策略。 + +设计取舍的优先级固定为:首先保证 backing/version/holder 正确性,其次保证本地快路径 +不被全局控制面阻塞,再次保证 batch/atomic/TP 语义,最后才是单轮命中率或 QPS。 +关键规约如下: + +| ID | 级别 | 规约 | 验收含义 | +| --- | --- | --- | --- | +| V1 | MUST | native write 和 stream 可见性完成后,Put slot 必须立即进入 `local-read-ready` / `precommit_local_visible_info`。同 owner local read 不等待 master PutDone。 | 在人为延迟 master RPC 时,同 owner Get 仍能命中并取得 holder。 | +| V2 | MUST NOT | `local-read-ready` 不得被解释为 global committed。master route 成功前,其它 owner 不得通过全局 route 观察该 value。 | local 与 remote 可见性分别故障注入,不出现未完成 route 的跨 owner 读。 | +| V3 | MUST | `Committed(route_live=true)` 和 owner-hot admission 必须等 master route/maintenance 成功;这个门禁不得反向阻塞 V1 的 local read。 | hot Moka 中每个条目都可与相同 `put_id + backing identity` 的 live route 对账。 | +| G1 | MUST | required batch `R` 必须与可 pin 的 local-visible `L` 和可共享 inflight Get `F` 完整分流:`LocalJoin=R∩L`、`InflightJoin=R∩F`、`Leader=R-(L∪F)`。每个 key 独立线性化,不要求用一把锁取得整批快照。 | 重叠但不完全相同的 batch 不会对共享 key 重复申请 slot 或传输,同时大 batch 不会阻塞无关 key。 | +| G2 | MUST | 任何 leader GetStart/payload transfer 之前,`LocalJoin` 必须已持有 `MemoryInfo` holder pin,`InflightJoin` 必须已持有 shared-op waiter/pin,`Leader` 必须已原子安装 marker。 | pin 与 hot demotion/reclaim 并发时,kernel 看到的地址不会提前回收或复用。 | +| G3 | MUST NOT | 不得用“snapshot inflight set,稍后批量 insert”实现与非;必须逐 key 使用原子 entry/CAS 确定 leader 和 joiner。 | 并发两批均只有一个 leader,registry 清理不发生 ABA 删新操作。 | +| G4 | MUST | leader 子集的压缩响应必须先按原 index 重组成与 `R` 等长结果,然后才能按原 `atomic_group_lens` 计算 `raw_prefix_hit_len/transferable_len`。 | 不会因压缩 leader 而改变 prefix 顺序,也不恢复半个 radix node。 | +| G5 | MUST | `transferable_len` 之后的 local pin、join waiter 和 leader prepared Get 必须立即释放/revoke;不得保留到 TTL。 | suffix holder、master inflight 和 prepared slots 在每轮结束后可精确对账归零。 | +| G6 | MUST | owner 侧按 key singleflight;master 侧的防御性唯一性粒度为 `(key, requester_owner)`,不是全局 key。 | 同 owner 不重复 materialize;不同 GPU owner 仍可同时拉取同一 key。 | +| G7 | MUST | per-key shared Get 必须至少有 `Starting/Started/Ready/Failed-or-Revoked` 阶段,所有 waiter 观察同一终态并共享同一 canonical `MemoryInfo`。 | 重叠 batch 测试中 master GetStart、DMA 和 committed local route 均只出现一份。 | +| G8 | MUST / SHOULD | per-key singleflight 只是 leader/joiner 的线性化粒度,不得把控制面降级为逐 key RPC。同一 required batch 的 leader 必须压缩成一次 BatchGetStart,GetDone/Revoke 也必须批量收敛(MUST)。payload 当前仍逐 key调用 `transfer_data_no_copy`;应按 peer/transport 汇总 descriptor 后批量提交,或至少在有界 time-window 内并行聚合(SHOULD,尚未实现)。 | Start/Done/Revoke 次数按 batch 而不是 leader key 数增长;另外单独统计 payload submission,未实现 descriptor batch 前不得宣称数据面已完全 batch 化。 | +| G9 | SHOULD | 同时到达的多个 required batches 中,已经判定为 leader 且具有兼容 value geometry/transport 的 keys 应进入短 time-window micro-batch;窗口必须有界,不能为凑 batch 无界延迟 local hit 或 prefix 响应。 | 同时并发压力下 batch size 提升,但 p50/p90 GetStart 不因等待窗口显著恶化。 | +| G10 | MUST NOT | owner Get 规划、hot pin 和 runtime metrics 不得持 process-wide key-control mutex 遍历 batch/cohort;key-control 只能是短 O(1) 的逐 key/shard 临界区,禁止跨 `.await`、RPC、RDMA。规划取消必须用 RAII 清理尚未 BatchGetStart 的 leader marker。 | 大 batch 与无关 key 并发前进;取消任一 await 后没有永久 `Starting` marker、undecided 或 prepared slot。 | +| A1 | MUST | atomic group/TP cohort 可以逐项 local-ready,但只有完整 group 才能对 restore 发布命中;同一 cohort 先全部 promotion,再统一 owner-hot admission。 | 任一 rank/member 失败时不暴露半组 GPU KV 状态,首个成员不会提前 hot eviction。 | +| A2 | MUST | local-first Put 的同一 batch 必须由一个 publish job 持有全部 reservation/pending fence;PutDone 不确定或部分 promotion 时只用同一 identity 整批 roll-forward。声明不完整的 atomic group 禁止退化为逐 key 发布。 | 注入丢响应、取消和局部 promotion 后,所有成员最终一致发布,且不存在半组 hot admission 或提前释放 slot。 | +| S1 | MUST | KV 驱逐和复用单位是单个 slot/key/version;`512 MiB` grant 只是物理容器,不是驱逐、恢复或等待单位。 | 一个 grant 中部分冷 slot 可独立降级、回收并被后续 Put/Get 复用。 | +| S2 | MUST | slot 只有在 `route_live == false && holder_ref_count == 0` 时才能回到 Free;route 释放和 holder 释放的任意先后顺序都不得提前复用。 | 故障注入覆盖 route-first/holder-first,不出现 use-after-free 或重复 free-list entry。 | +| S3 | MUST | owner 容量驱逐与 remote replica 解耦。owner 提交完整、精确的 atomic/TP source cohort;master 只验证并删除该 owner source,不选择 victim,也不要求 CPU route 已存在。最后一份 cache route 允许删除,后续正常 miss/recompute。 | 有 CPU 时只删 GPU source;无 CPU 时 route 消失;remote write 失败只损失后续命中率,不否决 owner 回收。 | +| S4 | MUST | Moka 已发出的 size eviction 必须进入有界、可重试的 exact source-eviction ownership。cohort 元数据暂不完整时保留同一 selected identity 重试,不能静默丢弃、降级成单 key 删除或重新进入 append。 | `size_evictions` 可与 selected/handoff/committed/restored/obsolete/retry 对账;只有物理 Free 或安全恢复 hot 才结清 selected debt。 | +| S5 | MUST NOT | `evict_some`、hot ratio、slot 循环或 grant shrink 不得修改 owner 配置容量。GPU0/GPU1/CPU 实验容量仍为 `128/128/256 GiB`。 | 调优前后 `contribute_to_cluster_pool_size`、Moka max capacity 和 expected-grant 契约可对账。 | +| T1 | MUST | Put/Get/replica/demotion 的结果不确定时必须使用同一 operation ID 重试幂等终态,不得猜测失败并释放可能已发布的 backing。 | 响应丢失/重放后 route、holder、slot 和 quota token 都只提交或归还一次。 | +| T2 | MUST | 相同 `put_id` 的 live-local/GetDone 竞争是可收敛状态,不得作为 `InvalidArgument/Unknown` 永久失败;输家释放新 slot 并复用 canonical holder。不同 `put_id` 才是 stale。 | `cannot replace a live replica` / `could not publish current route` 从可见错误归零,且不会覆盖当前 backing。 | +| P1 | SHOULD | local hit 和 local-ready Put 快路径不同步等待 master/RDMA;跨边界工作按 batch/time-window 合并,避免逐 key `start-transfer-end`。 | 进行 master/RDMA 延迟注入时 local-only 路径延迟和 QPS 不应同比例恶化。 | +| P2 | MUST | 实验必须同时记录 QPS、L1/L2/L3/总命中、local/inflight/leader 分流、CPU source Get、replica/demotion、slot free/used 与业务错误。 | 不得只使用 QPS 或逻辑 admission 声称容量收益、去重或 CPU 已生效。 | +| P3 | MUST | 与 Mooncake 的容量对齐按“进程内 HiCache L2 + 外部 storage”总和计算;GPU 侧 external segment 必须扣除 L2,CPU 无 L2 保留完整 256 GiB。 | 两方总容量均为精确 512 GiB,开跑前 allocated=0,不用重复计入 L2 的基线做对比。 | + +上述规约是后续代码、并发测试和三机压测的验收清单。历史兼容路径可以保留,但不得 +以 fallback 名义跳过 V1/G2/G4/S2/T1 这些正确性门禁。 + ### Mooncake 对齐实验给出的性能约束 2026-07-12 的三机对齐实验使用两台 TP=2 GPU 节点和一台纯 CPU 节点,标称容量均为 @@ -70,7 +114,7 @@ E15 的 4,718,592-byte value 被旧 slot class 扩成 8 MiB,payload 利用率 - 主要落点:plan blob ABI、`value_ptrs[]`、`local_fast_put_start/local_fast_put_commit`、`get_start/get_transfer`、SGLang `write_*_to_fluxon_values` / `restore_*_from_fluxon_values`。 - **对应 KV Cache 适合 write-back 最终一致性** - 实现思路:KV Cache 的不可变、可丢失语义天然对应 Fluxon 的 master / owner / external 三层架构。master 管全局 route 和最终可见性,owner 管本机共享内存和 holder 生命周期,external 是 SGLang worker 的热路径接入层。 - - Put:native write 完成后先更新 external / owner 本地可见索引并返回 `KvFuture`,后台再推进 master route commit。`KvFuture` 成功前只表示本机 write-back 进入提交流程;失败时清理本地在途状态,退化为后续 cache miss。 + - Put:native write 完成后先更新 external / owner 本地可见索引并返回 `KvFuture`,后台再推进 master route commit。`KvFuture` 成功前只表示本机 write-back 进入提交流程;响应不确定或可能已发布时必须保留 local-visible/fence 并以同一 identity 整批 roll-forward。只有明确证明 master 从未发布且操作已经终止的 abort 才能清理本地在途状态并退化为后续 cache miss。 - Get / restore:优先查询 external / owner 本地热路径;本地 miss 时再进入远端 prefetch 和 restore。读取只 materialize 连续安全前缀,失败时 rollback 或按 miss 继续。 - 主要落点:master route、owner shared segment、external local visible index、`KvFuture`、`get_start/get_transfer/release_views`。 - **对应适配 SGLang KVCache 特化接口** @@ -252,7 +296,7 @@ blob[11] = value_ptr_9 hostless backup 的核心约束是:Fluxon 负责 GPU KV cache 之下的本机/远端 KV 层的地址分配、route 提交和生命周期管理,但真正的 KV bytes 由 SGLang native kernel 从 GPU KV cache 写入。因此 Fluxon 不能在收到 key 后立刻发布 KV route;它必须先完成 key reservation、put id 分配和 owner-local reserve slot claim,把稳定可写的 `value_ptrs[]` 通过 `plan_ptr` 返回给 SGLang。SGLang native kernel 写完这些地址后,`local_fast_put_commit` 才能把这些 slots 提交为 resident values,并发布 Fluxon KV route。 -这条 backup 路径按 write-back 最终一致性设计:native write 完成后先进入本地可见和后台 commit 流程,跨 worker / 跨节点可见性以 `KvFuture` 成功为准。提交失败不会破坏推理语义,只会让对应 page 失去 shared backing;上层清理 `storage_*` 状态后按 cache miss 处理。 +这条 backup 路径按 write-back 最终一致性设计:native write 完成后先进入本地可见和后台 commit 流程,跨 worker / 跨节点可见性以 `KvFuture` 成功为准。`KvFuture` 返回失败时,上层不得把 page 标成全局 `storage_backed`,后续可按 cache miss 处理;但 Fluxon 内部若处于响应不确定或可能已发布状态,仍必须保留 local-visible/fence 并以同一 identity roll-forward,不能把“上层不采用”误解为可以立即释放 backing。 ### 本地主副本与异步副本控制 @@ -319,15 +363,15 @@ Free | slot 上限 | `slot_size <= 512 MiB` | | refill 触发 | 当前 slot class free slots 不足时登记 pending demand 并唤醒 rebalance actor。 | | 预期容量预热 | owner 可配置 `owner_local_reserve_expected_capacity: {value_len, payload_capacity_bytes}`。启动时按 grant 内真实可用 slots 计算并申请所需 grants;SGLang 启动脚本必须等预热完成。 | -| shrink 下限 | 配置预期容量后,rebalance 不把该 slot class 缩到 `expected_grants` 以下;业务瞬时 pending demand 仍可临时增加 grant。它不是物理上限。 | -| 默认等待 | soft wait `10 ms`,hard timeout `10 s`。hard timeout 保护一次 refill/reclaim 事务,不用于掩盖 master 调度饥饿。 | +| expected capacity | 配置预期容量后,`expected_grant_count` 同时是预热目标和物理 grant 硬上限;业务压力只能触发 owner writeback/reclaim,不能把 owner 容量扩到该上限之外。只有未配置 expected capacity 的动态模式可继续按 demand 申请 grant。 | +| 默认等待 | soft wait `10 ms`,hard timeout `30 s`。hard timeout 覆盖一次有界 replica/reclaim 背压事务,不用于掩盖 master 调度饥饿,也不替代 terminal/pending 对账。 | | shrink 单位 | 整个 grant;不做 live grant compaction。 | | Moka 计费权重 | committed slot 使用 4 KiB 对齐后的实际 `slot_size`,而不是原始 `value_len`;容量驱逐因此对应真实内存占用。 | -| Moka 容量水位 | master `replica_cache_capacity_ratio`,合法范围 `(0, 1]`,默认 `0.95`;它只决定常规冷条目选择水位,不改变 owner segment 配置容量。 | -| 常规容量驱逐 | Moka 到达配置容量后选择冷条目,并通过 eviction listener 进入安全回收流程。Moka 只负责选择候选,不直接释放 owner backing。 | -| 物理 NoSpace 兜底 | refill 申请不到 `512 MiB` grant 时,按 `slot_size * required_free_slots` 计算目标权重,扣除已经在途的回收权重后调用 `evict_some(additional_weight)`;随后按 route 扫描可安全释放的 slots。 | +| Moka 容量水位 | owner `replica_writeback_hot_capacity_ratio` 控制 local hot/writeback 窗口;master `replica_cache_capacity_ratio` 只约束 `Allocation && !owner_local_indexed && lease_id.is_none()` 域。两者都不改变 owner segment 或 expected grants。 | +| 常规容量驱逐 | owner hot Moka 的 Size 事件只转移“写回任务 ownership”,不直接释放 backing;master 的环 B Moka Size 事件进入 unindexed Allocation reclaim。两个环分别闭合。 | +| 物理 NoSpace 兜底 | owner pressure actor 根据 free-slot 缺口减去 selection debt,只在这一处调用无谓词 `evict_some`(单次 ≤256 MiB、≥200 ms 间隔)启动 writeback。旧 route 全表扫描已删除;remote write 失败不进入 master drop/reclaim。 | | 容量不变量 | `evict_some` 只驱逐一部分条目,不修改 Moka `max_capacity`,也不修改 owner 配置容量。 | -| route 维护反压 | route 发布后的 prefix-index/Moka 更新进入容量 512 的有界队列,由单 actor 每批最多处理 512 项;队列满时 `put_done` 等待,避免 metadata/Moka 水位落后于 owner 物理分配并饿死 reserve RPC。 | +| route 维护反压 | route 发布后的 prefix-index/Moka 更新使用既有有界 actor;队列满时 `put_done` 等待,避免 metadata/Moka 水位落后于物理分配。它不负责 owner slot-pressure victim 扫描。 | Qwen3-VL-8B、TP=2、page size 64 的单 rank K/V value 是 4,718,592 bytes,正好是 4 KiB 的整数倍。exact-fit 后一个 512 MiB grant 可以提供 113 个 slots;旧的 @@ -517,6 +561,133 @@ sequenceDiagram - `InlineLocal` holding 从 owner 返回 start response 前已经安装;`get_transfer` 把它移交给 returned plan,`cancel_get_transfer` 则携带 holding IDs 精确释放。owner 重启或 generation 不匹配时不能继续使用旧 inline plan。 - `get_start` 只命中部分前缀时,SGLang 只能恢复 `transferable_len` 覆盖的完整 atomic groups,不能构造半个 atomic group 的 GPU KV 状态。 - `get_transfer` 返回 miss / KeyNotFound 时,SGLang 必须放弃本次 restore 并执行 rollback。 +- owner 必须为未被 `get_transfer/cancel_get_transfer` 消费的 handle 设置有界 TTL;TTL 回收与 + 显式 cancel 走同一条 plan Drop 路径,不能永久 pin local holder 或 per-key result。 + +### Batch Get 的逐 key 交集、pin 与 singleflight + +hostless restore 的 batch 通常不会完全相同。多个会话或同一会话的不同轮次会共享 +大量前缀 page keys,但各自的 batch 长度、后缀和 `atomic_group_lens` 不同。因此以 +`keys + atomic_group_lens + prefix_best_effort` 整个结构作为去重 key,只能合并完全相同的 +batch;它不能阻止两个重叠 batch 对同一 page 重复申请 prepared slot、重复发起 Get +和重复 DMA。 + +读路径必须在 owner 侧按单 key 分流,同时保留原 batch 的顺序和 group 边界。对一个有序 +required batch `R`,定义: + +```text +L = 通过 owner reclaim fence 后可以立即取得 holder 的 local-visible keys +F = 当前 owner 上已有可共享 Get 操作的 inflight keys + +LocalJoin = R ∩ L +InflightJoin = R ∩ F +Leader = R - (L ∪ F) +``` + +这里的“逐 key”只指 singleflight registry 的判定和线性化粒度,不指 RPC 粒度。 +owner 逐 key 完成 `R` 的完整分流后,必须把全部 `Leader` 按原 index 压缩成 +`leader_keys[] + prepared_targets[] + original_indices[]`,通过一次 BatchGetStart 发布;全部终态 +使用 BatchGetDone/Revoke 收敛,最后才按 `original_indices[]` scatter 回 `R`。当前 payload +backend 仍对每个 key 调用一次 `transfer_data_no_copy`,因此只能表述为“控制面已 batch、数据面 +descriptor batch 待实现”,不能表述成已按 peer/transport 成批提交。后续应直接按 peer/transport +汇总 descriptor,或使用有界 time-window 聚合兼容传输;不得为了 per-key future 在循环中逐个 +执行完整的 `GetStart -> transfer -> GetDone`。 + +`L` 只包含能在当前 owner generation 内取得稳定 `MemoryInfo` 的 +`precommit_local_visible_info` 和 `get_cached_info`。只有 master route、只有 +`local_snapshot_info`、已进入 reclaim fence,或只存在 hidden pending 但还没有可共享 +future 的 key,都不得当作 local hit。`pending_local_get_info` 属于 `F` 的生命周期, +不应通过把未发布 bytes 提前放入 `L` 来规避竞争。 + +一次 batch 的必须时序如下: + +1. owner 使用 256-shard key-control table 逐 key选择 local / join / leader;每次只持一个 + key 所属 shard 的短临界区,禁止持锁遍历 `R`,也禁止任何锁跨 `.await`。 +2. `LocalJoin` 在离开该 key fence 前 clone 对应的 `Arc`,以 resident holder 引用 pin + 住 backing。即使 route 随后被 hot demotion,该 slot 也要等本次 holder 释放后才能 + 变成 Free。 +3. `InflightJoin` 在离开 registry 前取得逐 key `Interest` guard;该 guard 必须能观察 + 同一个终态,不得另外申请 slot 或发起 DMA。prefix decision 由 guard 的所有权表达, + request future 在任一 `.await` 被取消时,`Drop` 必须自动归还 `undecided`,不得依赖 + `decision_registered: bool` 和尾部手工减计数。 +4. `Leader` 使用逐 key 原子 entry 操作先安装 shared op,再加入本轮压缩后的 + master BatchGetStart。不能先对 inflight set 做一次普通 snapshot,稍后再批量 + insert;否则两个 batch 仍可以同时观察到空集并都成为 leader。 + 若规划在 BatchGetStart handoff 前取消,`ExternalGetPlanningLeadersGuard` 必须把本轮新建且 + 仍为 `Starting` 的 op 发布为安全 miss、按 Arc identity 清 marker 并唤醒 joiner;此时尚无 + prepared target/master operation,所以不得发 Revoke,也不得留下孤儿 marker。 +5. 只有 `LocalJoin` 和 `InflightJoin` 已经取得 pin,且所有 `Leader` 都已发布 + inflight marker 后,才能对 leader 子集发起 master GetStart 和后续 payload transfer。 +6. leader 的压缩响应必须按原 index 放回与 `R` 等长的 result slots,local、joiner + 和 leader 的状态全部拼回后,才可计算 `raw_prefix_hit_len`。不得在压缩后的 + leader 列表上计算 prefix。 +7. `transferable_len` 仍使用原始 `atomic_group_lens` 向下收敛。一个 group 可以同时 + 包含 local、joiner 和 leader,但只有所有成员均可读时才能对上层发布完整命中。 +8. 超出 `transferable_len` 的后缀必须立即释放 local pin、减少 inflight waiter,并对 + 已 start 的 leader 执行 revoke。未发布的 prepared slot 必须返回 Free,不能因为该 + key 不在连续前缀内就保留到 TTL。 +9. 保留前缀的 local holder、joined future 和 leader future 一直存活到 `get_transfer` + 成功移交给 readable plan,或 `cancel_get_transfer` 明确取消。 + +请求级不得再叠加 exact-batch shared-op 状态机。每个 external handle 直接持有自己的 +`BatchPlan(keys + Local/Interest items)`;完全相同和部分重叠的 batch 都自然在 per-key +registry 合流。leader 子集在进入第一个网络 `.await` 前移交给一个注册到 owner task +registry 的 cohort task,该 task 独立完成 `BatchGetStart -> transfer -> BatchGetDone/Revoke`。 +因此 external Start RPC 被取消只会 Drop 本请求的 Interest,不会让已经安装的 leader 失去 +executor。该收缩同时删除 request 级的第二套 phase/Mutex/Notify、waiter_count、完整 key +向量结果缓存和纯聚合后台 task,但不改变公开的 start/transfer/cancel API。 + +prepared local-reserve claim 也必须由 guard 持有。BatchGetStart 明确接受的 target 逐项从 +guard disarm 并转交 per-key flight。已经收到响应、但响应长度或 target identity 异常时, +所有已返回 `get_id` 的成功项必须先移交注册 Revoke cleanup,只有明确未接受的 slots 才能 +立即返回 Free。若 BatchGetStart transport 失败且完全没有响应,owner 不知道 master 是否已经 +接受,也没有 `get_id` 可以 revoke;这类 slots 不得立即复用,当前实现隔离 65 秒,覆盖 master +60 秒 inflight Get TTL 后再尝试释放。该 TTL 隔离是未知提交点的安全兜底,不替代后续带 +request identity 的 terminal query 协议。 + +`Revoking` 状态必须保留完整 `get_id + prepared_target`;RPC 超时、响应丢失或长度/identity +不匹配时保留 marker 和 slot 并重试,只有 master 明确确认 Revoke 后才释放 slot。若 Done +已胜出,则 Revoke 失败方不得释放已经 committed 的 slot。BatchGetDone 同样必须携带原始 +`get_id` 集合幂等重试,并逐项校验响应 identity;不能在固定三次重试后把 +pending-visible slot 遗留为无 owner 状态。owner shutdown 是唯一允许停止该重试的进程级终态。 + +per-key shared op 至少要区分下列阶段: + +| 阶段 | 对 prefix / 资源的含义 | +| --- | --- | +| `Starting` | leader marker 已经对后续 batch 可见,但 master 尚未接受;joiner 只能等待,不能把它计为命中。 | +| `Started` | master 已返回成功的 `put_id/get_id` 和精确 target;可用于计算连续 prefix,但 bytes 还不得暴露给 kernel。 | +| `Finishing` | 至少一个 Interest 保留该 key;唯一 cohort executor 正在 transfer/GetDone,后续请求只能 join。 | +| `Revoking { item }` | 无 Interest 保留该 key;`item` 持有 get_id 和精确 target,直到 Revoke 明确终止并释放 slot。 | +| `Ready` | transfer、幂等 GetDone 和 local promotion 已完成;所有 waiter 共享同一个 `Arc`。 | +| `Failed/Revoked` | 终态错误对所有 waiter 一致可见;leader 只释放一次 prepared slot 和 master inflight。 | + +shared op 的 registry 清理必须同时比对 key 和 op identity/generation,只删除当前这一个 +terminal op。旧 waiter 的延迟 drop 不能删除同 key 随后创建的新 op,这与现有 +`key + Arc::ptr_eq` 的 generation 清理原则相同。同一 required batch 内即使出现 +重复 key,也只能有一个 leader/shared op;原始的多个 index 分别持有结果引用。 + +owner 侧 singleflight 是主去重边界,master 仍需要防御性地保证一个 requester 不发布两个 +local committed targets。master 防重粒度必须是 `(key, requester_owner)`,不是全局 +`key`;GPU0 和 GPU1 同时把同一 key materialize 到各自 owner 是合法的,不应被串行化。 +prepared Get 从 master GetStart 接受到 GetDone/Revoke/TTL 终态期间占有该 +`(key, requester_owner)`。 + +master 已经看到 requester 上有相同版本 live replica,或 GetDone 时另一个操作已经 +发布同版本 route,都属于可收敛竞争,不得使用 `InvalidArgument/Unknown` 当作永久 +失败。master 应返回可区分的 busy/already-exists 终态:owner 释放本次多申请的 +prepared slot,在 reclaim fence 下重新获取 canonical local holder;正在 demotion 的 key 则等待 +route 移除后从 remote replica 重试。相同 `put_id` 的 GetDone 竞争必须幂等收敛到唯一 +local route,输家不覆盖 canonical backing;不同 `put_id` 才是 stale Get,必须 revoke。 + +该路径至少要暴露 `required/local_pinned/inflight_joined/leader_started`、被省略的 +GetStart/DMA 数、suffix local-pin/waiter/revoke 数、join 等待时间以及 conflict retry 数。 +当前 owner 周期快照已暴露 active handles、per-key flights 的 Starting/Finishing/Revoking、 +`undecided/retained` interest,以及 local-reserve 的 Free/Prepared/Pending/Committed slot 数; +workload 结束后这些临时态必须在有界时间内回到基线。 +`prepared local-reserve Get target cannot replace a live replica` 和 +`prepared local-reserve Get target could not publish current route` 应该从可见错误中归零; +仅看最终 QPS 不能证明重叠 batch 已经正确去重。 ## Fluxon 本地可见索引与生命周期 @@ -524,77 +695,111 @@ Fluxon client/external 侧会维护当前进程可直接访问的 value 索引 | 状态 | 创建入口 | 生命周期 | | --- | --- | --- | -| precommit local visible | `local_fast_put_commit` 开始后,由 owner-local reserve slot 对应的 `MemoryInfo` 记录到 `precommit_local_visible_info` | 表示本次 put 的 value 已在当前进程可读,但后台 put commit 尚未最终完成;成功后转为 `get_cached_info` 中的 committed entry,失败或取消时移除。 | +| precommit local visible | `local_fast_put_commit` 开始后,由 owner-local reserve slot 对应的 `MemoryInfo` 记录到 `precommit_local_visible_info` | 表示 value 已在当前进程可读但 global publish 尚未收敛;成功后转为 committed entry。响应不确定/局部失败时保留并 roll-forward,只有证明从未发布的显式 abort 才移除。 | | committed local visible info | put commit 成功后,由 SGLang 进程内的 Fluxon external/client 将 `MemoryInfo` 记录到 `get_cached_info` | 保存 key、put version、`holder_id`、`offset`、`len` 和 owner node;后续 `get_start/get_transfer` 可以复用这份 `MemoryInfo` 构造 readable plan。 | | inline external holding | owner 判定整个 transferable batch 都在本地可见后,为每个导出 page 分配 external holding ID 并安装 holding | start response 到达 external 后由 handle 缓存;随后必须移交给 `get_transfer` plan 或由 cancel 携带 holding IDs 释放。holding 绑定 owner generation。 | | get-transfer holder | `get_transfer` 成功后绑定到 readable plan,并由 plan 持有引用 | `release_views(plan_ptr)` 后释放引用;plan 生命周期内 holder 保证对应 value 不被释放。 | +Put 的本地可见性和全局发布是两个独立的线性化点,不得把两者合并成 +“等 master 后才能本地读”: + +| 线性化点 | 条件 | 立即允许的操作 | +| --- | --- | --- | +| `local-read-ready` | native kernel 已把 bytes 写入 local-reserve slot,且对应 CUDA stream 可见性已满足;client 将唯一 `MemoryInfo` 安装到 `precommit_local_visible_info` | 同 owner 的 `local_visible_mem_holder(s)` 立即可以命中、pin 并读取该 slot,不等待 master PutDone。 | +| `global-route-ready` | master PutDone 已按 key/version 发布 route,并完成必要的 route maintenance | 该 slot 才进入 `Committed(route_live=true)`,可被其它 owner 通过全局 route 发现,并可进入 owner-hot Moka 参与后续分级。 | + +因此延后的只是 global committed 和 hot admission,不是 local read。之所以不在 +`local-read-ready` 时立即加入 owner-hot Moka,是因为 Size eviction 可能马上启动 +replica/demotion/reclaim;此时 master route 还未发布,会使回收协议无法用同一 +`put_id + backing identity` 证明对象归属。precommit entry 本身持有 resident holder,已经 +足以保证本地读期间地址稳定,不需要依赖 hot Moka。 + +同一 atomic/TP cohort 可以逐项进入 `local-read-ready`,但 batch Get 仍必须在原 +`atomic_group_lens` 边界上判定可恢复前缀;这保留了“本地已写页立即可复用”, +又不会向 SGLang 恢复半个 radix node。master 发布不确定或部分成功时保留 local-visible +entry/fence 并整批 roll-forward;只有明确从未发布的 abort 才能移除 precommit。已经取得的 +local-read holder 仍可安全完成当前读,最后一个 holder 释放后才能回收 slot。 + 收到 `local_cache_holder_id` 后,SGLang 进程内的 Fluxon external/client 使用 `holder_id`、`offset` 和 `len` 构造 `MemoryInfo`,并记录到自身 `get_cached_info`。`MemoryInfo` 记录当前进程访问该 value 所需的地址信息和释放动作;后续 `get_start` 命中 `get_cached_info` 时,可以直接把这份 `MemoryInfo` 纳入本次 get 结果,`get_transfer` 再把这些 value 地址写入 readable plan。底层内存的回收由 owner route、holder 引用和 owner-local reserve grant 生命周期共同约束。 内部 `MemoryInfo.holder_id` 与 external holding ID 属于两个生命周期域。resident local-reserve page 的内部 holder ID 可以为 0;每次 external export 仍由 owner 分配非零、递增且独立的 holding ID,同一内部 backing 的并发导出也不能复用 ID。这样 cancel/delete ACK 可以按本次 export 精确对账,多个 resident page 不会因内部 ID 相同而覆盖 holding。external 在构造 inline holder 前还必须验证 response generation 与当前 mmap owner generation 一致,并验证 `offset + len` 位于 mapping 范围内。 -`precommit_local_visible_info` 只覆盖 commit 进行中的短窗口。put commit 成功并确认 holder 后,会移除 precommit entry 并记录 committed entry;如果 commit 失败,precommit entry 必须被清理,不能作为后续 storage-backed 恢复来源。 +`precommit_local_visible_info` 覆盖 local-ready 到 global route/promotion 完成之间的窗口。 +put commit 成功后会原子转入 committed index;PutDone 响应不确定或局部失败时 publish job +必须继续持有 precommit/fence 并以同一 identity roll-forward,不能清理可能已被 master 发布的 +backing。只有明确证明 master 从未发布且操作已终止的 abort 路径才可移除 precommit。 ## Local-side 主动驱逐与安全回收 -local-side 主动驱逐不是在 Moka eviction callback 中直接释放内存。无论候选来自常规 Moka capacity eviction,还是 owner refill 遇到物理 NoSpace 后显式调用 `evict_some`,都必须经过同一套 master/owner 安全回收协议。其外部可见不变量是:已经释放或复用的 backing 不会仍然作为一个可访问 route 提供给新的 put/get/replica;如果暂时无法证明可以安全释放,则候选保持 pending 并退避重试,队列关闭等无法继续推进的路径才把当前版本放回 Moka。 +local-side 主动驱逐分成“owner 选择冷 source”和“master/owner 安全删除该 source”两个 +阶段。owner hot Moka 的 Size removal 或 pressure actor 的 `evict_some` 只完成候选选择; +dispatcher 随后提交完整、精确的 atomic/TP source cohort。该容量事务不查询 CPU replica, +也不等待 remote append:有其它 replica 时只删当前 owner source,没有其它 replica 时允许 +删除最后一份 cache route,后续 Get 正常 miss/recompute。proactive remote replica 是独立的 +命中率优化,失败只代表少一份可命中的 CPU copy,不拥有 owner 容量释放的否决权。 ### 触发与职责边界 -- Moka 使用 `NodeValueReplicaDesc.weight_bytes` 计费;对于 committed slot,该权重对应真实 `slot_size`。 -- Moka 只做冷条目选择。eviction listener 把 `owner_node_id + key + put_id + weight` 放入 safe reclaim queue,不直接 drop `MemHolder`,也不直接释放 slot。 -- `evict_some(requested_weight)` 的参数是“希望移除的权重”,不是目标 cache size;它沿 LRU 顺序驱逐到满足请求或没有候选为止,并返回实际驱逐权重。由于条目必须整项驱逐,返回值可以大于请求值。它不会通过临时调低再调高 `max_capacity` 来制造驱逐,因此 owner/Moka 配置容量在调用前后保持不变。 -- `eviction_reclaim_pending_weight` 记录已被 Moka 选中、但尚未完成物理回收的权重。NoSpace 兜底只对 `requested_weight - pending_weight` 调用 `evict_some`,避免对同一轮压力重复过量驱逐。 -- activity、holder 或短暂 owner Busy 导致候选无法回收时,不立即插回仍然超限的 Moka。该候选继续计入 pending weight,并以 `10 ms` 起步、最大 `1 s` 的指数退避重新进入 safe reclaim queue;route/put_id 已变化时结束 pending,不复活旧版本。这避免同一个热 key 在 eviction 与 reinsert 之间形成高频循环。 -- safe reclaim queue 满或关闭时,入口立即回滚 pending weight,并且仅在 route 仍是相同 `put_id`、owner replica 仍 live 时把条目重新插回 Moka;旧版本候选不会被复活。 +- owner hot Moka 以 committed slot 的真实 `slot_size` 计费,value 只保存 + `Weak`,不因热度索引额外 pin backing。 +- synchronous eviction callback 只发送 `(key, put_id, Weak, weight)` 到 lossless metadata + channel;callback 不取 key-control、不查 index、不展开 cohort、不 RPC/RDMA。 +- async dispatcher 从当前 local index point-pin `Arc`,在锁外展开完整 atomic/TP cohort, + 构造 `OwnerSourceEvictionMember { key, put_id, backing }`;不使用 cohort-wide 同步锁。 +- `evict_some(requested_weight)` 是 owner slot-pressure actor 的唯一生产调用点;参数是本轮 + 希望选择的字节数,不是新容量。单次 ≤256 MiB、最短间隔 200 ms,调用前后 + `max_capacity`、owner 配置容量和 expected grants 均不变。 +- `selection_debt_bytes` 覆盖已离开 hot window、仍由 source-delete/retry 状态机拥有的字节。 + pressure actor 只选择 `free-slot deficit - selection debt`,避免重复超选。 +- `BatchEvictOwnerSourceReq/Resp` 使用 Msg ID `3069/3070`。RPC 不可达、activity Busy、 + partial overlap 或 actor 暂不可用都按同一 exact identity 有界重试,不重新 append; + physical Free、stale/obsolete 或安全恢复 hot 是 selected debt 的唯一终态。 +- active size class 为 `0` 时是尚未分配的正常 idle,pressure actor 静默等待;当前只支持 + `1` 个 active class;`>1` 时停止选择并限频报错,不能用全局 Moka 在多 class 中猜 victim。 ### 安全回收时序 ```mermaid sequenceDiagram - participant C as Moka cache controller + participant H as owner hot Moka + participant O as GPU owner dispatcher participant M as Fluxon master - participant O as Fluxon owner - - C->>C: capacity eviction / evict_some 选择候选 - C->>M: enqueue(key, put_id, owner, weight) - M->>M: 校验 route/version/backing - M->>M: try_install_reclaim(key) - alt put/get/replica 在途或已有 reclaim fence - M->>M: 保留 pending weight,指数退避后重试 - else per-key activity 已静默 - Note over M: fence 存在期间拒绝新的 put/get/replica - M->>O: Prepare(item, epoch, exact backing) - O->>O: 隐藏本地索引并检查 pending put / holder - alt Busy 或 Stale - O-->>M: Busy / Stale - M->>O: Abort(需要时) - M->>M: 当前版本仍有效则退避重试;旧版本结束 pending - else Prepared - O-->>M: Prepared - M->>O: Commit - O->>O: 校验并释放精确 slot/backing - O-->>M: Committed - M->>M: 删除相同 put_id 的 owner replica/route - M->>O: Finalize - O-->>M: Finalized - M->>M: 清除 master reclaim fence - end + participant R as existing local reader + + H->>O: Size event(key, put_id, Weak, weight) + O->>O: point-pin current source / expand exact cohort + O->>M: BatchEvictOwnerSource(exact cohort) + M->>M: validate caller generation, closure and backing + M->>M: install all master activity fences + M->>O: cohort Prepare + alt reader already holds source + O-->>M: Busy; restore visible index + R-->>O: holder released + M->>M: bounded retry of the same identity end + O-->>M: all Prepared + M->>O: cohort Commit + O->>O: Prepared -> Releasing under key shard + O->>O: unlock key; release route+holder in one pool update + O->>O: Releasing -> Committed + M->>M: remove exact owner routes; last route may disappear + M->>O: cohort Finalize ``` Master 与 owner 两侧分别承担下面的正确性约束: | 约束 | 当前实现 | | --- | --- | -| 并发线性化 | Master 为每个 key 统计 put/get/replica activity。只有三个计数都为零且没有其它 reclaim 时才能原子安装 reclaim fence;安装后新的 put/get/replica 不能取得 activity lease。replica append 在完整任务期间持有 lease,避免远端副本尚未完成时回收 local backing。 | +| 并发线性化 | Master 为每个 key 统计 put/get/replica activity。只有三个计数都为零且没有其它 reclaim 时才能原子安装 reclaim fence;安装后新的 put/get/replica 不能取得 activity lease。已经取得 source holder 的读或 replica transfer 必须先排空,但 transfer 是否成功不改变容量事务义务。 | | 版本隔离 | 每个候选携带 `put_id` 和 reclaim `epoch`。Master 在安装 fence 前、Prepare 后以及删除 route 前重复检查当前 route 仍是同一版本。 | | backing/slot 防 ABA | committed slot 必须同时匹配 owner、`grant_id`、`slot_index` 和 `slot_size`;旧驱逐请求不能释放新版本或已经复用的 slot。 | -| 现有读者排空 | Owner Prepare 在同一个 key-control lock 下先从 `get_cached_info` 隐藏索引,阻止新本地读者;随后要求 `Arc::strong_count(mem_holder) == 1`。若已有 get/plan 持有引用,则恢复索引并返回 Busy。 | +| 现有读者排空 | Owner Prepare 只持该 key 所属的短 sharded key-control fence,先从 local index 隐藏 backing,再要求唯一 holder。若已有 get/plan/transfer pin,则恢复索引并返回 Busy。 | | 写入冲突隔离 | Owner Prepare 遇到 `local_puts`、`precommit_local_visible_info` 或 `external_pending_puts` 时返回 Busy,不会回收正在写入或尚未发布完成的 value。 | -| 精确物理释放 | Owner Commit 持有 key-control lock,使用 `Arc::try_unwrap` 取得唯一 backing,并再次断言 slot identity 后释放 owner-side committed-slot route、resident holder 和内存引用,使该 slot 可以回到 Free。identity 不一致按内部不变量失败,而不是继续释放未知 backing;整个 grant 的 mmap/registered memory 仍按独立的 grant 生命周期回收。 | +| 精确物理释放 | Owner Commit 在 key-shard 内只切换 `Prepared -> Releasing`,随即释放 key 锁;之后在一次 slot-pool 临界区同时释放 committed route ref 与 resident holder,再回到 key shard 标记 `Committed`。这避免 key-shard mutex 嵌套 slot-pool mutex,也不暴露两次 pool update 间的中间状态。 | | route 更新顺序 | Owner Commit 释放物理 backing 后,Master 只删除相同 `put_id` 且 backing identity 相同的 replica;这个短窗口仍受 master reclaim fence 保护,对新请求不可访问。Master 更新 route 后才 Finalize owner fence。 | -| 幂等与失败关闭 | Prepare/Commit/Abort/Finalize 都按 `item + epoch` 判定已应用状态。Prepare 或 Commit RPC 不确定时通过 Abort 查询/收敛;如果 owner 已经 Commit,则不能回滚 backing,而是继续删除 route 并 Finalize。Abort/Finalize RPC 失败会退避重试;未收敛时保留 fence,优先阻塞该 key 而不是暴露已释放内存。 | +| cohort 事务 | owner exact source deletion 和 master allocation capacity reclaim 都以一个 cohort request 进入 lossless queue。全组 master fence 与 Prepare 要么全部取得、要么全部撤销;一旦任一 Commit 已成功,只允许 roll-forward 完成其余成员。 | +| 幂等与失败关闭 | Prepare/Commit/Abort/Finalize 都按 `item + epoch` 判定已应用状态。RPC 不确定时重放同一 identity;已经 Commit 的 backing 不可回滚。未收敛时保留 fence,优先阻塞该 key 而不是暴露已释放内存。 | +| partial/replay 判定 | 全部 source 已不存在是 `Completed`;部分不存在只有在完整 exact identity 已在 reclaim registry 中时才是 `AlreadyInProgress`。无对应在途事务返回 `Stale`,部分 overlap 返回 `RetryableBusy`,不能把残缺 cohort 当作新事务接受。 | | 失败候选收敛 | 暂时 Busy 的当前版本保持 pending 并退避重试,不立即插回 Moka;stale route 或版本变化直接结束 pending。只有队列关闭等无法继续推进的路径,才在 route 仍匹配 `put_id` 且 owner replica live 时重新插入,避免旧条目覆盖新版本。 | 从可观察状态看,回收事务允许 Owner Commit 与 Master route 删除之间短暂存在“owner slot 已回收到 allocator、可以复用,但旧 route 对象尚在”的内部状态,但对应 key 的 master reclaim fence 在整个窗口内拒绝新操作;安装 fence 之前已经取得 lease 的 get/put/replica 又必须先结束。因此调用方不会通过该 route 访问已经释放或复用的 backing。 @@ -603,15 +808,50 @@ Master 与 owner 两侧分别承担下面的正确性约束: 内存/并发正确性与“驱逐后是否仍有另一份可恢复数据”是两个不同契约: -- `OwnerReclaimReason::Reserve` 用于物理 NoSpace 下的 route-scan 回收。它只选择存在另一份非 tomb replica 的 key,因而 local backing 释放后仍有 recoverable replica。 -- Moka eviction listener 产生的请求使用 `OwnerReclaimReason::CapacityEviction`。当前实现允许它删除最后一份 cache replica;最后一份被删除时,Master 同时删除整个 route,后续表现为正常 cache miss。这与本文前述“KV Cache 副本可丢失,miss 后重新计算”的缓存语义一致。 -- NoSpace 处理会先调用 `evict_some`,再执行 `Reserve` route-scan;其中 `evict_some` 产生的 listener 请求仍属于 `CapacityEviction`。因此不能因为后半段 route-scan 有副本检查,就推导整个 NoSpace 兜底都保证保留 remote replica。 -- 因此,当前已经保证并发访问、版本和 slot 复用安全,但没有对所有 `CapacityEviction` 保证“local 驱逐后 remote side 一定保留一份”。write-through 已成功建立 remote replica 时可以从 remote side 恢复;replica append 尚在途时 activity lease 会阻止并发回收。 -- 如果产品契约改为“任何 local-side 主动驱逐都必须可从 remote side 恢复”,则必须让 `CapacityEviction` 对 active/local owner 同样要求 `has_recoverable_replica`,并补充无远端副本、远端 tomb、replica append 并发及 RPC 故障注入测试。不能只依赖 write-through 通常会产生远端副本这一经验条件。 -- Put `atomic_group_lens` 只保证副本准入不主动切组,不能单独证明 CPU 侧整组已经完成。下一阶段的可恢复优先驱逐需要记录组内 remote append 完成状态,并让 GPU Moka / `CapacityEviction` 优先选择已有完整 CPU 副本的 group;远端只完成部分 pages 的 group 不能作为“驱逐后仍可恢复”的依据。 +- **环 A(owner-indexed source)**:hot removal/`evict_some` 只是 owner 的 victim selection。 + owner 把完整 exact cohort 交给 master 做 source route fence/delete;不要求 CPU 副本。 + 有其它 replica 时只删除该 source,没有其它 replica 时允许最后 route 消失。RPC/Busy 暂时 + 失败时 source 保持可读并按同一 identity 重试;remote write 失败不进入容量失败补偿。 +- **环 B(master-only/unindexed Allocation)**:master 有界 Moka 的原生 Size eviction 可以删除最后 + 一份 cache route,后续正常 miss/recompute;这是 cache 容量语义,与环 A 的结果一致, + 但 victim authority 与 backing 释放位置不同。该分类只取决于 backing/index/lease + 语义,不取决于 CPU/GPU 或 active/remote-only 节点角色;当前默认置换策略为 + Moka TinyLFU,正确性不依赖具体 victim 顺序。 +- 旧 `OwnerReclaimReason::Reserve` route 全表扫描、`reclaim_before_grow` 和 master 侧手动 + `evict_some` 均已删除。NoSpace 只返回明确可重试结果;owner pressure actor 等待真实 Free + slot,不通过增大 grant 数绕过 configured capacity。 +- `atomic_group_lens`/Put group 是 source cohort 描述;master 在 source deletion 当下验证 + 请求集合与当前 atomic/TP closure 完全一致。它不从单 key补全 cohort,也不要求共同 CPU + owner;任一 member stale 时整组不 Commit。 ### 当前验证证据与覆盖边界 +2026-07-17 对当前 Fluxon 工作树完成 direct source-delete 本机回归。使用 +`CARGO_TARGET_DIR=/tmp/fluxon_target_direct`、`-j 4` 和 closed-sdk runtime,最新代码 +`cargo test -p fluxon_kv --lib --no-run` 通过;exact source cohort 定向测试 `7/7`,owner +slot/reclaim 定向测试 `19/19`,`fluxon_kv --lib` 全量为 +`171 passed, 0 failed`(193.19s)。覆盖有/无 CPU replica、最后 route 删除、stale backing、 +partial replay-only、cohort fence all-or-nothing、retry exactly-once、`Releasing` 和 +route+holder 单次 pool update。全量测试还修复了 `0 active class` 被误判后每 10ms 报错的 +idle actor 空转。本机回归本身不替代 release 三机部署、真实 RDMA 与 E44 自然冷跑,后者 +按下一段独立验收。 + +上述独立验收已在 2026-07-17 的 E44 r9 完成。三机容量保持 +GPU0/GPU1/CPU=`128/128/256 GiB`,两 GPU 各固定 `232` grants、`26,216` slots; +S96×T24、concurrency 24、session-stream、无预热自然冷跑为 `2304/2304` 成功,QPS +`5.609336`,L1/L2/L3/总命中率 `5.4060%/0%/54.6878%/60.0939%`。CPU owner 被选为 +唯一 proactive replica target(`77,384` 个),并实际为两个 GPU requester 提供 +`183,923` 个 key、`808.26 GiB` Get source 数据。 + +容量闭环终态为:GPU0/GPU1 direct source commit `130,540/145,888`,dispatch failure +均为 0;Free slots `466/488`,Prepared/Pending 均为 0;active flights、retry entries、 +selected 和 selection debt 全为 0;grant 数始终等于 expected `232`。业务错误、refill +timeout、P2P、panic、OOM 和 scheduler exception 均为 0。日志中的 recoverable +`not_ready` 只对应最后一份 route 已按容量策略删除后的正常 miss/recompute;所有真正提交的 +prefetch 均以非零 prefix 成功,没有 TP prepare reject 或 transport error。该结果证明环 A +的 direct source-delete 正确性和容量收敛,不证明 selective CPU replica 已达到 Mooncake 的 +命中率;后者仍是独立性能策略,不能反向成为 Free 的前置条件。 + 三机 SGLang 正式压力还覆盖了 expected-capacity 与常规驱逐的组合。E16a4 使用两台 TP=2 GPU owner 和一台 CPU-only owner,标称容量保持 128/128/256 GiB;两 GPU 各预热 207 grants, 正式请求期间各按 pending demand 增到 208 grants。1152/1152 请求成功,QPS 4.845,两侧 @@ -952,9 +1192,10 @@ recoverable-first eviction 优先选择已有完整 CPU 副本的 group,才能 当前实现把提前写回的热度观察点下沉到 storage owner。每个 GPU owner 维护一个逐 key 的 owner-local hot Moka;本地 committed value 进入该 tier,`InlineLocal` 等 owner 本地命中会刷新 -热度。hot tier 发生 `RemovalCause::Size` 时,owner 立即 pin 当前 `put_id` 的 backing,再把该 -value 交给现有 replica actor 异步写入 remote CPU owner。Master T2 resident Moka 仍是唯一的 -物理回收决策入口。 +热度。hot tier 发生 `RemovalCause::Size` 时,callback 只把 key/put_id/Weak/weight 交给 +lossless metadata channel;离开 Moka housekeeper 后,异步 dispatcher 才逐 key point-check、 +pin 当前 backing、展开 cohort,并交给 replica actor 写入 remote CPU owner。Master 仍负责 +remote route 成功后的 cohort demotion/reclaim 仲裁。 ```mermaid sequenceDiagram @@ -969,7 +1210,7 @@ sequenceDiagram S->>G: InlineLocal hit G->>H: touch current entry H->>G: Size eviction(key, put_id) - G->>G: key fence + version check + Arc pin + G->>G: async dispatcher: DashMap point-check + Arc pin G->>M: put_append_start(key, put_id) M-->>G: reserve remote-only target G->>C: RDMA transfer @@ -1016,10 +1257,10 @@ replica_cache_capacity_ratio: 0.95 | 场景 | 当前处理 | | --- | --- | -| hot eviction 与 T2 reclaim 竞争 | 两者使用同一个 `owner_key_control` fence。reclaim 先取得 fence 时,hot eviction 放弃 stale source;hot eviction 先 clone `Arc` 时,reclaim 的唯一强引用检查返回 Busy,等 replica 任务释放 pin 后再重试。 | +| hot eviction 与 T2 reclaim 竞争 | owner-hot pin 不取全局 `owner_key_control`。dispatcher 在 DashMap shard read guard 内校验 current identity 并 clone `Arc`;pin 先发生时 reclaim remove 后的唯一强引用检查返回 Busy,Prepare 先发生时 dispatcher 看到 index 缺失且 live Weak,按 `RetryableReclaimFence` 退避,绝不从 Prepared 升级 Weak。 | | 版本替换、delete、显式失效 | eviction listener 只消费 `RemovalCause::Size`。`Replaced` 和 `Explicit` 不创建 replica;reclaim/delete 按 `put_id` 条件失效 hot entry,不能删除随后安装的新版本。 | -| 旧事件与重复事件 | listener 同时校验 `put_id` 和 `MemoryInfo` identity;dispatcher 入队前再次校验当前 owner index。`(key, put_id)` guard 覆盖排队、transfer 和 append-done 全周期。 | -| 控制面阻塞 | Moka callback 只完成 fence 内 pin 和容量 4096 的事件队列 `try_send`,不等待 RPC/RDMA;dispatcher 再进入现有容量 128 的 replica task queue。事件队列满时计入 dispatch-failed 并立即释放 pin,避免积压事件阻止 T2 reclaim。 | +| 旧事件与重复事件 | listener 携带 eviction entry 的 `put_id + Weak identity`;dispatcher 以当前 owner index 再校验。`(key, put_id)` guard 覆盖排队、transfer 和 append-done 全周期。 | +| 控制面阻塞 | Moka callback 只向 lossless 轻量 metadata channel 发送事件,不点查 index、不展开 cohort、不 pin、不等待 RPC/RDMA。dispatcher 完成 point-pin 后再进入容量 128 的 replica task queue;RetryableCold 按 owner committed identity 去重并退避。 | | append start busy key | owner-hot 任务遇到 `KeyBeingWritten` 时最多尝试 3 次,重试间隔为 25/50 ms。其它错误不做这一层重试;最终失败释放 pin,保留 GPU primary,不会把失败任务解释为 CPU replica 已完成。 | | 可观察性 | owner 每 30 秒记录 hot capacity/weighted bytes、Size eviction、enqueued/completed/already-satisfied/failed/obsolete、dispatch-failed、inflight 以及 stale/reclaim/duplicate skip 计数。CPU 数据面完成仍以 `put_append_done appended=true` 和 master target 计数为准。 | @@ -1190,9 +1431,14 @@ owner/client receiver 改为 WaitSet 后虽完成 1152/1152,QPS 降至 6.6932 #### E16ay Get-target 压力与 local reserve 物理容量闭环 -local reserve 的 expected capacity 是下限而非硬上限。Put 并发需求可使它从配置的 grant 数 -继续扩张;后续 slot 回收只让 grant 内部变空,并不会自动把这段 512 MiB 物理 allocation -归还 master segment allocator。原 shrink actor 还只检查队尾 grant,并要求连续全空 5 秒。 +> 本节记录 E16ay 当时的历史实现,不是当前容量规约。后续修复已经把 configured +> `expected_grant_count` 改为硬上限,并删除 route 全表扫描;当前行为以本章开头规约表和 +> “Local-side 主动驱逐与安全回收”章节为准。 + +E16ay 当时 local reserve 的 expected capacity 是下限而非硬上限。Put 并发需求会使它从配置的 +grant 数继续扩张;后续 slot 回收只让 grant 内部变空,并不会自动把这段 512 MiB 物理 +allocation 归还 master segment allocator。原 shrink actor 还只检查队尾 grant,并要求连续全空 +5 秒。 另一方面,CPU -> GPU remote Get 的 target 仍是 master 直接从请求 owner 的普通 allocator 分配。因此系统可能同时出现: @@ -1226,6 +1472,80 @@ pending 与 owner-hot demotion 都为 0。配置的 owner 容量、resident/hot expected 下限没有改变。这证明同步归还空 grant 可以闭合 Get-target 物理 headroom,但 QPS 仍比双 GPU baseline 低 0.79%、比 Mooncake 低 1.33%。 +#### 单 KV slot 分级循环(取代整 grant Get-target 让位) + +E16ay 的整 grant 让位只是在旧 Get target 仍从 master 普通 allocator 分配时的兼容方案, +不是最终的缓存分级语义。`512 MiB` grant 只是 local-reserve 的物理容器,不应成为 KV +驱逐或恢复的最小单位。多个 grant 中的所有 committed KV slot 已由同一个 owner-hot Moka +按 key、版本和实际 slot weight 统一管理;因此正确闭环是逐 KV slot 循环: + +```text +任意 grant 的 Committed slot + -> 跑出 owner hot window + -> owner 展开完整 exact atomic/TP source cohort + -> BatchEvictOwnerSource + -> master activity fence + owner holder drain + -> owner route 引用与 resident holder 一次 pool update 归还 + -> master 删除 exact source route + -> 该 slot 立即 Free + -> 后续 remote Get 直接 claim 这个 Free slot +``` + +CPU proactive replica 可以在这条路径之前、期间或完全不发生;它只改变删除 source 后还能否 +remote hit,不是释放 slot 的前置条件。 + +这条路径不等待同一 grant 的其它 slot 释放,也不排空或归还整个 grant。普通 idle shrink +仍可在 grant 已经自然全空且高于保留下限时回收物理 allocation,但它不参与 Get 的正确性 +或前进性。 + +Moka size eviction 是冷候选 ownership transfer,不能被当作可丢失通知。如果触发 key 的 +atomic/TP cohort 元数据暂不完整,owner 保留同一个 selected identity,在有界 retry actor 中 +等待当前 route/metadata 可构造完整 cohort;不能退化成逐 key source delete,也不能重新进入 +replica append。RPC/Busy/partial overlap 时 GPU route/holder 保持 live,并且事件必须以 +handoff、committed、restored、obsolete 或 retry 状态可对账,不能让 slot 永久留在 hot cache +之外。 + +remote Get 的 local-side target 使用与 hostless Put 相同的全 pool slot allocator;allocator +可以从任意 grant 取一个匹配 `slot_size` 的 Free slot。没有 Free slot 时,复用现有 Moka +候选与 owner 两阶段 fence,逐 KV reclaim 所需数量的 slot,而不是选择某个 grant drain。 +slot 状态机和失败契约如下: + +| 阶段 | 约束 | +| --- | --- | +| GetStart | client 先 claim `Free -> Prepared`,把精确的 `grant_id/slot_index/slot_size/address` 交给 master;master 校验 owner 和 grant 几何,不能改用另一个 target。 | +| transfer 完成 | `Prepared -> Pending`,唯一 resident `MemoryInfo` 放入 hidden pending-get 表;此时 bytes 不得通过 local-visible index 暴露。 | +| GetDone 成功 | master 以 key/version/owner CAS 发布 committed-slot route,并确保 resident Moka entry 已可见;client 再把同一 `MemoryInfo` 原子移入 committed index、`Pending -> Committed`,并加入 owner-hot Moka。 | +| transfer/GetDone 明确失败 | revoke master inflight,移除 hidden pending;最后一个 `MemoryInfo` holder 归还后单 slot 回到 Free。 | +| GetDone 响应丢失 | 保留 hidden pending,用同一 `get_id` 重试幂等终态;不能猜测失败并释放可能已经被 master 发布的 slot。 | +| 并发或旧版本 | 同 key+owner 只能有一个 live committed route;CAS 输家不覆盖现有 backing。delete/reclaim 按 put id 清理 hidden pending,避免 master 已发布而 client 尚未 promote 的窗口泄漏。 | +| owner source eviction | 完整 exact cohort 可直接请求删除当前 owner source,不依赖 CPU route;最后一份 cache route 也可删除。master fence 与 holder drain 完成前 slot 不得复用。 | + +hostless Put 也必须经过同一发布门禁。`local_fast_put_commit` 先把写完的 slot 置为 +`PendingLocalVisible`,只允许当前 owner 本地读取;master PutDone 已发布 route 并同步完成 +resident Moka admission 后,client 才执行 `PendingLocalVisible -> Committed(route_live=true)`。 +同一 batch 的成功成员要先全部完成 promotion,再统一加入 owner-hot Moka,避免第一个成员刚 +admit 就被容量淘汰,而其 route 或 atomic/TP cohort 仍未完整发布。PutDone 明确失败或响应 +结果不确定时都保留 pending/fence,并使用同一操作身份重试;不能释放可能已经被 master +发布的 backing,也不能把部分 item 的错误当作整批可回滚。 + +发布生命周期必须以 batch/job 为单位持有,而不是每个 key 各自 fire-and-forget。一个 +`OwnerLocalPublishJob` 持有整批 master key reservations;external local-first 路径还持有 +整批 `ExternalPendingPutCtx` 和 owner reclaim fences。PutDone 响应不确定、响应长度/identity +不一致或任一 item 未达终态时,job 保留全部状态并以 25ms~1s 退避重试。全部 master route +成功后才开始 local promotion;若取消或局部错误发生在 promotion 中间,下一轮接受已经 +promoted 的成员并继续其余成员,只向前收敛。所有 promotion 完成后才统一 owner-hot +admission。只要任一 item 声明 atomic group,而 job 未包含连续、同序的完整成员,就禁止 +退化到逐 key PutDone;不得用“部分成功”换取半组可见性。 + +`Committed` slot 的可复用条件仍是 `route_live == false && holder_ref_count == 0`;释放 route +与释放 holder 各执行一次,任意先后顺序都不能提前复用。Get 使用 local-reserve slot 不占旧的 +master 普通-allocation durable quota;旧 quota token 则必须绑定普通 route 生命周期,在 +revoke、失败、替换或删除时恰好归还一次。 + +容量语义保持不变:GPU owner 仍是配置的 `128 GiB`,CPU owner 仍是 `256 GiB`;该改造 +不调整 `contribute_to_cluster_pool_size.dram`、resident/hot Moka capacity 或 expected grant +数量,只让完成 exact source deletion 的单个 KV slot 立即回到同一 size class 的 Free list。 + #### E16az external local-IPC busy-poll 验收 E16ay 的两个 GPU owner 仍分别产生 147,124/150,701 条 iceoryx2 @@ -1340,6 +1660,14 @@ Put admission 的随机 identity 必须跨 TP rank 稳定。物理 storage key restore。不能直接使用较长 rank 的 handle,也不应因为尾部差异把两个 rank 已共同命中的 前缀全部作废。 +`get_start` 长度一致只完成了 intent 协商,不能作为 restore 的最终提交点。每个 rank 在 +`get_transfer` 返回可用 plan 后必须再进入一次 TP commit gate;只有所有 rank 都成功,plan +才可进入 ready-prefetch、radix node 和 layerwise restore。任一 rank 超时、P2P 失败或 plan +缺失时,所有 rank 统一取消 handle、释放已成功 rank 的 views,并把本轮 restored-token 数置为 +0,按共同 cache miss 重算。这个门禁必须位于任何 rank 发布 restored prefix 之前,禁止一侧 +restore、另一侧 recompute。异步 CUDA descriptor submission 的错误也必须在消费 prefix 前对 +所有 rank 可见;已经修改临时 node/slot 的实现必须全 rank 回滚后才能继续调度。 + ## 失败处理 | 场景 | 必须动作 | @@ -1348,7 +1676,7 @@ restore。不能直接使用较长 rank 的 handle,也不应因为尾部差异 | `local_fast_put_commit` 返回 future 后后台失败 | SGLang 清理 `storage_staged/storage_pending/storage_local_ready`,必要时删除已 evicted 的 dead leaf。 | | `get_start` 后放弃 restore | 调用 `cancel_get_transfer(handle)`,释放 get-start 持有的 owner/external 资源。 | | `get_start` 只命中部分前缀 | 只允许恢复 `transferable_len` 覆盖的完整 atomic groups;后续 page 按 miss 处理。 | -| `get_transfer` 报 key miss | SGLang rollback 当前 restore,不继续构造半个 node 的 GPU 恢复。 | +| 任一 TP rank 的 `get_transfer` 失败或 plan 缺失 | TP commit gate 在所有 rank 上拒绝发布;释放成功 rank 的 views,统一按 0-token miss 重算。 | | `get_transfer` 成功后 native restore 失败 | 先 `release_views(plan_ptr)`,再执行 SGLang rollback;此时 handle 已被消费。 | | CUDA host registration 失败 | direct path 同步失败,不能降级为未注册 host memory。 | | `plan_ptr` 类型用错 | `local_fast_put_commit`、`put_abort`、`release_views` 都按 registry entry 类型校验并 fail fast。 | diff --git "a/fluxon_doc_cn/design/teststack_2_Benchmark\347\233\221\346\216\247\345\267\245\345\205\267\351\223\276\344\270\216AIPerf\346\216\245\345\205\245\350\247\204\345\210\222.md" "b/fluxon_doc_cn/design/teststack_2_Benchmark\347\233\221\346\216\247\345\267\245\345\205\267\351\223\276\344\270\216AIPerf\346\216\245\345\205\245\350\247\204\345\210\222.md" new file mode 100644 index 0000000..37cb6c6 --- /dev/null +++ "b/fluxon_doc_cn/design/teststack_2_Benchmark\347\233\221\346\216\247\345\267\245\345\205\267\351\223\276\344\270\216AIPerf\346\216\245\345\205\245\350\247\204\345\210\222.md" @@ -0,0 +1,565 @@ +# Benchmark 监控工具链与 AIPerf 接入规划 + +> 状态:设计阶段 +> 调研基线:2026-07-10 +> AIPerf 基线:[`ActivePeter/aiperf:teleai`](https://github.com/ActivePeter/aiperf/tree/teleai),提交 [`d72160e20957013d6608afcc88ed24100cb27dc5`](https://github.com/ActivePeter/aiperf/commit/d72160e20957013d6608afcc88ed24100cb27dc5) + +相关文档:[TestStack 架构与 CI 测试流程](./teststack_1_当前架构与CI测试流程.md)、[本地文件日志与 Greptime OTLP 导出链路](./log_1_本地文件日志与Greptime_OTLP导出链路.md)。AIPerf 能力判断依据固定提交下的 [architecture](https://github.com/ActivePeter/aiperf/blob/d72160e20957013d6608afcc88ed24100cb27dc5/docs/architecture.md)、[API endpoints](https://github.com/ActivePeter/aiperf/blob/d72160e20957013d6608afcc88ed24100cb27dc5/docs/reference/api-endpoints.md)、[server metrics](https://github.com/ActivePeter/aiperf/blob/d72160e20957013d6608afcc88ed24100cb27dc5/docs/server-metrics/server-metrics.md) 和 [profile exports](https://github.com/ActivePeter/aiperf/blob/d72160e20957013d6608afcc88ed24100cb27dc5/docs/tutorials/working-with-profile-exports.md)。 + +## 1. 结论 + +Fluxon 当前已经具备 benchmark 编排、终态结果、服务指标、日志和常驻 UI,但这些能力仍分布在不同链路中。现有链路适合 KV、MQ、RPC 和 FS benchmark,缺少生成式 AI 请求的 TTFT、ITL、token throughput、goodput、trace replay 等负载和指标语义。 + +规划采用以下边界: + +- **AIPerf 只负责生成式 AI 负载和请求侧统计**:新增显式的 `AIPERF` test stack mode,首期支持单个 load generator 对 OpenAI-compatible SGLang endpoint 发压。 +- **`test_runner` 继续负责 case 生命周期**:suite 编译、资源准备、启动、超时、取消、终态、历史记录、UI 和对外 API 都由 `test_runner` 管理。 +- **Greptime 继续负责连续时序指标与日志**:Fluxon 服务指标、日志和已有监控链路不迁移到 AIPerf。AIPerf 的请求结果以 run artifact 为事实来源。 +- **AIPerf UI 和 API 不成为新的公共入口**:AIPerf 以 `runtime.ui: none` 运行;其 loopback API 只供同机适配器读取,`test_runner` UI 通过现有 ops 接口展示标准化后的进度和结果。 +- **现有 distributed benchmark coordinator 保持原路径**:KV、MQ、RPC、FS 的 `benchmark_result.json` 语义不由这次接入改写。`AIPERF` 是现有有限模式集合中的新分支。 +- **依赖必须固定到提交和构建产物哈希**:`teleai` 是未保护的可变分支,运行时不能直接按分支头安装。 + +首期不启用 AIPerf sweep、AIPerf multi-run、AIPerf OTel 导出和 GPU telemetry。case 矩阵仍由 TestStack 的 `scene × scale × profile` 决定,避免形成嵌套调度和重复监控通道。 + +## 2. 目标与非目标 + +### 2.1 目标 + +1. 把生成式 AI benchmark 收敛进 `start testbed -> testrunner` 两步模型。 +2. 复用 AIPerf 已有的请求生成、warmup、并发或请求速率控制、请求级记录和聚合统计。 +3. run artifact 和请求链路统一使用 `case_id + run_index`;连续服务指标通过 `cluster/instance + run time window` 与 run 关联。 +4. 让常驻 `test_runner` UI 同时展示实时进度、终态摘要、artifact 和 Greptime 时间窗口。 +5. 保证离线安装、固定依赖、固定随机种子和明确的失败状态。 + +### 2.2 非目标 + +- 不用 AIPerf 替换 `distributed_benchmark_coordinator.py`。 +- 不把 AIPerf FastAPI、TUI 或 plot dashboard 暴露为 TestStack 公共服务。 +- 不在 Fluxon 内重写 TTFT、ITL、token throughput 等 AIPerf 已提供的算法。 +- 不允许 suite 同时传入自由格式 AIPerf YAML、任意 CLI 参数和环境变量覆盖。 +- 首期不支持多 load generator、AIPerf Kubernetes service mode、真实用户 prompt、鉴权 endpoint 和自动性能回归判定。 + +## 3. 当前工具链分析 + +### 3.1 当前数据流 + +```mermaid +flowchart LR + A[ci_test_list.yaml] --> B[test_runner.py] + B --> C[resolved_case.yaml] + B --> D[distributed benchmark coordinator] + D --> E[benchmark nodes] + E --> F[benchmark_result.json] + F --> B + B --> G[summary.yaml + case_runs.yaml] + + H[Fluxon processes] --> I[Prometheus remote write] + I --> J[Greptime] + H --> K[local logs / OTLP logs] + K --> J + + G --> L[test_runner UI] + J --> L + M[ops interfaces] --> L +``` + +当前各层职责如下。 + +| 层 | 当前实现 | 已有能力 | 当前边界 | +| --- | --- | --- | --- | +| suite 与 case 编译 | `test_runner.py` | `scene × scale × profile`、`resolved_case`、run 目录 | 没有生成式 AI workload branch | +| testbed 生命周期 | `start_test_bed.py`、controller、ops | 启动共享服务、apply、进程状态和日志 | 不执行单个 benchmark case | +| benchmark 执行 | coordinator + nodes | KV、MQ、RPC、FS 的分布式同步和聚合 | 指标模型面向 operation、bytes 和内部 phase | +| 终态 | `benchmark_result.json`、`summary.yaml`、`case_runs.yaml` | 强制等待结果、校验节点完成、记录 run outcome | UI 主要展示原始摘要,缺少通用指标视图 | +| 连续监控 | Prometheus-compatible remote write、Greptime | 服务指标、部分 transport 指标、日志 | 与 run artifact 的关联字段尚未统一 | +| 常驻 UI | `test_runner_ui.py` | suite/run 状态、日志、GitOps、ops log | 当前没有 benchmark 曲线和统一结果 API | + +### 3.2 当前链路已经稳定的部分 + +- `case_runs.yaml` 是 suite workdir 内执行状态的单一事实来源。 +- `summary.yaml` 是单次 run 的终态摘要,runner 会在执行前写入可诊断的占位结果。 +- TestStack benchmark 通过 `benchmark_result.json` 完成终态握手。runner 会校验每轮 `completion.status`、节点数量和 operation 数量。 +- UI 是常驻服务,run 结束后仍能读取历史、日志和 ops 状态。 +- Fluxon 指标使用 Prometheus-compatible 协议进入 Greptime,服务日志同时保留本地文件和 OTLP 路径。 + +### 3.3 主要缺口 + +| 缺口 | 影响 | 本设计的处理 | +| --- | --- | --- | +| 缺少生成式 AI 请求语义 | 现有 operation latency 无法表达 TTFT、ITL、token throughput 和多轮会话 | 使用 AIPerf 计算并保留原始 metric tag 与单位 | +| 进度、终态和时序指标分散 | UI 需要分别读状态文件、原始 JSON、日志和 Greptime | 在现有 `/api/run_state` 下增加有界的 `benchmark` 分支 | +| run 关联字段未贯穿 | 很难把请求突刺与服务指标、日志对齐 | 固定 artifact 关联键,并保存 cluster/instance 与 benchmark 时间窗口 | +| 当前 UI 缺少 benchmark 图表 | 只能查看 JSON 和日志 | UI 读取标准化摘要、timeslice 和 server metrics artifact | +| 多节点 percentile 聚合口径有限 | 当前 distributed benchmark 的 p50/p95/p99 是按成功 operation 数加权的节点 percentile,不能作为全量样本 percentile 使用 | AIPerf 路径保留请求级 JSONL,并由 AIPerf 计算请求总体 percentile | +| 工具能力容易重复 | AIPerf 也有 UI、API、server metrics、OTel 和 GPU telemetry | 用明确的所有权表限制每条链路 | + +上表中的 percentile 结论只描述当前 coordinator 的节点聚合实现,不扩展为其他 benchmark 或整个监控系统的结论。 + +## 4. AIPerf `teleai` 分支评估 + +### 4.1 可直接复用的能力 + +| 能力 | `teleai` 快照行为 | Fluxon 用法 | +| --- | --- | --- | +| Python 版本 | `requires-python = ">=3.10,<3.14"` | 满足 Fluxon 的 Python `>=3.10` 要求 | +| 许可证 | Apache-2.0 | 构建产物保留许可证与 attribution | +| endpoint | OpenAI chat/completions 等 | 首期只开放 OpenAI-compatible chat streaming | +| 负载控制 | concurrency、request rate、warmup、ramp、trace replay | 首期开放 fixed concurrency 和 fixed request rate 两个有限分支 | +| 请求指标 | TTFT、ITL、request latency、request/token throughput、error 等 | 直接采用 AIPerf metric tag 和单位,不在适配层重算 | +| artifact | summary JSON/CSV、请求级 JSONL、`inputs.json`、timeslice | summary JSON 和请求级 JSONL 为首期必需产物 | +| server metrics | 自动发现或显式抓取 Prometheus `/metrics`,当前默认每 333 ms 采样 | 首期只抓取 runner 解析出的单个 SGLang metrics endpoint | +| 实时 API | `/api/run`、`/api/progress`、`/api/metrics`、`/api/results`、`/metrics` | 只绑定 loopback,由同机适配器读取 | +| UI | dashboard、simple、none | 固定 `none`,避免出现第二套 UI 归属和入口 | +| OTel | 可流式导出 metrics 和 timing | 首期关闭,待 Greptime OTLP metrics 契约单独评审 | + +### 4.2 依赖快照结论 + +截至 2026-07-10: + +- `teleai` 指向提交 `d72160e20957013d6608afcc88ed24100cb27dc5`。 +- GitHub compare 显示该提交下 [`main...teleai`](https://github.com/ActivePeter/aiperf/compare/main...teleai) 为 `identical`。 +- 仓库中没有可识别的 TeleAI 专属配置、插件或 patch。 +- `teleai` 分支未启用 branch protection。 + +因此,“使用 `teleai` 分支”在工程上必须落实为下面四项记录: + +1. source repo:`https://github.com/ActivePeter/aiperf` +2. requested branch:`teleai` +3. resolved commit:`d72160e20957013d6608afcc88ed24100cb27dc5` +4. wheel 与 wheelhouse manifest 的 SHA-256 + +实现前还需要业务方确认:当前意图是否就是采用这份与 fork `main` 相同的快照;如果预期存在 TeleAI 定制能力,应先明确对应提交或差异清单。 + +### 4.3 不能直接沿用的默认行为 + +- **不能按 branch head 在线安装**:testbed 运行期间不访问 PyPI 或 GitHub。 +- **不能使用环境变量替换普通参数**:suite 编译器生成完整 AIPerf YAML,启动命令只传 `--config`。 +- **不能使用 AIPerf sweep 或 multi-run 展开 case**:TestStack 已拥有 case 空间和 run history。 +- **不能依赖 AIPerf 默认 UI**:非 TTY 与 TTY 下必须都固定为 `none`。 +- **不能依赖 server metrics 自动发现**:显式写入 SGLang `/metrics` URL,并关闭 Kubernetes discovery。 +- **不能直接公开 AIPerf API port**:API 只监听 `127.0.0.1`,端口由 testbed port allocator 分配。 + +## 5. 目标架构 + +### 5.1 核心角色 + +| 角色 | 责任 | 不负责什么 | +| --- | --- | --- | +| `start_test_bed.py` | 准备 SGLang、Greptime、controller、ops 和常驻 runner UI | 不启动单次 AIPerf run | +| `test_runner.py` | 编译 `AIPERF` case、分配资源、驱动 prepare/execute/finalize、写终态 | 不计算 TTFT 或 ITL | +| AIPerf adapter | 在 load generator 上启动 AIPerf、轮询 loopback API、原子写进度、校验 artifact、生成终态 | 不拥有 suite、历史或公共 API | +| AIPerf | 发请求并计算请求侧指标 | 不拥有 testbed 和长期监控 | +| SGLang endpoint | 被测服务,暴露 OpenAI-compatible API 和 `/metrics` | 不决定 benchmark 成败 | +| Greptime | 保存 Fluxon 连续指标与日志 | 首期不保存 AIPerf 请求级记录 | +| `test_runner` UI | 组合 run 状态、AIPerf 摘要、artifact、ops log 和 Greptime 时间窗口 | 不直接连接公开的 AIPerf 服务 | + +实现代码按现有 runner 分层落位: + +| 模块 | 计划改动 | +| --- | --- | +| `test_runner.py` | 增加 `AIPERF` suite schema、case 编译和有界 dispatch,不承载子进程细节 | +| `test_runner_runtime_backend.py` | 增加 `AIPERF` prepare、execute、finalize 和终态读取 | +| `aiperf_adapter.py` | 唯一的直接进程入口,负责 AIPerf 子进程、loopback API、timeout 和结果发布 | +| `aiperf_contract.py` | generated config、progress 和 result 的强类型模型与 validator,不提供第二个执行入口 | +| 现有 runner UI 代码 | 在 `/api/run_state` 与 run 页面增加 `AIPERF` 显式分支 | + +### 5.2 数据流 + +```mermaid +flowchart LR + A[suite] --> B[test_runner compile] + B --> C[resolved_case.yaml] + B --> D[aiperf.generated.yaml] + B --> E[ops apply on load generator] + E --> F[AIPerf adapter] + F --> G[aiperf profile] + G --> H[SGLang OpenAI endpoint] + H --> G + + G --> I[AIPerf artifacts] + G --> J[loopback API] + J --> F + F --> K[aiperf_progress.json] + F --> L[benchmark_result.json] + L --> B + B --> M[summary.yaml + case_runs.yaml] + + H --> N[SGLang /metrics] + N --> G + O[Fluxon services] --> P[Greptime metrics + logs] + + Q[test_runner UI/API] --> M + Q --> K + Q --> I + Q --> P + Q --> R[ops status + logs] +``` + +AIPerf adapter 是单次 case 的直接进程入口,生命周期与该 case 一致。它不作为 testbed 常驻服务运行。 + +### 5.3 所有权与事实来源 + +| 数据 | 事实来源 | 保留周期 | UI 读取方式 | +| --- | --- | --- | --- | +| suite/case 状态 | `case_runs.yaml` | suite workdir 生命周期 | runner 本地读取 | +| run 终态 | `summary.yaml` | run artifact 生命周期 | runner 本地读取 | +| AIPerf 请求摘要 | `aiperf/profile_export_aiperf.json` | run artifact 生命周期 | runner 结果适配器 | +| AIPerf 请求级记录 | `aiperf/profile_export.jsonl` | run artifact 生命周期 | 按需下载或离线分析 | +| AIPerf 实时进度 | `aiperf_progress.json` | case 运行期间,终态后保留最后快照 | 通过 ops 文件读取接口 | +| SGLang run-window 指标 | `aiperf/server_metrics_export.jsonl` | run artifact 生命周期 | runner 图表适配器 | +| Fluxon 连续指标 | Greptime Prometheus-compatible API | Greptime retention | runner monitor 查询接口 | +| 服务与进程日志 | 本地 daily shard、Greptime `fluxon_logs`、run log | 各自既有 retention | 现有 log/ops log API | + +首期不把 AIPerf summary 再复制到 Greptime。这样可以避免 artifact、OTel 和 Prometheus 三条通道同时保存同一组请求指标。若后续需要跨 run 长期聚合,应单独设计一个由 runner 控制的离线导入协议。 + +## 6. 配置与编译模型 + +### 6.1 suite 只增加一个有限模式 + +目标 suite 结构采用 `scene.test_stack.mode: AIPERF`。各层仍保持现有分工: + +| 层 | `AIPERF` 分支内容 | +| --- | --- | +| scene | model、endpoint type、streaming、dataset、warmup、profiling phase、随机种子 | +| scale | load generator target、SGLang endpoint instance、资源规模 | +| profile | AIPerf artifact set、adapter deploy 模板、SGLang runtime 组合 | +| resolved case | 具体 URL、metrics URL、run_dir、loopback API port、完整 source manifest | + +下面是提议中的 suite 片段,只用于说明字段归属,当前代码还不能执行: + +```yaml +scenes: + sglang_chat_concurrency: + test_stack: + mode: AIPERF + aiperf: + model: example-model + endpoint_type: chat + streaming: true + random_seed: 42 + dataset: + type: synthetic + entries: 512 + input_tokens: 1024 + output_tokens: 256 + warmup: + concurrency: 8 + requests: 32 + profiling: + type: concurrency + concurrency: 32 + requests: 512 +``` + +Fluxon 只接受上述有界字段,不接受 `extra_args`、任意 AIPerf config fragment 或环境变量模板。需要新增 workload 能力时,先把它加入明确的 schema 分支和 contract test。 + +### 6.2 生成单一 AIPerf 配置 + +runner 根据 `resolved_case` 生成 `aiperf/aiperf.generated.yaml`。该文件是编译产物,用户不直接维护。Fluxon suite 统一使用 `snake_case`;生成器在 AIPerf 边界按该提交自带 JSON Schema 输出 `camelCase` alias,不在同一份配置中混用两种拼写。 + +```yaml +schemaVersion: "2.0" +randomSeed: 42 + +benchmark: + model: example-model + endpoint: + url: http://sglang-host:30000/v1/chat/completions + type: chat + streaming: true + headers: + X-Fluxon-Case-ID: sglang_chat_concurrency__n1__teleai + X-Fluxon-Run-Index: "1" + dataset: + type: synthetic + entries: 512 + prompts: {isl: 1024, osl: 256} + warmup: + type: concurrency + concurrency: 8 + requests: 32 + profiling: + type: concurrency + concurrency: 32 + requests: 512 + artifacts: + dir: /testbed/run/results/example/run_1/aiperf + summary: [json] + records: [jsonl] + raw: false + trace: false + sliceDuration: 5 + serverMetrics: + enabled: true + urls: + - http://sglang-host:30000/metrics + formats: [json, jsonl] + discovery: + mode: disabled + gpuTelemetry: + enabled: false + runtime: + ui: none + apiHost: 127.0.0.1 + apiPort: 19081 +``` + +启动命令固定为: + +```bash +aiperf profile --config /testbed/run/results/example/run_1/aiperf/aiperf.generated.yaml +``` + +`testbed_aiperf_api_port` 由现有 testbed port allocator 派生并写入 resolved case,不增加用户侧端口配置项。 + +### 6.3 依赖交付 + +构建阶段完成以下动作: + +1. 从固定 commit 构建 AIPerf wheel。 +2. 解析并下载目标平台的完整 dependency wheelhouse。 +3. 生成包含文件名、版本、许可证和 SHA-256 的 manifest。 +4. 把 wheelhouse 作为 profile 所选 artifact set 的一部分发布。 +5. load generator 在隔离 venv 中离线安装,禁止运行时访问 package index。 + +`resolved_case.yaml` 和 `benchmark_result.json` 都要记录 source repo、requested branch、resolved commit、AIPerf package version 与 wheelhouse manifest SHA-256。 + +## 7. 执行与终态契约 + +### 7.1 执行时序 + +```mermaid +sequenceDiagram + participant R as test_runner + participant O as ops/deployer + participant A as AIPerf adapter + participant P as aiperf profile + participant S as SGLang + + R->>O: apply adapter workload + O->>A: start generated config + A->>P: spawn direct process + P->>S: warmup requests + P->>S: profiling requests + loop every 1 second while running + A->>P: GET loopback /api/progress and /api/metrics + A->>A: atomic replace aiperf_progress.json + end + P-->>A: exit code + artifacts + A->>A: validate and write benchmark_result.json + R->>O: read terminal result + R->>R: validate, write summary, finalize apply +``` + +### 7.2 `benchmark_result.json` + +`AIPERF` 使用独立的强类型 payload,runner 根据已编译的 mode 选择专用 validator。建议最小结构如下: + +```json +{ + "schema_version": 1, + "result_kind": "AIPERF", + "case_id": "sglang_chat_concurrency__n1__teleai", + "run_index": 1, + "completion": { + "status": "SUCCESS", + "exit_code": 0, + "error": null + }, + "source": { + "repo": "https://github.com/ActivePeter/aiperf", + "requested_branch": "teleai", + "resolved_commit": "d72160e20957013d6608afcc88ed24100cb27dc5", + "package_version": "", + "wheelhouse_manifest_sha256": "" + }, + "timing": { + "started_at_unix_ns": 0, + "finished_at_unix_ns": 0 + }, + "summary": { + "request_count": 0, + "error_request_count": 0, + "metrics": {} + }, + "artifacts": [] +} +``` + +`metrics` 中保留 AIPerf 的 canonical tag、统计字段和单位。适配器不把 `time_to_first_token` 改名为另一套 Fluxon 私有名称。 + +### 7.3 完成状态 + +完成状态使用有限枚举: + +| 状态 | 含义 | runner outcome | +| --- | --- | --- | +| `SUCCESS` | 进程退出码为 0,必需 artifact 可解析,至少有一个成功请求 | `SUCCESS` | +| `START_FAILED` | venv、配置校验或子进程启动失败 | `FAILED` | +| `PROCESS_FAILED` | AIPerf 非零退出 | `FAILED` | +| `RESULT_INVALID` | summary 缺失、schema 不符或计数不满足不变量 | `FAILED` | +| `TIMEOUT` | 超过 case deadline,adapter 已终止子进程 | `FAILED` | +| `CANCELLED` | runner 或 operator 发出取消 | `FAILED` | + +首期不把普通请求错误率直接转换为 case 失败。请求错误会进入 summary;后续性能门禁必须使用单独、显式、可版本化的 acceptance policy。 + +### 7.4 不变量 + +- `case_id`、`run_index` 必须与 `resolved_case.yaml` 完全一致。 +- `resolved_commit` 和 wheelhouse manifest hash 必须与 staged artifact manifest 一致。 +- `finished_at_unix_ns >= started_at_unix_ns`。 +- `SUCCESS` 要求 AIPerf exit code 为 0、summary JSON 可解析、`request_count > 0`,并且 `request_count - error_request_count > 0`。 +- 所有 artifact path 必须位于当前 run_dir 内,并记录 size 与 SHA-256。 +- adapter 只能用临时文件加原子 rename 发布进度和终态,runner 不读取半写文件。 +- timeout 或 cancel 后必须等待 AIPerf 进程组退出,再写终态。 + +## 8. 监控与 UI 设计 + +### 8.1 指标分域 + +| 域 | 代表指标 | 来源 | 首期展示 | +| --- | --- | --- | --- | +| 生命周期 | status、phase、completed/total requests、elapsed | adapter progress | run 状态卡 | +| 请求体验 | TTFT、ITL、request latency、error rate | AIPerf summary/timeslice | percentile 表与时间曲线 | +| 吞吐 | request throughput、input/output token throughput | AIPerf | 摘要与时间曲线;goodput 随阶段 3 的显式 SLO 配置加入 | +| SUT | queue depth、KV cache usage、running/waiting requests | AIPerf server metrics artifact | 与请求曲线共享时间轴 | +| Fluxon 基础设施 | transport、KV、MQ、FS 和服务指标 | Greptime | 按 run 时间窗口查询 | +| 日志 | adapter、AIPerf、SGLang、Fluxon 服务日志 | ops、本地日志、Greptime | 复用现有日志查看器 | + +请求级 `x_request_id` 和 `x_correlation_id` 只进入 record/log,不作为 Greptime 时序标签,避免高基数。 + +### 8.2 关联字段 + +| 字段 | artifact | 请求 header | Greptime 查询标签 | 说明 | +| --- | --- | --- | --- | --- | +| `case_id` | 必需 | `X-Fluxon-Case-ID` | 不要求 | 逻辑 case,由 runner 关联到查询窗口 | +| `run_index` | 必需 | `X-Fluxon-Run-Index` | 不要求 | 同一 case 的第 N 次运行 | +| `cluster_name` | 必需 | 可选 | 必需 | testbed 集群 | +| `instance_key` | 必需 | 无 | 必需 | SUT 与 Fluxon 服务实例 | +| `model` | 必需 | 请求 body 已包含 | 可选 | 模型身份 | +| `endpoint_type` | 必需 | 无 | 可选 | 首期固定为 `chat` | +| `case_key` | 必需 | 无 | 不使用 | 配置快照 hash,不进入时序标签 | +| source commit/hash | 必需 | 无 | 不使用 | 保存在 provenance 中 | + +长生命周期服务不能随每个 case 动态改写 Prometheus label。runner 应在 resolved case 和终态中保存 `cluster_name`、相关 `instance_key`、`started_at_unix_ns` 与 `finished_at_unix_ns`,再用这组条件查询 Greptime。`case_id` 和 `run_index` 只需要出现在 run artifact、AIPerf 请求 header 及可选的 run marker 日志中。 + +跨 AIPerf 请求时间和 Greptime 时序数据做叠图前,testbed preflight 必须检查 load generator 与 SUT 时钟。首期允许的最大时钟偏差应固定为 1 秒,超过阈值时 case 在启动前失败。 + +### 8.3 runner API 与页面 + +扩展现有 `/api/run_state`,增加一个按 mode 判别的 `benchmark` 对象: + +```json +{ + "benchmark": { + "kind": "AIPERF", + "status": "RUNNING", + "progress": {}, + "summary": null, + "artifacts": [], + "monitor_window": { + "start_unix_ns": 0, + "end_unix_ns": null + } + } +} +``` + +不新增平行的 AIPerf UI service。run 页面增加以下区域: + +1. workload 与 provenance +2. warmup/profiling 进度 +3. TTFT、ITL、latency、throughput 和 error 摘要 +4. timeslice 与 SGLang server metrics 曲线 +5. Greptime 同时间窗口入口 +6. artifact 与 ops log 列表 + +UI 服务重启后,历史页只依赖 run artifact 和 Greptime,不能依赖已经退出的 AIPerf API。 + +## 9. 可复现性、性能边界与安全 + +### 9.1 可复现性 + +- 每个 scene 必须显式给出 `random_seed`、warmup、stop condition、ISL、OSL 和 streaming。 +- endpoint URL 从已解析的 SGLang instance 派生,不允许在 scene 中另写自由 URL。 +- load generator 与 SUT 首期必须位于不同 target,避免 generator CPU、网络和 SUT 资源相互竞争。 +- 记录 AIPerf commit、wheelhouse hash、Python 版本、SGLang image/commit、模型、tokenizer 和完整 generated config。 +- server metrics 始终使用相同的显式采样配置。AIPerf 当前 333 ms 采样行为本身也属于对比条件。 +- raw response 默认不保存;请求级 metrics JSONL 必须保存,以便复核 percentile 和异常请求。 + +### 9.2 性能结论边界 + +AIPerf 给出的请求指标覆盖 load generator 到 SGLang HTTP endpoint 的请求路径。它包含客户端排队、网络和服务端处理的组合影响,不能单独证明 Fluxon 某个内部模块的耗时。 + +SGLang `/metrics` 与 Greptime 指标用于解释同一运行窗口内的服务状态。两者采样频率、时钟和标签不同,叠图只提供时间相关性,不自动证明因果关系。 + +### 9.3 安全与数据保留 + +- AIPerf API 只监听 loopback。 +- generated config、result 和 artifact path 都要经过 run_dir containment 校验。 +- 首期只使用 synthetic dataset,不接入真实用户 prompt。 +- `raw: false`、`trace: false` 为固定默认值。 +- endpoint headers 在 result 和日志中必须经过 AIPerf 现有 redaction,再由 adapter 二次校验。 +- 后续鉴权方案必须使用专门的 secret 注入路径,不能把 token 写入 suite、generated config 或普通环境变量。 + +## 10. 实施阶段 + +### 阶段 0:依赖与样例固化 + +- 确认 `teleai` 快照就是目标版本,或取得明确的 TeleAI patch commit。 +- 构建离线 wheelhouse、license 清单和 SHA-256 manifest。 +- 用固定 SGLang mock/fixture 验证 AIPerf summary、records、server metrics 和 loopback API schema。 +- 保存一份脱敏 golden artifact,作为 adapter contract test 输入。 + +### 阶段 1:终态 MVP + +- 在 suite schema 中加入 `AIPERF` mode 和有限 workload 字段。 +- 增加 case 编译、testbed port 分配、generated YAML 和 isolated venv prepare。 +- 增加 AIPerf adapter 的 direct-process 启动、timeout、cancel、artifact 校验和终态写入。 +- 增加专用 result validator,并把小型摘要写入 `summary.yaml`。 +- UI 先展示终态摘要、artifact 和日志。 + +### 阶段 2:实时监控 + +- adapter 每秒读取 loopback `/api/progress` 和 `/api/metrics`,原子更新进度快照。 +- 扩展现有 `/api/run_state` 和 run 页面,不新增服务。 +- 增加 timeslice 与 SGLang server metrics 图表。 +- 用 run 时间窗口和关联字段查询 Greptime。 + +### 阶段 3:对比与门禁 + +- 由 `test_runner` 管理重复 run 和基线选择,禁止打开 AIPerf multi-run 形成第二层历史。 +- 定义版本化 acceptance policy,明确 metric、stat、方向、阈值和缺失值行为。 +- 对 percentile 门禁优先读取请求级记录的 pooled 统计,不使用节点 percentile 的平均值。 +- 增加跨 run 对比页和机器可读的 evaluation 结果。 + +## 11. 测试计划 + +| 测试 | 执行模型 | 成功条件 | +| --- | --- | --- | +| config compile | contract test | suite 字段唯一映射到 generated YAML,未知字段快速失败 | +| dependency provenance | contract test | commit、package version 和 wheelhouse hash 一致 | +| happy path | 直接启动 adapter 进程 + mock OpenAI endpoint | exit 0、终态 `SUCCESS`、必需 artifact 存在 | +| request failure | 直接启动 adapter 进程 + 失败响应 endpoint | 错误计数保留,至少一个成功请求时完成 | +| invalid result | 直接启动 adapter 进程并注入损坏 artifact | `RESULT_INVALID`,runner case 失败 | +| timeout | 直接启动 adapter 进程 + 挂起 endpoint | 整个进程组退出,终态 `TIMEOUT` | +| cancel | 运行中发送 runner cancel | 终态 `CANCELLED`,没有残留 AIPerf 进程 | +| API isolation | process test | API 只监听 loopback,testbed 外无法访问 | +| UI restart | 启动常驻 UI,完成 run 后重启 UI | 历史摘要和图表仍能从 artifact 恢复 | +| clock preflight | process test | 偏差超过 1 秒时在发压前失败 | +| offline install | clean testbed process | 无外网条件下从 wheelhouse 完成安装和运行 | + +进程生命周期测试按独立脚本或进程直接运行,并显式检查 exit code 与残留进程。不要为了统一外观再套一层 pytest 入口。 + +## 12. 验收条件 + +首期完成必须同时满足: + +1. 用户仍只执行 `start testbed` 和 `testrunner`。 +2. suite 只有一个 `AIPERF` 配置入口,运行时只消费生成的单一 YAML。 +3. testbed 无外网时可以安装并运行固定 AIPerf 快照。 +4. runner 能区分启动失败、进程失败、结果损坏、超时和取消。 +5. UI 不公开 AIPerf API,run 结束和 UI 重启后仍能展示结果。 +6. TTFT、ITL、latency、throughput 和 error 指标可追溯到 AIPerf artifact,不经二次重算。 +7. AIPerf 请求窗口可以和 SGLang server metrics、Fluxon Greptime 指标及日志按 `case_id + run_index + time range` 对齐。 +8. 现有 KV、MQ、RPC、FS benchmark 路径和结果校验保持不变。 diff --git a/fluxon_release/closed_sdk/lib/libfluxon_commu_core.so b/fluxon_release/closed_sdk/lib/libfluxon_commu_core.so index 0d1a1d3449bba46486f9296723538b5cde4e3bd1..ce9458d043159b8d39c17dc474a0b9a71c89a0cd 100755 GIT binary patch delta 6083184 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

fl8i-|e0w|W#BpCYe@+>m9(1rC}H zoN!+Q(Z3Dp37?L4ry~R{%hzy-Jg)=Rsy96fHS%g9plBoM-37j){;dFl)6Yt@Me_Y1 z(a}m;VD!0G1@)&kh@Br@SR*!ZOF^nn9GR;z4yzSyEDj9i&oR#vC8-u@!&CI$Xc

+EtK+vo0Bn1_+YsJuMbRIq@g+# zA06{0O$^!)=vh32`BUJ>$e*AGV+-CaOpJMcSCSgrH=)F;E+o-$CPSYj!XWZ)GGw)a zp_n3@j?rao=Pye>j2Z6~re}jg$;7&-DHfNQx%fB_Z^RPb6di^){nzsg9b3Ry!!ZR3 zv2UXjQ=-CLu%>4`5Gr6b0JjZ$4m4kmP2VyJphF<(%IAW!F*3}mzuMhMXl+J_$hhUV z@d}8sfAYQ%AWp+;rcq=av5jOLt|6=vE2@aMIf*x5sf|RNG54OfUy9`yPYT4ecSzeqDmM1GZvQsE^)|`Tp^%Zt)(V*xR9^3>OmqmS1^n3{W{#3} zh3M@4{UMwR8FW&0?b#A*i2dVz6%+pV8cZ!WJm4f%zAD?R8G##_+F&kF>&4ibQ^LY_R94T-_{?P$>aMJH5 zQ8%Y)v7dcaSTp7yF)E82|Bh7*3o`ET(=|(l~bY(~_@d zjsC3UGC4s8V!z0mlpLEHotPHIkW@im2+t9FyolCkKr}v`jO8N6SfG6H;!+wRFoSUn z45YgWVeVa0yGhipqOU}=F~q%`g)myOp`V;DX{RLGEa?tBLV1Pp(d$F8m8}Y@#?;@I zBh;rKSEEeONvqVrBl*N5*G3 zNjmk@O_Ui?IZz}%;EDD0<#kN}fgt+L4^jd==oiR-#6j37Lz2VpC{aJGUVHNGxHzUJ zq2WDT$+HDhASAh{;2}&0F(u5a5CJNBp&Oz6Qi|MwLe7{3pJ~&)Y_g@M?>r*9n+Yg$ z7S_0!4yDfy!AU(tHplo`Kh?d%k7(a1d;D;yHAnf`YG1}KKZ{=S`G!LO?N30V!G7WI zBpw!vu1N#P6FNC)B)uhLj6_2!&j8UlqnR7)?KKn=&)~YTd$`12#t9R@hF1rYBPg;! zC}ZL*Vuc$CHd}8>^xoh-lZB=e2<`NgGo|^qfv+np4g!_N(9ef$o+P>%FlkJvQ={lCSO0 zHZg2i+U8Ol*3< z(u7z|$(Y%K-R6<&%`s#HQDw2|8TA62Yl>NZ&s`PiVNrpG%Sya2q3At-?ba>W?vQ=5 zIqQ??JJOu(ju?xZvkghp=v;F)rAqF-=4@S>XJu2iw^{`0zSWbEKRG?Oa|^aP%QLYV zTbR>Hn%|rquO)7eubqtBz4JXco3fI+Ci45%^Te96=?_k%70uc3`VFQvkFxfUT0NVy z*rVF@W^D1J8d`ATF?s5X?DS(GRoXp1OzQn}cJwLhL^F2nDeFKp*5_&MLNm7fX?b5W z*0I5hZJM&H4H5?aj1@HuB7LBtb+!q++E6>ugpFvVpZyt|)F>NwcQ^8vyvSBRlX&<= zcKsPY>hJMvWcLd!I{R7wwij5B=cE@MXyQZ8$|m-nW-ztUer!VRn_BmNPIH^eOPbP|rt;;c zG_;vKwi&H!CU0v-eVS`So74K{9A)~pNSxAw_D5UPL(r1NFQ^+{pf)dVlyGPB&mX9? zhklJ+v!9N=Rxg(BB_U`xgtV-?x6$b&gxym6B_jgaW(?;_e>J2}`5_Bp-v-+fE@p+s z;KuIoW^qv*5gYOJqzKY$lOQtQlVqW~bBRgD%_M4*Z1hN`Sh7`|Ok!84T4M&0pc>SGY};?Ij{7(Mx-*yia) z^<#N0OCGEZWUR@uISM#xG7w`R=gdWVzpi&PSWm+kV$c#pUMHMB#p`2jTb4AB-Nkct zgxz@;yuXY5Wd}%Rl$3*TxZ^g&190#hqS9?Hw^FIIY9QTL^~63%EX;`=f1spF0*-^X zWr#1{6YKCCsj$u#>##?OaXeOu}Xn=fsC*) zCl#X=ryrC+Z1KyJ!gYi(^d?C=B+;(>cQfopo?poCuvecG`Yjc zzq?bE6dU+?N%dHt?@O{`z7Z2cUK@Tz!gpT-d%2jZ#@@YKP$%|I&Ehn1%9V0ozZhKj z#7m&j>f6oO3&wl&`h6#yW^46XVgqMaaC(h=~dCRUNyf+H>6;J!b>1Ah{1cqh_u z;`MU2!C2~$g7jqU(hsVCU=8%&u%`J?X{L=L_=LpgLhr2w8P!0z)=_bSG~p0+LF@nUS3f+*5;|A>}oKLXe?t^GU|X&t!Rq`^0+ovp=lL?aAQsXRFczF zII0TG>QFKeE&~AKAdS1o_GS^**(j31D1zeLCL1SYI#59?3+BbgK-#}#e+1=rI{+KT zdUl_j8|$7{6sZDnj-|iIGUZ>g9FRL7RPBffUiula(|^Jw-}T#qoY?q}F}2UFFY>r8 z_61{K$ZY|}pBn4Au_!|vl94!BdHzo&xv_483XRzLS4y&D^}eQtDHHU7Y!=J3Ojg$l_cQsjOlK;8g{WgM>e!3Phv2LdM;~;T zZS>^`**+=5s1$WxV6yMVUU9mk$nYW3pGlz&6+ z#_^tAfshbOD&8f&1n5z38j#g~EaZQS zSDTi2Yo>9)8G=c|cW4jr-?924EoOkT#n>;g zSG14mZD%pWlK(!j&Tl}Nrtx>-!UrW4^{q5F{@r6@)#IK(i;8oq92N#{`f*c{>2!>u@HL-`krTvCJioMvQFtIsu|CuI@ z&+m9M{x|nxqlOd&GhnEhEn_czOt5yp;-IcS7c5~bi9-g|zI5uu(z}%8M$uLIYBTmQ zg!xWaeIqY{(SeYxPLxz|(d7*hK5GvFtSZt5ZfN@7!7=KqiKdddjA(u(&QjEaU?KHY z?C8@-#+ft&)}-RZRv~UGtqx^gqGpe3!td-4Rc}ERL*^<0D;R-XXRsvF)1?R~i?vc3 zwpGbO%(~l>g@Q5JoFLOoN8Hm%sqVxVuh^yIAK`0HHt^gB!<3e2bj7d=;bk@sI|1|c z2~3X0O9xVM(O%KFC?astd4;YkW)}|Ik+Lddk9}D3AWqDbktBo38Y;<~;5I9(0P*N6 zL)36fR@)#1ckK3uC0QXMzz_nE8Ilb>;C@L4r+i3?jckWqbZ+yKXC2NWI^^&4m(k?j z7s4U+;Diu7BBWhGK+c*IgX}8L+7lF^uMoiNy0Jz?2kT>pQK-<~gO;}Q=NAM)Nd5{r z+Y%D?!8Iu$568oSr*{O|u|NXid-V;<1B0|VC|?axt5E8w5FHFzNS_PEzsVT^tPsn= zI*=it__|y@sDBBFJ@$2z_%y#qpA3?=$)~EZQLbv|tHJ81HQ{2B;W<%_tv82CxHxU~ z05@~P=RvxIzZcp#AfZq^vM?kD{Yv;G$Hm?hh%eZ|s=M)gl&wn3Ky4S(TH?;CYVVi5 zti}P^|0C2Wa(`?K9bDf2@Jn+cjwSrE-ALawR-$Xsa336!pu$OcW=$$vlOk;5@k4$U zI2FJ;Lh%e#feBU<0so zA);{8PTV^%!eU(55Kh!*5H1cFu;*cYJPAmT^9WtvIBylC7kf{DW-bWUNBUr}3-V8g ziX~hOh}0-++?zvX`ARDMrp@TJRJPG&-c5zz0kZyaS~8Mj^{U8j?TPeDW39Z^TBWfc zLMcf13`4lch9vHgaIq|TiHtj)QXj{~^3+76_oZUHb{d>`N)jPtZ%bl&&sWwcxag?o zIQQHWWk29y=F4;NF~Xqdh5YtXVFdHEt;yStft3cOE5($Bp4RNl-e*pSf&V;Cw@QN z_>|Hc)(27EAJr~b8{wj(OK8K&WcjR=w(jF$0wvH?cU@TazSv+?{Pa8f*iael#i_Jd*F;0<`jyyqNfP9!0m9s9O=OvA;R+!bhF?^@!< z#9A=iiZ?9%*@t0k`d1+w8!pY13w5|tT)@TBsOu=RIfqr+Rn8gZoO2cmC?QZ5Ncx}Kvted~v=Z?C`o7iI)7{lwUAgW(_nbl0A|y`f z*O2rb^ZP!|Ewa9XQ_Vu(knR}$=Qz>X;MxuDbAD3- z>l6Uhr5RFBd<(6qC-F}dJ@38>UKX#)%5nSI&$ZPN+q^|z!^^QDW)u8aZeon!m*4x^ z99kTK_vk#W0rPyQ2|{ECxh{@px;eP8$&Dd&_M|(7;tf7kQrDLcX1*?-!637fRb-ZWkLW=)Z#P%BtHF ziij2?@4Lzfb}I9wi!-Ywn#68d5BFV`->o0K$iqSmoMF563eNFD=gAlPQT(7+ z5`+Y&Ia^y$@mus9On#?y9=a3R^01&`jGY4q-yTBI z%qa1Yzab4^k)e2LFO`dkn-YbPYDhEW&IS<5?MXA!#5-PN+|)fSHXmx- zX|R^_i%MX!Mxrq?XY*4Cf?ZB~pArk*?CnpB?Jlz{E=qIXe;R?Tzd!%9I9(@g*fZjK z9biJlj9hOB>^zMg#MKdnMZC^f(>Qa-Q{uzMy=Ve#Vs}4_E2HnZhT&nvr(HaJ(x(^W zdFMW7;`lPRJ5l_F7_4N=zpyimCh|mV)H7oD6Op24M2n|lBc2fhpUS%UG^|Q4&MbM# z#qq|c+T)v$>6ZW&WImoRpFt>;)*kch2;a-yoGTW19I)KEPVUBBQB(&T;K7;R)?87N z$ym!V*}3a;#op{z8ct2E>mu>`y0QJaqJ8eyalAHnCvHkq$>SZhIxTb1zqrQEf!Z!d zTnYVX2>i|}JR%1snn@^vg`PbuM-0d`o97_jF*{b2BerG7;AMU{8!&{#gI+JSV?5rh zA$Dy$P|}-J*82^_{IGkzfmk2OIne+DBR@aYK(zA^fh9I(#m-`q&%y>CR;q7YY#`3X zu*VWda$}gn*XEfxbFg0QcmvTZe-q(H&$~7go_*AB(6v1G-x6c^bLo*oS%`T!q(D&? zj%~{VUJk1yye_sSOU#S19cZ=ZK$L!)*8=Bvq{lX4Ku#a1;ndE|zajC4EVh#cMGiz6 zGT%SuW9gd{S57I zpBBUMC9O19d8IczxsVw{hoK^enlT*DHgN+o6bUp$*(}%$QEZ8aM#TSu@hJ;Prq=Z5 z(sRE!N8wfv;1P$=WDi=Z#RDK@y|>K+Ak6@xQyh2i?eKu;=|`AeuzAMoxNs&Tjuzee zF1r~>BAPsf1o5Vf##(kyR=Wqpru$-D9uQ~m`+TPd#I*aLz?rM}f1TgOnZn@8Iml`8 z5d1_tkY>Lg?)VT0!dm0$XG0lh9u)h+ve`qTOY}Q!9}*qX4r-loIb#kaUB#$+_jY|q zjH=&`&z&vII`yDv)0h`@`|gh6=0Oi+op?~}dVr75J-{7h(Pv{l9}@dN8|(g%xc1o? zUOMD+vGxy%w?4;b4t}n!h9Acte4{jT_nf0BLgHI!K>dpMP47xnj11csqGGfAUp{`U zjEtg7QHZ^~SeoFQK@sO%$pF}$!Lqyc==BW1*N!0l`cT%93{fPD_5O9l%BX!QLtOPf zkK^LBX=rqZ(_={1CgY{PbpSwujgCvFdN0H}G|Y9rw6-zBRm0L7`{5P+^fc_5$LX&J z=Nck^h<%MjZg^sQwGv{Ft}FYr6EwIOl7Y^xCgxB&5v zTfv>B1@(rE$wu)PHHOEkQ z`s~-^9a_NvylNxh@Bd<^@Kjc$eRm z+!q*dAAo70r(rIJS=+_mdU4eXB7Kx*p#&-cweF#IKbxRM|$dD(c^R*wHOuyCpg`Q zS|*={PmZ~utd%+>U=tfKu0BrpqyOp*QZbs2bgO+WHk5HONO)1p#QAQz-Cw6Ey0wV8 z4U!VV8~uFK{SeLM_f6Ge7c{Y!nMw|64y+ArgPm#TiUh&SZk@*0AplnXma;_OX@V~Q zH_qS$Erw>cj9;`{vw>l`u34R!lOQz>@L#QTyO@PZ8i5%3gw8Q%P{hJ@rhsGihC7r;Xt_Krd!7TS4keaL>D%*PY42aZfLu1Fr^D z%E({n_m4F??}$G*`yFiaomCEW`kZNw=wUig1z2G@9UXB!#ELT$ZD*eXv8#&U{xu4Z zJg5{@WUeUH+MzCv>gUjKN0m4<(@{$tTI;Bt4jppT8HX-8s(qN6C;9leZfo-qXxe?W zMx717XTY^6{B632A4he({sUdLHK-fpcns>7Y^|%+gYoh+0lexumk!`nBP&U{B7>D) zj(7XDdigCMj1_3$!01F~Uv}A7R2*-M@{R^}Vpxc$v4t1|%3R${bPUvgq6r{(h;jWH zIR9a>^{|W{#LMWVB)3+Quf3i7Zt~*N_u}QeevaM`z))*)0h#E*XwK3+@mMd@5r0yH}} zvU?*ebB`_hge1iGCQI`GRFLF84Bl@#?(i^eaGo6#rvBmbQ8&@((j}vN`48i_uFd@hU#7#Zr%+g_K1kGh~N%73zk8Xab(?PvSy#ALbK_!g?)pa*^Qod~7KxiD92yE>@$MNX* zHS-{=Zg4YhYqH%ze2#|=)p)QnEI z=tI*SYtcZS8>!JxPcUZ`npwL`cL4^!$ zCUlOMO$0omI58q(T*S?BSh-LDy4&2KBYNZmoz5kViy!IB0kh17qUmhdf$yCw7?piVYf16JZxl5QaJ-4dG~4)F)0g7& z&yTz7yJ#DaneCu;3b_P0L3Hzk0dmsu_?S1%XbTG(rshSH-ZmAOVb3J-HE~H{tzN%d5?|CFwXjS%t&$}uQr)r<1TGO+#XZr1fGB&1eav@KntyR3SS8iNM}$IXEduB z!_6C&4oI-Lvenh=h0rC<8t)sTh2epkro@nlgP&nEEPov*V4m#*D2@XZS;xV)9uOx8 z`h?L8i|vyTQ82vg2AHMgWrH@D>X1ph65}_oXptUL?%N3C8Phwu-9Ra)dCStFJY&C| z0by}(T)Gdyti3J+!mDaohUgyhx}}TdA$uY;BW({fHk)m`Uxpa%cn8x(`>^VfA(n-` zU1^ZHv_DM8p3J(MAv${A2Z$i`ymvCiG|z)GXqD$J%@lh)Z%U>(<9Q=8MYA-o6WmE@ z-uXIWM4Gp$j+mb2LFn?46=`0dIXLypa$DH(EM25roc`!eWQhCH7^*D_>> zIy5@-=M%E%%`7!Kiw0-aiSM3KT)%)p*=|v(SF#cTE z;wR$0_Y~#2pEjQqFGl}JKhNMs&}C0iLDf@tHG%(oXaFsku34CEp$k3KplNz|v_bIJ z^=B2f`avV=ioIfAM(yx_O;a8ols_sU!2A46yok+lU$Ow40oweJU5guduokBz2y)}6 zoGN<;9Do8o+fU~L`0U}TM9X$|T=ARyR#@!&VMAWY$ zPeB2AzSo@*(kg!NzsJ;(DZl)(U!#ZyrKH2qP>{CAfFs-Nj18Po_&zWIhP&KAEP&c( z(0;=?WzYpfwKeI60r*SVKp*s)&lNx~ESnlFz@&a`3WxCtjfSfDVpM4F9n2Yg-gWkT_ z@Z~0hRwXTDkb8{qjoF2N47d#)JKn;n0I2Ayk4{5%sH?-NuTnSki8KW+Ed0~S#`8d6X^w1*dD}(nG{P+$MHI70oy{Bexl;bwsB#x`TXG|GaGYHh@Pm4WzUU>!bij@iTr0q41hF_F zccg;adl)OVqB#VPo&SsT{wMWfe6N7%`HPWf#8cRobHU$* zfw1taTxeKuyllcd_S4}$O0l&Dj$P`Z;r2v-;=)SVNG3LppTvsS<(#SiWnXV5#q!u=GD__GKv~ zv!@2-D!8g?0@f_$PkWXdRc@YHtcwPHFw4x+!a&%}(VL7j=#c*H^7|5vZys4_eBe!k z-?^1$BA1)B%x-|6X~CK!KDXqH_#hA4H&~7|Yn%qK30%+tWbv^#K$NppGvQ_$qla-k zP5*C@gBfNJnpNH!gZw=IO}K0aVv~eYD8wNQth2FFNw!qg^i03ThkofBSS7S%d&gKR zz~N<*U?^{v`cPp1mS}m{V71Ymax7&qO`+;C^JQ04G@gNNEfuI(wyb8;51RAy8NRLc{AJF2R$aA<-B`($%uZvaXJc z^P7Cj#f5{GyEz1UQf&Fe4a<)6XJ)6YKKaFQWj zV$Xkj-9o!Pp}V|N)fpk(#z4cLYRLHpZ8X$jgLWs+bcqr^#KX=Zask+Sm)PXZ#g6Db z{8@;e@2#U?a4uY|&1R*$<2sr>e%pWKE!5vQ_6)z-_g=?(P<+|`HhrT!e?hOz#XJDx z3>9KnImpesoub5RB1)ZlbvUdNoCQS@*&h%7V0(B|G`z?LxAjNq_2HkVQ0 zXDoOr&H}3Iii;AgvSNel?FTD}>mli;NS)pu9gTd20XkubKOKsyGf}vLvT?eLmz+5) zo1TaOAsZjMzBn@teME)-F0$maA|IcHy;Vs8qyfrCXXK~4!8z?E6L8-)2oThv@v;Qf zz@HP0qlW>i#bS|vCkAcImDp&t42*r-0y6~+d@xhM*Lc~I2u$iB%?V1xZA^?Exe{WBo)tjJps9+nZ=G$SjFQ2R%E!v0ZUad~0Wr46BJ|e3gz}^B22UuQL^}kpV?S+{EmGm{%Fma$76O{+3OgS_?+m0 zCfGv{uYq)o=|Ih7mL)eUF%#e08?je*;S5JKQ*~Cd!Si7)u> zg!H;#ogFv3ad$F{4$oqhRYgVO}moh|DaIr}95XC%CQ-Sq5 zsd*vcDDq%xn1i`Jh3hX!cav*gZg>h|J?aGWUHKz}%y_ZzQVf18$k|Px)v9{2#%ni! z=mz$FI!B52ReomGbcuO_zrw2*-bH|sIAC5qUO8bbj7B@3oQ*^)Ykdvv;_2gbh@(`| z8{6m^Lv`w#v;*NPiDG|zzxi8mL1Am$f(qk{&ITIWscX*a*PsdK#V6pq@NdU?!F_=L z@f`Ir`7XX+>imFAU}=1l1udd!x`i*EqaVkFGhAAS6>v)b4~Mq3Mxk@a65L|59dNUf zdlfK>60%bLo$wfkMmrB+nBmc{PW;Ncac-IAtLmN%3$D)u_(2O$=m}&3owrFdfmMPj z5^LUt`h&0}>ETHR4TM~{fe4e#@&OD5kYXLfpi;fZga?c(9I*m>7Q%SCXmXH7y{j2j z7GfR(sC^T7b~JTNqy5#~a~}7ckLOOAQ2*g8`1qSWl5Ir@^T3~nmBd@Rw^bKAbk+MO z#q8BVYfNOU;vs5?Mtv&1^Cl08w|;h9W_`6^qwSRvp?j4XI;t^(R5FRwWJw-(}kzRF050$Z~t~jHf99vfm2=kd~k&Fe9ij97; z50q=YW+qOZ$|+n`SM-b(uBa#9w}{ zsDXvGUKtC9ANh^_(E&5ma*cy!2@a@6~J)G3EN_^ND z=LeIAFP}1>UlB0PARGy>Yo`29A0(h=JN3OF%c;u)J zS6pPBjiq*Eij75Yq>l|%u*fxuur<540zn&Fpl^h{HxY&`y_S$pliqs@>Sf-3$e^S3 zLQr|9^yVmWQhH+$rL5#|MdQ`4iXH0X$RaEwE3Y4s!JB9D33^;$|M6`Xi}D}CRXdd; zz~3NR3rm!GL z{qbOp?hgVs15PI{#8!p}CG*~fw-?w8gKd8Y40o|frw!~;SDOlQLR%|#v55icRwV_J z;?Iab3Gt^0VA1o)27YH5dINZ#HE)Ox*&2LZH(mDAA%Y;M=rpck3g$U0#kf=XcQQ(# z#)%eayZ;N6K%%fw@0BOor$0JMpxV{%ZD9a%zvaEfQLi>=K)MpvJJm3Vu*sEWbcOH1 zmp_i|p+IO7^IAZ5w;0h{np&yRqVl;T=-0QKh>HnDlvYY6YVKw*#R4>k#Q89rJiaXd zCZ0rl<)Tda9b|ATZr%#&bjY^sMU*5sW4)CKr{$o^sw!}J2oixj4deK9%>=FSoWQHQ zTKBLo-K{?k+?An<4H{L^AromDmjcuAq8i@gC(F&<`HSu-bLsLhj3{+~4e3R4v6CK6 zh3g1F0=1VFU*tuiGnIzb2kFyU5*zURAA^?1g2iYK^e;6`nuUP7wqg_DWKBUKXSpV! zSGK;qmP<<`Q(|LM@8292&N7P&sPL%CT!|{a@ShMf;@U$zwLBwqHlsCyDiR?y0- z$wH6=j*frppJUSEk3KR^eltU&iRb>3;T|rIMp7Yy5!aK#CZ?J;A2g4~H9a}_w&1Zo z7x-Xr_-!G+R{ zT`2uAvSZB0Y}Z(XVP8%;W*dOO$uEST6i+)prtej(8hLbR`k0B%fMqA#e&`HqbkLYK zSgvDR>fwA><11}Izqig{gL*L6pyPup?|)*)Ls$Vhr$c}>--F}6x(Pe;RXsLZf;z*5 z8Ty2ghVwnldYwZcqcOo9xYP13TjCuH*5D5;r-e-`Wwad==H(*(M7lUp`U<=Qs-RdP zB`_7be*rP68k7yi5Zk^6FoJW>K^Tt0aw>u+!s>LU*bs4XPfe0}Gbn$O*QabQCXN2Yypbl_xUxN{o*9=W zmPenymWBwL$Z_B*ybRpaFYT_wh>%Ki@tl)s?(qzolo36XK?^egEZUV3#)eQ5fMpYYC? z3;9;I@4TC#Rs#!ceRR_A#C|J&-H4xuU1T?k!QD|DAd#oTOt$b)@yi^`{a0}uw;XR& z?@UwCp)h;Y-C|T>Y=2X+q|n>jRO~E_;mrBM?9)v|=f>XgCSq{o%-L8EHTGsU5i1(I z!y%~9IPXGZak;S?$W*iPP!l@a#NF7GCO0*=H>LNQxHG$gv@%Ee7Zr}T{)NO8MnIw0bWXXWl_Dz;`FF_3mqqX=?;rICx{%Y_Qh zY0+2>X(ARi_M|D;^1nxrfOVM>euu*jeLMw z+=G4Ou6vy3_tC_AU7VPAFWV%R-)G}^!+pDPTwdi+^af&txs_#Hfj$;%dxXk6r);s# zbdD&o*h*XT8X~Z)=yF?(3VB;>u{mV5Qeud7N^G%KdJrK$BGV^8eMM#c-N1OMZXpIontVN@RhTvUj| zi`YtmDna+&)N7jgy)pR}C8D0j&*<s6{&)gFk zOIdm6B#x(;-dP-*?sk(7nBSKtOgd+}?JR0mQG@&f*uj{z>Ur}g^!?-|2hM-T`>FVa z{0qHahKdDd#Q>0oTX@yiLB<+U?#{Rj3F0Ia@>o!efr-{sw5l+l)UALbjut4jX`emEdR1_TI^I4gKHL`bfdIai~p zycvxDdI2~9>wN}L+Lhx=qVYZpO2W7D{#Ne!)q8_)*1OAdSM4bAY^4~ETg_}Yo!Gi; z8dD#=zXIX&rN<^b5(HbsUw^YC93Q%{)+*8dtzq*svo|6xQI_*&aHmiS7wP~t( zVWs=f6F=Gm*(+QY>yQX_XbnuI4xm20jZlXf=f^c+Y;85cH{s;qoA~2n!AYRL&5=gm z!=RqXR%)}vKH!I?A`9kKiNHn^q-XPh^$sz<2}l!w=|LjD&M@~_h@>^oSmIKE=pPyK z-VV`)kXs^YsdT}N*4p+)DVl4)HeNwivdr~__+k{U3|U_n?lS?f+{f1A1swzc-N-Cf zfPMp!B@XB&f~Jq?@JK@cTb^PG9utyxE2W8;y7#1YMbevgbeByd?5|@{Wk-t?O;^#) zxTt=FTUIAovC-zR@cxxHjKr_mP4WQ&O;$E8-iXgSJEneo$eyuv<7)hb{CIf$guM7v ztE66h<AaMbl7&x=u(RYTjm0bMpyu?lnpvq3*?y? zZW=INs)U?!A3&n5GMcZxg^2A!I58k^=)6O8u)z2%+-?=i;IG zvp*RV@i9{5h~EkEJ65CnCnnFKBrB1o2F>`dz+hO@AZ(V@M?Qvg{w*GezVy0y^tsZe zf2S|RviWaIwZiTa0Q_GeY*x2RLLe;5Ln&X>?Fqm?F|rTMv3Ur_G#m~yJ={FQ^uX!c z#){xLZYdlOwd`$3X%#MF%oNP*lSA%Qu=a-3h7hd_VYS;!s$xllq{Qh_G6|tjeJS#& zQu(V`#r+)pR>1?-oSc3j1R*|#9A;~TP-}d=UUSa6Vu;Si;HKK`0xr$R0}W@Hi{Jo0 zZUs$y7ZMPBeA0CKx?--y$D1stxhsZ;_;{8dav%`VLGlkQWH*MzI0@&gxTef)5wXmX zE5o2(g2C&G6E4P$VXq_tAESrcw}jQnKahCYllgz%!&$UgID=Px69^cBm4D);l@nRCJ+lbadX`zI+ zgiu23@Wj^ATOw(z^xdvDjkMh@HXX6OHVzF?uXS?hTKP z5oZQRESwDkxv*33!ItD@hKQil64`=s$7rn>-?deD5joS^h#+RBXHsY%MnCzY{;K#P ztSreH`E_|tDrcl>Tv=kmgMn)?foUINK`rq@Jh&1F2c?x!8kxM9(XtZD?b%x6M3fj} z!y3dt^%}VLgHW+$Q^6izHdWV8T&TEZamV8PbWc7ma$X2t1S={JEP=ho#|I@}D#yL> zGOINF$_6>Zb>d!5mQ6i~X~18&Wjf+X!rjxc zvz>#dbvEsH{4{WC0RJfZTVWU)M_Z$Cyfzf>nJ#vQ<{()w74DoahA3FMKolKrjTo?S zxNW*v;Ax`*g7{8t$4dPDESa{!?l02WfOAt-_pJT2oj=bwN;${utn`Mil;z zsYV7Iib+j|zZiom{_Gp4zxQu#b zb`H0@PVFmY$iI05;L=I3sQ}*%NZl{snAKhI^bSvY&Miu31P56m1`uX+Ee!p@8-aSs zI3qGXDt7utcz`GRnvn$&G1~k)_NG<@+$$3-M4gE(p-6WioI_lmv+T&Rs90{talB92 zyCdS5`VS^fC$c^&&N&PtDsdw>qGBFEeYhp!o{i9zh}$try`t`@D9w-BE2Fe2>Vm`N zMAW?!rOuw&%lD{<_o?#2V-e-={(eY-~HLK~q~CXmY*U$LENsY`I) zbkwf`Jk;6__qJ)GjR1SvYKM>7bj6N#Ry0OMG2iS|(bJV<>Q5nqr-G`v;0K_I>gtAz zKEbhN!x4Uze#wq-1Wu)rd*7;I=7PTy&T!3csYAW(HAX~oOjozE>I)iQu&cP=1Ro8S zlfMZ6hyGaJxKX!H(-Vm80t844L*}=a9>#pTR(Bw-xC5#yVvXT|OLDux6?4Y4TOkU; z3?i&Us%MCbLS{*bCWIa+E8^1FpCy*~gY0h!|L?3!z10dIwMzFfH~Kdt`X>OfAXU@C z8$DQ4!s|Vdww=Zc7MYQ@z}WJ}Ppl3_274H3c&6NCN8XKM^YjEzU@E*7L9oi+78P@y z@Mb&!#8-&bbR#o7(ERMh?e9n3<{owM+`g#)VV*n5quHLj(xc@bN}#ku-T)E)Hy}X= zdn^Wf#I0*sYysI~?uRy$Zi4a!A$_e)1P4e&44%~)!GM_VohDr{!)+{j(+ZEWpxzf< zTlQ%@nlX>=SY%-=I2ELr=4;>M7=|XZCER`CnPBlY!_%dhX`aG8Bcz%rsaRsnDH|k$ z;=7;8m_N&_f(sPxqG7F2USF7t9xr823d4rH4(d7pC+T4rhNtS>NzNMK!3q&9vvEA# z3j6)pth^9ETFCG~CA!FIcrpIrK|u3Lpa{+oLJ|0P85Lp}JPOB%gJKfr#8S&K9q6jkeV56AnM;^myKu*+{}$UaQ;Qa+eL>$ZOo@zYLs7UzozhBF~w zY%-lb`H;ePTIK`w<(#PpC3k0MJ+PuWi|UCUVP{M|F~fDb*Asgp&XqjT+;a}*iBW0J z$~>_;-INY^Un%*qw>VvV-vi_$(k9yTp!|T!bdTLHRT2fDKu19<7spIwNy?W|eJ!+G$dgN38d^I|sCg!WT`Lr}& zZOo@#e!e=DPjBa!7YG+AFX=k!Hdb>J411}K_HIwK#e0_B-xfuoM(^5Ud&q8Mi?^kR z??~Ga5mnwY6!3_MwO6;dq#Z%+9dXTL`na z)DFuh@VT9~=%OXtgy?#bk(QTe*%P4SgUJ2^Ozd+(Q*Cv+QISP1DVQGc6*YgvOhPdI zRBE)@5r@g1kLXQ}k5@v-2tf^cBOgCXbi0=WLo;6hHOUQyF^!KuFzgdbOg8!WplNSa z;MKC{DGWS(=4!}BVCW>t#|Na{S&7qjgj3nbYd56^D=JcIhN6W^tyi=|skarKR_cnP z7LMxTP~1_&9iPTKYNkVr9JSV=ZH_$Z&^{-*o<5FJsJWC%$N%T)n<%8ote0mGw18FS z;{&=4HI2Bz$IA?xQ9fn_#|N3$>Y}MYmC(^raf^mnYP?0$ED7_`yp$?jNHh~6j*ZSl zKosWegh;W@$Fp^3Nd!Yeqch;?A8t6<(C;z$LMM}r4NFZvzF@Mkq1fW%eHI%V;vqg> z9&&cL;+k|8x?+lQid?bJak{zUY&e3e*TcwMPgf0dX`HKOyY!Z;Ho3IB1}lI+IiluA zXn90!j?kWnIv%0-BC2JSK8RFQ0yi|!Ydzj*1n9Nwt`3a6_En6Vx(y%ONyFZNmSNdI zqRtE1qmHC-Ehi3udvfn?H%gjs6h;x zmopqHNooQ7@&IozRJZqdh(olOd*ZTbPxfF*v=d^@d z(*Z~4Oc@yuR4|WhyQMlN>8w;AvL#k^x2d14M%h#ncr~#ste70}QcOT-$a4*D$fLnm zVMK8JCdUhmHPm#278r89LCec0AhiF$VuHd&0AaBa0U7dKz8#^1dks1Y0VIRYl;0lA zcvvI8P^@J@V{wtT0<&d%GlJuOrh5+b+LjLHm{HbOfiZd4;xipXR#8aw4tcm|LdYE= zX?Eyw>=i<8KS}L;sc@!8vXzdf+Je&f!7!YW^R;k$3;MtecaIz4wibE}Lr?fV^)ES} zpb-CRB4e;Upfb2ZYzRp1(!&V$JgVW&=<5`YY_MEHZ83jJj4eU4BV zD8sT95YPDt7{*_?2MiG!J3H_XFP4wXe~YJi&S&fH0-Rr~?7;84zajvi( zC-BcSj^Dk0T%)tLZH^60 zRzn<4VB&FPpP5IQ|vGskLFRK@m|4VnrR z0Ez)o+oN=I0;BhnjBn`OP}}|z+rMB1TgYPX(13+VOVT}wAs|D-m@$mZAuQ)&BL2Bg z)qDPA?$J0H7PyzgAR^GfTafyk>UgYJtmBS|tOBdyZSq*5T|8%A4Kj(WUSjh#RN{0O zp&zq#b2%%Wq&B3FIf9NyT>J|L)zVUbxW;0~l#s%l#U{Qa;;aRmiZZ{Pl~rn++`w_C z<|>xfNu3waP-?7~`0VrJ3Vgihm6x!GoJn^FnXAcE%3KO)Zi`GN=Nby7G@Xfc;K>+n zie9GK-=w}K%r7fUbE`>flT3A`AN&s>nxWK+q=an*Ztr5o&Qf^8ie8l&r^L5l z&W>pkUoo|)ZVndm5FW+MblEV0jDOR#$C)(9jK%X`D{h)(3l2QC?s%x1E;&E0?!$QR zKiJIB$uvQAm{bfZ$#RnbT1Eg^tVA|8>3ib~;;r_KtrwqWmEIT^%BsX$gjk2JHS=((ufV0{tD95{ll;~-?SgaSBE*9?dOc#-7 zn@ktp`@xob2{A@nEN_7=Hiq2hO1u+NAKGFt0?=&ix4l*lV#K}O90u!6QIO?OTNPbU zuMP}T>#&N4scRBjDQ6tZMzI|^+^#EFS|%GFND)pM-^cM4(|yN=@_`3x_bIk_Oo^qo zw+R%z+ih<)@}=B0inc0sP|*qH_HyV$#XHD0$!}3w1b^GOu{ifR^ABzpQ1CFiq0rfzW9qm<5w2{$H z^}wkSZB8J9*4(_MF4TT*ieGlY?!|7Y{#Hz5@B44z2y#@8e zhIIE39+8nTqMm45C$_7e=$M&ttR5^$-kwHcRBn@bjl}v~Z&86bnCq1kh;zB##fGAF zp4Ym*i064b^2P3abt9kJ)pyS}q~QfG&S*qi3*8fibf~bjStmxhL=}ujv5nWc7T?xA z*ddQW<_rcF)4Ohoe%!aSz?K$4qG6kRF|vEY zFtSG4Vx;K;PZCN8vO^F#3666El!5KwlJoLJaCilmu_>LI@oSs2n#DUiMPiU z+2nQylf=`|$O5N6rQLurg3>Pns6z-ag$+A>8Jn0q7@97a=_`2K<-G;SzvUHUlVy2r zL!iY`^FlNXr~*mjWqj9+;=6o2vJ_t%J!EkxC+=IUyDdV1F?y>kI3PSU=w89IMp@p} z5NL6{P9f1Xq>4i{Ba}BtQX8rINa~i{ta+5GLb~`1P&l4Nw>fL1?}&)LmbW3|i({6z z0yYroEsQ{u#G4rrZz=C`1SRYZiHK8S??43dQr^O-_|Wx=qM}R0yN0V#cUY9hMcvs^ z>Y3&irO}YI)Ux8SG!dn1T}M2irT_!%mO7SVXY4mE&1N>*NlzmKW%#D$PKOWO;*y*n zAV^lEv=*-9W~k(5dSnNOQADAsv`>$q#OE8lp}lB$6QS#Dc?Yo6w>%IEcVf;~h)sLf zLZX>;M@X6=U2xAYvX#HtrqxyV>)0u9*rExB4b{q|Q-->3(8VMNF!q3nAqeCc2$pprbFq~& zz(do_@VeXZmIGD=b6-X$oR?8p&yPxPmK}e0*SKsyX=p{~yQXEpAuv<-&YRe0dc9D1 zrgz>F8%z&7oI|DuagwQ)yUn8gmV3qmovoT1qNzzmi>$DG7gomjb1*CH)4V-8_8Z=L z-V6Vfv&xSBg(&=mdWH{@=FNHmjOQ>Xz;2@YOL+D(z^haQGlLYf zL*6DS)&w;%L8>(@@tKFhpJS`FHZ4uk@eXFwYUv*VgiSiHl@eDznslyg0aDv%ls=+@ zyD~VcN`+Z))AOmxGiyzo`Fz*n$Dc_3sEQ8&AIS68FT`KMU5J`j@_|?3(v16EA>#mo z!OS#VdqV!Vcn-k5?t!3U#Wh|#2{>*(eIGz^zhsZtZ(+QcO3rdZU~GB!;IpBaq0*A|93^5`r^{}`k!na=LK!6?jQhQ&3}uRo?_6XGnHt3*=rLfichF< zRr|$dZ|0$^0r{UutFFb1OW%9XExH}{YANI>eoX`@jJU1o8g{{d_Ylt0j0Z9_g7Ptew7-o>BDZ8 zA--1AOVC?#|5XUWv*DBhy07U31K1u?XE>@OBH|rKmnfgrb4r(Z5|FZvS^4@f`DZ&jRtBcB^p`zh4+eAgm^^)zchpjx-bn46Txleue=^Gop#scP>uRlP4^FI zb4$Eq0~KsR><$dxi`Ynlx>}-vDG^*xvNAOl7k!RETlj84I}(3I$yXJ5=Ed`;1h^u8 zEH{DC8ztDE3IL#4NZuL3%TR*v5u)O$Rq$Dz$}$%J!;BIO66g;L_=sLNmjr4R?}PkN zFNAGivhIO`V?&@Da6nfG)i|MJMuGx1bg<`Ev?`t%YMV!HLJ}CTT$7e=4 zH+*vehpg@4s-T>OloXCEuf)>z&3L@qJ#|>iT43Gx3HszZpb*`{_2Dxt(1R~~gn5D2>A z)hf?IVgRW9!z-R$etP7|gHefUeCq z5Zh|IfXtYpMn>1Rb0YOo=k>M&r*tp=qssJvZHUSrD zmx?mLb$(z!Jg^_x5KS7VH9ZcdN=+Wp0Dg9x>2x`{(r`bdeIKwO=)AnbXXDi)al=rsPb?2xpXgSpn8hok_;iwiRdicL}aU z8wTOsR0!3c)*27weKZA6)v%3@iie{i&A3{wbGwW=ko8&pxpw_k%? z<8PwI-vo^r>j)Qa*2G(yT&vMGO&!2bY%+j8@N}TXmrV6!LU(gF==N#@d#Wk@EW!CFpTH$>`*dWfuD>pjiRZrN%AWC*i{U7j5Wv|hJjtngg+{-L$ZP<>dri!mg(TJ zp>?I$>-bM)$$dU+?Zjc^i-Xa|5?u^$iY2<4xt(ENG)8c=EI&he!(50+dR<+pNO~WJ#YN>Ip0AzbZ3~Njj<+Q&#yj4oFlacv1!1^T zyzyai$np9@qu%lSHsJOQ=K!J}mZQQn0<1yh12mX_F2m@6N{+%;2_cCVB zE_UwH2xzYP>VA&3@1+WcA+}HzTy#Yjr(l&U);k4LT@Z>C406TPFk9@QN7NBlU8j{t zLtRtD=>Kc&)A~Z50Cr4<1WFR5IhtcvcK>6S3j|d5j zk6ZDbTg?~SN5oj`MVz+ml@YM3T3sUIK*&a6z7u*3p*S)Zr&r3{-VxEu=8FsL0%+OZ zunYFOVu30^z~vQHupHP(r=Y(p-g63CyJAwf;N7s;8AhZfy&sl0!qm={Z@M(dcV!SS zDHpl4%9Yz)I^fFFE?snG%LvF&2NJ-7Yb)~0yXDC5!!^*K)&lSpbeD?zd^5lqrAXeD zH-G?-lnRWh5y+H+W5WI~DF9PGVE#vZ4)ZTe?v;Wu|LAk5VYeXEa4j4G8snFMT!POE z$R#+F5NdcSKrW4flgW@DTB5tb0S7%Sb7u$PO&|Kme-DZ8 z$IA_Out}GUyGEK6uPMy%4iHN<0hauVfO_r;=RwwTcVpDp$CDCI1&OX-CPZLr_RxpOAT{v5M$YeSw76A5C#mHEhNYU%y#S$ zFDIP}c2YxF+RqnvAno@tp_mxNp$)!1zG~c)DNwl4Uvy&LRkuH$3Ny#w$0QZPzgm{J(^Xk}pUus#=#+<;+(8 zomBkbi>_rOtMZWA*7eQrL;p`~q7q+ zyZK2ize=WVyIMGck`p~9#AA_Wn)p@(ulw=ufT^W|(}dVnd6lT8mOV_Pez$rt+q7<@ zHwEwYZ!=M~UwoU-NN$LJc}uKKL#*6-Yn`UXF6-aA&sGc;weA7QUwHEmtg!!nJni7- ztv$7|bG7-m(O{~r``c`|LCGYw7mUBRo?xndaneI-^Nbp*#J~0Ecbko_N@j0bCC`@+ z^9d|b?PjmWr9t8n7L!%Xx8E|LzU#@L_xRbjO0vGgssXSeGWjxQs@Z(cIpSHTCEqhf zle09MR575G&WerUF=LJ}2^0PdPIH#L;Tks9jpLuO#%DCB-EBOea%*l30RR9%+0`tH zHGJ6#%^Rp=YmOWY(d9&)ipq!#kfJONZ2Jg&hhr67WXM5RPz`C|JVctMn%t_<+G=vW z3~83ZA*CVZBbafa>^xh8#5oep3vA^}t4Z|ne(E%2VH$gdVL(QOdzfK z+2b@hN24jXe0GhG{@B}9qQTrvg&8ax6N9biZ!Qi-1Re?aB6blS26rjZ$qE}aLyVuv zmP>U}p8=tph)EoA*GZnOU7Vh(6-)+=k>(*_=pFvP-@!b&62|xNWRD{XJ&m~jMO3X`_s(iU?TXB))?Zgc?sRa+#9J%0+mq62xd&$2thL3a|%O z5y9|lP{Fu^m)y3}20Tu6e2C18Z-u&$c<~-A5txD}0f-$DIAzOGi9vlrg*MB=Nc+7I zS~RwoIGh=PfOf-+0t|wLEb;(NRuX;Ws;M!Ze~W~7)+AKda24d1U_%fH<^uJu6XS2L0YiSK+8%4Bd* zZAVZ)c{2G(lhDn_`IHefX*_@%<2DA8k8j?Ole$Ov5Q^?@?N3c%{1i-RQJ!6vYa#;*6tTERqJ zY!9{x$9T=wS(kAp>6Bx2nxe}pUid^s-2Q-*nhx*(7-zF;N4T;V1|@I=C9oMK@IF}x z3~Z_SvLnNRU7X*d6>QSQ70p|qgIEkDP@>COIxW_roJ2FBcgX^mW;0C!)GobUf)}SwY~Zl1<@TzY#&grQ z6I9hL_lSONHi@Yt-xKteOt}-r3}P*j?V7cPWi#_YbFIZr>EKy(adEgF!|C~8K!gmb zE|2Qe!gz3jK{JwIIJ{c&YhD`Pv@6}|R9!ipU)zml<%G3QSL52BKhUpn(-72O)d}Mx z&ljmXEC1HU228u@5^#}Hbw?bHr$UV3+ejT^y9A@|&s9uy=#;^FBGba!H5cH}zU1O) zJ{1PuB1RxyBiR`t7(v%a+JM|{3%}j_lly&HxA$wi_z3zv*hF6lfx@b^-{a>xDg=oi zNC;bL)EVkW8V%9pL}sTc?=&}^qHn(c`y^I8sS6$yf6d0B@=qwM)7xGnrZ%=}+L~X< zvUSS@mF}T#Ml&lVXp@z&qQ6eLRx{Izbt>H&{|3Gat2I)!ePBu~_)E zF!ToF@9kQbgRi-@k(iA@$@cXCg;~AkC&XxeEB*pAA+?~wGM^$>UrlLhbKVbbD%afr z1ho9+;YyIQN-$7_NZgiWM)i^${>P`uar+s<2l%^^R7KF0ZZ0Z<1Se|L0%pn_vUC2w2B5Y0X2S&+oSeyLmC9q{#8 z*Oi!~9|x1laA_S@z(4;#9NN|z=3SB{xWz^gyx6SdULQJgj_l}AezK=}o`!;DTJTXT%A-}v(2Vney9-d^-z2>+ZG-K;@vDs}1wfNLV%zk_woe+>S7EeBzKyES!Mqa#Uo1{mu~_raP` z&5a<~+D;CXc@7cd7PTzU$F0`t^5DQ@L&G;*xGqN%tFItv2kTp`Y2li=PMQ5R>Y4P) z;LEcSAq5`s<$-h>)L>BOt@Ymq&&qs~()yA&jzhHURYZ#`R>cfIPg_b6%oGr8Kp5w{ zsn-(YN_Ysh@f$R6*k#5O;vJmzkD>F|)b|6=(Cxn9W4zz5R#E7q zb$-;rSFHaPPk`F>ud)r%f65zP&=67vh78zfFcPH<46Mf+L-6W-4J|M#K4-#q^*)&= z5n&53wGQPCuo1oq=1pG7@rlJuGF;k|gN_`z60IodEj>x-+{>IPILYxy4t}(c=HTA3(OjI_ z6@3K91H3OB@x%w-M%t22Ytk#q4p7(h2h;u{o>PAiK8NhJrzXi|(*FR_Zp7B1y4GtM zYjZ)zbk|mp^ji%;)xS98XH3e4I6+$HJaI(jY^^IMIj1O|C)T@-TIY#rk(>>6MZ0JY zj>klEaDG*Ad^-9Fjt_cS1MrOW(8apqVER|^>{A&H4%HQ%>$o_cR>$d;D-P88Ten=X zGple|p4gb(lkT(Di&8 zR&TI|AB*ZQLH1iW%voPwEN<9Io6}f~D=b*iSZpqQ1;?e+0ZJm{!8(5z-%)=SEl5ou z>Xcj*L9p#tqq6}zWyzdBghvt}1HOU{d|mQ=K~wc|(jF6cHvke;rK+Y^9^cRgFy3Kz z9Z$rnC4R%r5QoY}FckCkl;3ZXi9x(yKm*MrjC{j6PJpR5@$!7@3!+iB5dS5grLUD& zb=kFtL?d+AN95D=c=9z^yuRYDGsHJLp?mBgHOqidrg_m2+w_8VCZatGH$ynWFjp9~ z%}{3zI$+2XhEE+$3BJspW}}K$!=pg<04-W%V1fkbQH(R>9D}B$n#C|nF4i1iIM!-F z%1_f(K-OB3CH@%3R$ah)O%tZX%0Ge-#m1eT_Omd;uXGa_QK0k+wysbd=LPo3!yMcN?xgTq0L^9tq@$i~dLj2FEp$!n`xC zbXV!fJduHLxPZ*DzxT}%F<-1pw}-^U>^gQ)Oq{Iaj*5xPb><+;Q*tu5#>9#o+dU@Q>}fe-PFD7i9I-ts zyJLQ@0$BP(JNve1S5ZB5gxEBde2@@ zjQ8%@?TKw3$Vxk;J-auJwkGlW;r)rC9giX!Z)P0;rMqdKGwEbSg(doNX0F_Bhyw5n zfF&*qhqH~Z;0n^;pv-*P)fA0q;M!gz3y0^*uAv9yHgJZ7#C?k`#6((II2<05YeF4|Cm2)}*{;-c2uE{n!#()ucbnv0+m@6Sw zb(Q2kO|;Okh~)E_tDA!C62p%1^^GAhzyzm_SQ)Z5hs5rX{2)Y!L+V0^PKPR@^b$e6 zOOOWY(}?xEVSGIw@}+O_a$c+tS>WHh5t4%?wUw%`r0%j#{Pgd@6v)r-Zx-MB`ONa) zCj@L*$c2!|RXaS*5gk;xEi_7$y;_OkAg~DX&Qy|1Q29&D2!cB&S*n*SE?b!hwVfFH z29Aql`rBbK)X9LpX0adk4!dGu*jw$2O<`}kD`vTBsY~lzcdtuFT{SO4y&`f(ga$<1 zNf8H(DpE4&KKiWX3f z;<|Kkf06A>vuUCIAvQv%NV;yDKX=$QcZn7mRJN1u__e!GHm0V=%#BUXn?zoO2rGoLAaa&RJH@vSj5P zEm^X1w5;#BJ-a)zQM<-`=Y0S9eU6~Er@Fdw-MZmks^kN^%m)(vuiKN5G|6-rK#dnl070# zZ1U`_DWYq#+c!%LOE#yZh*`-V((97b`e%xx$&ooJ5E{ZgQ>jOqJt&RNrCA@R(R=CU zu5>z^9+{OveKR7PvZ+I+)hm+*Wx7Z&%k+~vXVI3-H-wmz)eukiX1xM#glvW6s>I!f z=e~>Zc=2Qounb-TxCxInuZNachAmC+6finXoX|G|$kt|<>XhYhjJzgOImymNe6| zv2XO#;cvKE&pxG#lls@9Pu@{<&z-^2*@Cp$*6=pq;*zWZP-`}@~)MCVWhYs=r3aj_Sv_7FWu?4vrzpXaZ5(HZtFmqudt8Ec5 zcaB95?2M=nBXqcwg(dppy&&LLf0O_n_$%NCV!fsQB6k3}XHivuCqrmq_dg4lxLBFDx<6Ra2TQ>E62IQx==na0}kUz^q!bctCH2m`b4zYn$979Az zhyP&WJt2fizwZ4-M8BUgEy?=SwJbREeoTz{N)Gsa#`=c06-ZTcbSJ7v( ziqe0Q+@8DvBnFdJNHjYBMsQQvL>`2Sqoe@0bEe#HvCDHIfg6Nol>2QQdC}%6MQM^t ziA3kWI1Vh(Xw3+Ge*}4OLY{?7456>$9lrmx0J(K0H3aBS@jStIygzs? zDEi8G#--Q6TzJHLMm%f1NPz;f1X7ady@9F=}4bNd4LaLV*IKY5UlRqU&B9XMY8iC?pTN zz*16M8DOSNB}(R}1sSzd{HNGFj4c#=@gc8?XlgxA@vw{Hu3(3x$w1L!>0Utw+L%y8 zY?dbd4w}6dWc48GkoY6_K-Iq`44_|TbAtUwybV=_cR+(f@B(~(q2}GxaEbmr*!*FxlF;Wm@co`WHEfkWF%d#|_$df~TT2oWJBF`ms*U_1x+z~l5)fg9xCBLE-( zXiX~vh-y5iHtOC6;5h3kkPdZkjsc38uORHgP^%2uY*+^k+8Mjom52wtUvWh`k~fH< z^{h!mW6OPvvFi9^YNHNAy9a8bc?gn51$D2h0a_Dps}2BqhCMu}1E#l!p+*`sudu;D{^9;tbk4a5gP;R&`V4=46|AWusW3wV&yi)7s!lGaEx zqK&Egn$#_hSQ1-Fx2il$^5SIx;6)If^Hyur8j&|sHSzhDJhU@3t85SApblIuWGNkf=#Zk6v_Zm+o?%gnG)A%RrhB_3VrqCn_mdv( z00oi(=I4Wd-V|L;cd$tVO}-j|wS77>ddA20=76{9x8hA9-gE(l@OQO51h_H^@7Yd!UfDf;T;Apk5fy~7rBE?mX*17vy# z$R{th0D(7OKaW{1D8McxBCn%S&j^T4FLU`m}LfyJp%-=SJ+ ze+lv&#EC+x@>ZIRrhZY1cGBA`L9+McQIkfSjSxF+y8BJqo=AaEvuVWZBv_PwHLDVK zYV2FQcSR6owJ^Z_*{*rhbq==b#lcpHUzw#tu?b^G>7es!ek4HBitK`Zg(5Hj@4}ss z9WK3zh8PmCa7@;{^E$XVz%pl0GXv{vl3^_}XjZ(pV*Il6@ZvlQF9vNCd0;5VD&?7@ z{~pMuhKJcR!Z?F&>KXDTSYi|y1VXHhm}}8d%e`*V`M4q?FjJP_7vY{&&Bh38o_J1( z=OUL$y!J;%Jn*pYj)15YGYFa<_@b1yo96}eSOUOs_!pT4u4#%4HGrDQE9ZpnK_dQG z_l^K!#qc&7;ypv{Gsxe=x9x$_njmRp;N2u6^EKUa z!z`UF)y$QeY`lyu`M*N^Z{#2!OY>2s1=^DyE)5$s?;2Biep7%2$eO8BQG7aax3Yrm zbs=7lz@qiX{&=sG=AF{SV9i^}(SKhT(U-;*W%%GD{zkCo-9-j=my`K1*p@#bg4P`dDtsp`%Xiwrq=1ur#Li~&au;1j96&k(*4O=lL zQlVxo&}c@&L}I+qFN!CGctW+-#a|+5YAfP+zEy$i?ykTj)>&8Z-HqyZV{g>0%{s02 z6FUvP_GS8y&MHw)A$zz>tqp?(+sNYd+Pieb{*$c!qmtPM03w!6`ZdmP@c$&e;a zjn7qex^wHF2R3M=y(WIy4DC2Z9w4|b)90g){druLU$Yrllaui!VCqI-A^ja6M;CBs zLeKHRI8(D$Xtc0QAM>Q*gE5j>q=~nAR&@l?f(Cv;Zv`W1elGg*)^TYNEMjLUpZ1Jv z@GIO@5HrUSm{)oDDn?+kg7#aY3Bd4Ns8E0G9tLj(Mb;V!?~6nNWGN=u6c5L(JKobObirzqpv9 zxb|QX%qO&yr$3Gvd>#6}Ifjc}XNB<=Bt2;@lQcg*{bP-O33`_rcPP&VTx0Ri8^+%H zjJcT@-o-sx(>YZ-*nSm491CEWxxcZlgUg8&Oa;BjIcwme>U_vDWGWW<2ZVvdxx!M| z62of-{zs`Ge=U|!uCy`T0Vef~&-qx3%db+ux@G!(dOGNCcOH&%ccv6?x#(Qnm2r9_ z;1+81KH3aaVXfgoaj_TMz69%ww^%}9_r>8RU6U{<7MN;2Q{p~Fo&<|DW?HKXSkbPG1PFO*_&p#{lR-{ zq}~jJh6x@8>trf4fxFDqRbkNNrb7XeFe$3^DXFUzF?9AGnrU=KMXfCD@izyTfz z-~hpH)WTr2w~>Yg!E}NF^m?%G$W9h+5ipxVf9ZY*v^UG0go}&qU9+j3^5!dAqr8I- zJd~b4?$FM%aDc&8V-Z_L76Ds~rAdb811?`L#^vMsFEhNpl0G&fJtTEVz~ze_T$PS# zp-uyIIhKQ;;#Q5~{AFA;xW@wz4WIhya3?aR`KVhF_Q43=r;dA+4o5OVV=bjRxbLnF+@7!STVzJ`nB!C^g*i z68wT{$_E?hx&nknXbL(6QxGZ;hyjxUg^n4aOB_@)b?An`#OLDFA1~`c42YfmcsY3g z1@eDVOb8`+!f2vN7*OB)YfW_ek4ikVuQm+z##gcs*=l6XGzXn8z1XlENO|E0_ zvfE2G@}Rb`zXKd%Uf>OP6i&Lj+|MMz37G;p;BlZ(z+p_D*Thjx!uRZCg>o`Vy?LD2` z7}PU?I4syU%X7d&aZxn|EPC)(Eidn<0jbHa5i{$pdZK*6RZ+7dUx_bLOUxpyfESZt zo@Em)bMjs$e#&EwjF<_S55-ue6+aN(T%JxfvzTIbDUd5PIbWl>K!91?zVNOnU>0wS z#)(LmPaB&Tz2}v}oT?a5vu&KjF~e{4-@C^*C{Je!Ceu2cC3eWN-&FmSQbbgnpVq_%e$TWkRbi=i$6y5WQd%_mT*H4n~k?`hFLbt_CkC*%mo znvZxx*eS(>fHjA#vTl|^Jvkp=ojj;bmy>sf;rmo;4Pi&6LTqV1IJq@VY`8kaK3x^_ z;kxTT;Z0!YA`eEq6{L1B1b@YhHK^cC$`eov-W6V^i7!C=I2iT?4QIADo&j7SXL4s( zY^+~(YriMN_dKYg#zO~15G52~ArE}I%JChjo(F}@GBP(aQz`Sj+`wft?oh!CD=h%` z^M(=-dA(U|>w~f_c7cM$@>cG>WucLwV%x2Qrk4)r?6<+~kM%&^GWovnsj!x#e!p=U ze(7>5F8Glux#Hs$sARV&vzx?Zt{Oow`=2oevsYifF7A`BivN)>i$`&nudvmzyc`#0 z{Lhv}J{X=VaG9}oA^w$vW%mE?;WAeW%j}Ecnye0&`Ib^cjd7VPg=O|{jmr$EJvab; zAQ_i=lN8H!xmJpUhU@{lVkz60bXCeuCVe6+!D7B86tgdPnY6A9j4|B%@^j260fq&R z06)JEH+BT8@j`y=DAC@;&4X!0(r+_ya@+y6I>!%eW0iVt$x^9-2vZ`UeTD$gwZVUW zg=UqN-rz`4mTexp-mQWxcxSvNxjY0BY=5`{;37~RG;}$^<5R;x$M)P}es>oUALaSo znJ+!jD=p@f7LdD_;cL&1w*UTEH`-$N_=lrv!o<92@aw8+W3!?=+7*V&?4a0969g6L zXRzoyk}Mzq&I0Q$m=86vqGjs;PF&64HvrH@CvHO)j?l(X=C6}=N)I@rb0gdf(12;=Lm8kPai@*Ba z4>YWLh$2&I8iE(ZC9nwSbUi`M6!gsBo;|6109!iw)O&oAwftGjuG=(Z*{?c9CkRq`vW*7gxM# z(-u${@ptCJgoJc!%q*R{mZ=ab{o~fJY2q77&wH**fDLBN^n7n7^9ak}dA+Qdqo`-08v};R_`@2|KMI6eZ6`xW_DF zH`&pe$$w1X25;7!BO2|A&ps5K`HjZdZN^eER@PN=z=qgL1gu0 zCdO-s#u=tN2m_xGZ&l3SFm@x#1c1x5ptxlO*Go8g`z{_0*6kvl#>C&j2XLPB)SYgo zSYK@Bl!tf}UhG$pRv4=M*y=LR_^;0vKWgq5PDBe_K{ zAhhaIp>zM@&MC;o)J*R%8 zQzNmuehP}%TR$?Wp_tmhUDkkFH*}*7X>FrFt-PHU-JY<)T+rwv?K|6P_jlkha|JCP zDC>`J0waa9?Mbm+vQDl|DD~90g}=^vesfdNRiz()0+C1Q`=1b#T<6NSM7Ky}cM~x< z0%MQpkb1}ECSr2xb9gJwnbSn9P0t+tggBIr;Kqd+IY{ovz>%^bbAyI-=N$I%o>TXZ zolV4nx_D5X5Kt(%JLUvdkc z5bYj@ABvdth@AVBX!bR^uc>J9sNVKlqU&RNt8a=PkFCI4J0AZf-YR<1-1H>v^q+J; ze3C9c>2_*Dy_>iro6!6w?v^IBuZerM30?iB+5B6y>RaZyZ&Bx_No$+Z#imKqpQ2?? zCAIoC_5XIxv2W9~Z*QZXPgBRI6T1He`q5opI}2vX6!@wSrb}pZFC%khNW5=2Q$uit z`Qf3ESR^;G-no0o8)U(^CxWb#L-pV!9C`vu#om@9plz^LTLkA^JeXo(^_I+2UiS@f z!(|NGFx-bW(N3fb^zcq8CK}=GQp`5Ev4KSK7da4~x{$2+Zx%~%G!@@){mLU)* zE;>;1Ax1NOGgeR;(c~u83vBM8!3N+%oEZj6?Syh+Cc~3~27G(iz0Rv^J}BzL!R#UH z3HoYjCk4MH-5XsF9g<&F`~rmBzsgmb_$Qn~xbFD-#h=3YcNXuXT>K04<7f3@(9&W* zQ*c9CgM9m;54FV+9ZnF46|p`HiJ>8R(*kjm+~Lq!%e;!twUc(*G}3+ol7*d=GFH(H zmGmBdRX;_ZHBMUelY)tjqu~h?>qb{j8=K7%q??JJ`$ib}a6>2=iiNF|c_HAUi*EYY zxGWRu>oxRH^qKi^l(VqJldNu=^pug+VX;_7;7-0leiuq4GxBa2UPzGw5PF3o#>F!}{-_(=6paA~L^Kl73udLfwMS#Pd&?hPYYhi#8CV zA7ziX6~xInF124eP4SUC5%t26FX3~J_`pC%Oq1RP2L@W48{(klAbrXLCvx%3jP;tg zksw=Im8i1bq*otJ2ldtu;bFL*Qd&h|0?xk44)M-OS4_12JSigl19ti;S6s4hq6aR9 z@9Y^7L)`zt4`*C=U<&n#xZ@*qG)eYJp#qPebWWB_lBq}XH{e{7>~>2j36kMTVFv#> z9Y-)&I}3e*rJ=Ajb97wb_y7>rJa1Dku)U?|V=(!=99@_#s6@i3KcAiRG>lb$Nb zbSpk$Xezi8Rn3lv{@Y5sVUmFto)eYgBLkN7+0xk}>0OyoQg77S{#^t*%YWc3;2Iz- z@?CNP;Is*G9KqiyowcqkYcJu@Wyp?of_y$?qkfdNOA~7~7bfi;jPb=U1bZMGtj3au z?W7`cDd&O9a(5u8Gv={Xp3j!|&|AIFMg{o4VnLFJS-m)*Yh0Bue~LfSN@IrOewr%K zXheeiRntm>*&0$q1s+H=z^CN3?SXCI zT2lb2>YCV7RWydDeehyQbcHIbYcJDMYaij}k?=vTFdVA!kJZC-2|j*_H7Y5)>h32$ z`3QNJi6i1VXw;%yjjI}WK6`iLySoF!&H;LZ8v$4JpSiylzq9^De=e;fuY|kcgo0bG zVNbV2519++@n&XZD||Ffx%#D$*kne=hs3_XIv&&*SCKM0=^Cq~E75UB|7aK0_dmPx zxS?cy1c2=;Y8g!RNKY0gSQh)v%!ni>BOUpClqD+39cdGW`V7(H4VWgg^nx> zO;P^uTBypa(UklD0bOCS1+c7Iyp~#VUx%k&7j)M$?2~M6mGGkOU?7IAIw$36Q(O*iBycW190FsXTV&BP%e`PxYug*GXrBGb1Vxpq z#aSypyn-az~1K!o)wZj^TYqMD!p(pbGGvRDCt-7C-As^UT3MJLgW# zgI5Z~&jT9ms3cP?=)-HLMVq}pAuTVqimR$ZH2JlOslL~reTr2P1J=fm#^MbC>N9pr z^18AIiyF!71{L$50BEK?xLFiwYOzMME6IcCO3@RbhtP*B{SJ6E+ss9dq7d$8@HE=I|C2U$2vrhd!2!bfzU2PTsKr(N!_HchO?i2*>%PhT8tMK8{RdJ&EYtmeN(%`T6K9N?xe#G^kmHf)y2;XSE%IzUZO8L7dz8GI4I|s6l%xX#kYx6{n?N&AhDb2a3D2 z#y!e&$gj;Ls%;O|phB@74NI4AQe%MLFedb+b0M)e1U(0ysUR4=9W1vz^UMFu`ksG# zhz{sUY826+gaeVUi{3xH&TJ%B6_5n*TX9IbuSOFMPJFSlk5pICr}-`Zji1I^#~6Zq@j^jK^5{YcW<>1xK!8k9yd#Zskz#SME_?D~I>M zfxXaxyCvg;u7=Je@QZ$zas3BF_PeMfLW`CeZa+!ajLadDx|jN|W1}c`U`O0yi32xPpY3MUgyLcs4^?uv{XMT?r?$Kr^uou@Xg z!?$!<`VV;S`6`4fReyu8R1lFaYvVDL!vJMu&}cqPKVK~SmY>z!E0taHSYnEfGmGww z!mFrGg6nk2l`kv7VY<*PY80Jm7S)ZexKI$>`x0W2{u7U*WC1L8{7c#axkzVmoX;_Y zw0;>b&Ft13M)2uHnve7pUEP!j*YLF}3mE>;-ZXK{bHNZS^U9lnBvu zAYm+R1qa!6Kr1?E;XWK@6z*$@sd@w`VvBXYvQ3eZqim-AF|2oH)Kg9VJ{91G&dMd6x3=gJAd2tS)lZ(TEiLFYiB zxC`%^qN8-?nxdcS;rTcdB`h%2YT&25XR3WB9XHhllWv%*YlzyG!O?i0o}El@Uk@Q% z+`*t9(;6Zj)g4TR6|jYcprdrq=++?*&wGbZ@c59L5u$}5wI)PcLTZ1AJ_wNPJ_#vI zjCOHc1nv!gKr^C$4$z&g5sb03C?YOMrywE*g`7SSvCeXuM?@RD;faWtVLKnXVxMxh zxT0OyndgfBu7~I2U3_z)tJb@;%~eNT`p8w+U1}9k-6GU4qDDoiFrwx}XlX=kh|u5p^>{mm?9(l#qn$q*P{T2c0p=z-siOZ#CkT{1+n7t56lxWVji z25I#Z3uda9`vh~AKa*sE&)MB5dcZ46XNax& zl#O88_X!(C3(bO!wnI4`0uJP(nlr%>V_=7L#Bu4gaA0wDPANc4I@^^Pts=|uM8S_? zx$+h}VwY0K6rEA(V@0hU)!m`~jvDPyk)!51wA)dq9Xjgp9XQtSya*@*Ariw`QG|{h zrCHN8npmzP@KgRqL)7(`-O*f-vXr+QVaxhP!|o=GV9v)9@D7|ltvSbVTQ{7|h((nV zJXyqkQd^}uAnAlJ6@-?XQgt+`m#GkeH#qJt6{ws0Y7ILBt3h+1DR^J^kUq)|t56iQ zZBjDnE#t|$EETGA>H9;GlX578q?_BXz^ z*Av5K80kU@PYp5E^oDp?i*7ehd=hf;R!587M^33nk?t8b@$2ZYg>+%K74lDUA3*wQ zBpc6rda8Fat@YG)j}CbEAl*3uLR8#L;c0bYh|V7x z?iEioH|6wXan%g>_OQ+L#IJpodo2m*lJbxTMAO@rdt!aqUE_%(uI!d9PB7@ZIG1ED zND-|)+0~=>J-NrDmdUb1GA&MVPp8oOl(Nsiyj4t^ds_D;_EnY{v7VY-5Wo(xyQMEWsLuoBI4H(tMTF0nhovQ zd)m)MbmN?{8NY{!)|#xr978++hu~N#4@g=j?Ol@A%j}X`#J&LyH0J%?Q#8!`q)N!d zVI%#X_p11X^=JBB>4XUCpZ*R6K_HgoN8j!~Hq9^ZPf)dWH4@-zNceESxExSzj{$ARdW%+LU=G=vm&ps><+LeW;3ZAd7vvkAFrL_G{dQWxB13 z)>PH~72k#Cw*iOM`L9Vtn*9oMyf-z1+uR&H22%rreJ2oJ)@rOPeyo~#;@4pE)U3dg z7S*mneoba?Wfk~;X#A_|8Na4uU0osnK^cCvldiTOt!@6B?D$*q2`yoder=Xb4J@Sh#sevJi(n(BLT;fXw}zb2l0g2^gPaC?EYnu3wI|8aML~khz7)kvffef zyDr7c_>Av5JU=dMQ|QI$GkFs;qet7p9fUy=g3c|WL}RsNH69uzwc~-S^I#IxHvf`` zIV4{04HQ_=AvM>&Qj!a8;7Rgu5)^e)NbeSRJ$eO-D$P6_=$fFY2^#AGR|M#1I^g6B! z#j`MQU;MH6rueP(Px@1$XbzG6VecvM)4W7KPJI3gdKo$#OlH&Rmnm+VU1)BmIPRR$ zW@n1Fo*IxT&U55wjPOPTWoAa2XVHR8wK|jD%T)U^ z=|ZN1C($f5E{ld`C4LOe{XXNXqPeSBCwU(#9&Nm4;$8kba48DUC+d!v$&$tdEseb4 z{Z0HsbtX9a$BQcNg+F?@Beo^gk6(=cioSLQaJ>FvPABot;;RFUB@h161(VUASU%D6xT5E!ijs5o()>2RdJZKM0$(qoXP{LDyQd$oUM7H6JmYpiQ$$rKTr7QgFo8a&Zs=G)8-$}*iPp> zu~>0>n{qDZim?u-7dXzIT+ubm=}}>4S+2Mgq&vCJ#9Xn*<>%*Jr+2P+H^S+i5$8r- zQIN#x#YxVQx}t~2>9L-(t}a#;r@Q*e&h)xse=`4ZDcKoRSFA|k^qv$4oKJXxU5Si9b%U98S8k(<)@@ZDST9Hp1^VM!YpN{0Kv-xx_U$v=6UF)d< z^{8Jx><=sIWge|Zd+WvLO06bj#eJaCCF)nQVN{xt<&n}=QF*!+%dT|QmBjH>y3}g7 zlqz4YwcW0ObV+bb?U{yPC{^c}OpqCYxI5=IT zI|qGee+~YlkKwFV;#iQrVK`HiSTFhcVX&(xG2P_!8q;Z^#J~`zr-Ymn01yl9$DTgO zmNOhN+{T1oVuz2|;yv5jf|w^;eQZ-}rFyYzvx0;3bS!E`>y+B9=!jBh75UecYU5B> zM-6ajq@yM|ROn##?RL_xICLh^E{oWIl@HOI^x6bU?QQ{RJ{2^4gY`wU9rPoHvppm( z8rx92wWge6AxZ%1^y_Bsdlr8f?%_-G-N0JHtY{8^aWrh~QQ9N#)XF(XoPyS<~;UL1Vv*h$>>9h+oz$(&1aDq6HkT~5pj zj)v{CVQTBzJzVPMV%QhEX&^J&>VB%7ua?8*SJ8D9*LG!-tme<+Ls9mf*a&{+m8fwq zl#0)+FsZTB0-*&~qF*io_W>Mi*(kI?;~1AchJ?xHpaJ2swG0Ed6z(h?O{m;GWZWuU z7;X+SUT#k_t;nP?Fxw>T|A}3cn65Y!HEvxs8&~l#_+>@qTJ}QOu?)Ue%c1nk%IcLB z7=VDoBEjJ!5Z!08=)O}6-_XQK&4XCqOjm$Y?ZELQlY-=&xcrVPRbL@L;i6F4$18h= z?ynC^r@%i(C_p^RI(Q%Ju%N=sBthnQ)@Tyno2svXU*@Lrf3^FAIp!D3`TzY1H{j3o z`*FauMhu;{hz8iOcsuhfA3g{!{@7+XBY~}K@G5E^k{3bB7{b0fDHQHwi^ZWZ43z8m zz&sf8@ZfUD!#iUvcZNj^Eq6WJD(#OfI>o2vU^{J&O;h3q%PQtTu!{Uztoh33LS@ft zvpj?QUqB9klwWs=1|)zVz$KeZpv(8xTs#=A!Hlv&OFF92-m<3b%06DpXJyxaV6!Tf zax2+*s=G>;y;zn?xW$JwmSHktgdq-T;a*Z~*Y+dLt0ed#<`5Nb#cVdE?pBSco`8SC zH=9v2P-zozVrFWoh+4R!-4)P2$Ir*WvFUfoAO{$y=dFeFm9Az23CGBr4$2fG8&6Id z*?7`UX5+~)wtCKyYB@rneOW3-eELEX%HUSAm34q2;k7l?;B5l`1)dn+4+gid5Eq&A6=D)s5xz{ba&z=qRwI;B91DhfLa);IR<1JjWX0{E`eL(RUn8<56_RWBgw~7fm6G?sRl7`hMHp1T+>=(($aWQJo<1w02XX_#)8F5 zy>x4&P6NxHu)N`Qqq{+VJeM+n#B+)qAAg+DoDq0rI4ccW&Yo<=!WIfW&d{U5ddO^+ zgW&D#ZXnCm(wVDL|4G*z_>a7@DNBrzCZ6{(>utz_!^)$>v&DQX{S;U;ZEJj%*sPin zem?G`;)U*Er%#sH9yU>2E7$DiXN!^UkMQ0#*V~pUI>2EoOYDfa;MF}7aa(4I8%dmX zt!G}(6wQ+PJEu}oK7b-LC3R({=#i?BK9$yRTqekRbH-!>P>Azv%;5ZIGakYxCuC;c z%%L@zcVA;3OojB6?0Yz!{m+{@KJCo8JF&&!CP%-(--VJEXNZpjT8E`ZYM%_?)hxqS zI3SeOArpj9U+=wH&WtS^d^@(YeuAGqflnqNp*41R;^#c3?E)m(zC5PU$9`Lw5&3`c z8RLJv`p7__QIOS}d9WinD~Mp0uFt`vLG;`e;znp+rVM#p zh{sb;0k2E*9jxf)x^s@X%^bwF?hk;xMo1GskCQlCcF2^$rs!@u%|ldZ+Sg6mU^Ybh zd;&H+Y!OKhtKUEmZ}ueWn6OKgZOCM9$g^$D}Yc4&2u+KE^=dTSr9 z?<}``sQnhnt9okLsJ|Gq&-)f+XzTG6j)>X_9NK7SBl&?n2A$E(agZM1d=XepjymMf zu0&M~D#mBagTO0;!?51d5@Stx^oc>1LSXxt1cgcLaDm@0leR6OXuWaFhl5k#egOt$ z{0pxLfeNezGJJ^c4#D5fnFNq1V>O;!m*Hh0(bi;7x7ccmfmJjb2ekyiCW==RPAfd$ zhd=jesfSard8HR5LzewY%M@Jt?6b*WwN0OwEZz(K;!?6WZ29%@XpNoUEk&HLQ}-o{ z8+QJ>WN}<&k4qM_9A{XvSn4dnH(R^*z+_SAI>^7wb$cX>&8`c#v<{Ikc1ae8A`Ymx zPe%ZsBD#BKr(`k5v+;bXhsA%|a~Ggs&z+boCM9pB&Z*QowfIDh$((D6-evH=>FEfE z%bl1Gzec@By4Wb!5&jqyN*b0fu7x7ebg{^CHl~Yp_T5|4MH?rA^fc#=(dpuZ<09QT zEKjG2yF(@*Y^D$ax=9a2R%%k7W`P$&It zs%WDeqzhD?aj7_46w;q4xi3ZZb6ga+)^SnX2}dD)I;^ir5j|ZC=>aa*_F1<9iaZdJ zOH#zg5qD3DXrJ^72-A|>MJeKDlEQ-m&w&%+cF&oe;)`>h!XF)z)$9~8GuZ(-^NM75 zW{TL7%vnE7R(NtL8IG{+QnK5niV-Ppn^dtrq7V9%28?wd68P2k7 zF(%Vlnk`mkx_Evh)5Y`tS$8eS7Avzj|IV!JNp-}$f`A{t@4G>M) zU*|Kl5=(Zme8aybJs{u4j+!)=s8<4AJntfjf-K4j7+%)1ccuh-C*;mfO!me+DZ_Q2 zDN@D+;ZX>$x^7T!>8_M?L^5A#AM-14x8D@s$%Dd|Byt%*FiQaVt^tw>?B>@FW0vZbWvu&&21b7fn>oqP^C&s88-C?{P<2miC6KEnnVqc#A}p^jUo zPon?+-1zzlfjuPMBCH`tF5-TW}`)oINMN2!MZbjx7f1tW7wjOHkV^0w79A zoHHZ>Dn3DwQb-Ip<${nHV=h4DkA%FD7EQNYXcAi6?lha0+1_zQAKR~=R*yP|Q0@`xDyw`wox| zRL2wa5L6hNdt3vMUHG5|v{*3c0R&fd)ajyTA$>!OIh6#{xcH2YU9&hI#y>*XO-E_o zPL1YhDM2)UY5w5e0SE>rMh!1eFt7591B}QeTZ}U>f5%Fvi-Nm3Bc#m;RCt@ewa>1 z_+$u&7p%*GKM$V@;YzcM%iI=HheC89gsWHalH`K2DfMaTR}sL2-ys0kBz|Uz=5^G? z7R>|VqS4Blq-eHMYZNV2342(qa+fr(uP)kf+`s@`0YYa~T=ojSg~dL_iX>mP#1e~{ zW;a{NddyPM&VGyr{gyE)=z?43!LB(Ya9mohWj6;5v(^YO47yd8j~O*azQZ|(GYUT6XVO^uH@sX zH#q>PD$?AJ2A~pwBZY+q6Bda%QF3 zy#nEV_?Nuh6)P-vnk%+g;K+n{Y$K>_jSD5@VK)iM^D#>wO6FGa)sX{WT2UBrjok>2 zUneLHmyJq6`C__37w(8Hs8MwBnZhibKV{EmNF!D1{WuD(_^dQrTH?B9!iL>kKZk0b z4_P-t)Y%FTv#4L zU>3fL&Ak#gJ5~v2v#{~7gBEoj-1}B&-0--q|4$lV8 zqVnml@gBj%_o-e?B?xocJBwKW(Yq7UhmG(RgU%!@UT$&jNx~rrv4HQteRXfWjxlV~ z-JtgIjIkCUMTVo44XoY{npFk57T@0eeOfvW_11dB$vTZo>|qQGkJeZeG?u;u&E|@Au^(D4qa#hxY)0R^gux&c2;m1Blc&0xet@LqBdHUL1@2q;VhO!I-tV z)E11^)v517p1z-ju8ZUh(5SU$_136!qUaZldwur|^1X|E=gH}(QA^G0sZqyIlMh%0 z_;8+!*>^WI>*5GG9kp_f%-k@vET|x2Smv3=R=R%%)2t7C#1s;XVl?Lor ztBppVRMLZ$=JP9LtnVI1i)W$0W8`2-UnZ-qMojEgDp=QY&Qv#9OLp#Ha#fcxaT3;S za@BVSV-oTWb(rR?&}gz|1t4@~8UpS(%>MQ0!qLdM3I3;SrHH}$mdP08tF#L%^i26N zu4;&R==_?ET}@|y%_>;m#nQYVuDar+PfmA03X_FZ-||z>>O8k*6|4_GesMpJD{PO> zRE-8{zBQ4rhvmCEp@#q63S$1nreN{TmFL2J?`{@9caj6-#uH>=m7c3G#x-qm0~bfo z1K{2R$A>dsqh6X7pe2?xI2>%P&>j8O`?rWDA1h4HPbT;0-do~rt2xm-rH5spU@Fb@ zKUHV){^YeG(VndGe)1fS`$O-IXtQC6-VXwBz2AtptbfyANl^7;@0UaWF3 zOsxK@=DlivD_5zKV-Fv!rX|H-Q5GcKex(u%57eivNa?pSs_5HIrwg;{Rnx}E>mGtM zzMnBJ-Hi8U+HKW!S^O1-OlW$X4r<`Sc@CT(dg?G8{KWCz=cfG^^Dr6mf9GRtn1K|9 ze-RiR`{*`oSW|R+sZMhfh?E0aqb3>oe5qMJ%+_J#0lsB1*_(-0$7czI^EeH9EbYfQ z(J_0zZ83?hR+jlu;UQ4xSPckw0<$xbcM?rlsFH_of<2Gp-9^n5QZPo zJdpPc)MeoIQnFpdBr%xY;W%4sigdpgAE<4GYLdTXqs1%_T6`klQHFm|?J3ef6|1?A z8Tud6nwO4c0&IBY%;Q*V<%!49{-EV?`pp_>=h0KO!a%Erv)ivBX?JN1;%Cg+ov`U+ zm#dnzJ1*)8sFd-~#1(ruyMQj!uILw4Gq)%-I09Ti z0;icwh$f8dM2q+STTx-N^5zBBu~b6#eJieS*dU8dHSoB?mA7iL?@y&6vYyjl7C!++ zNN|W%LKg1Vy0rk`EJI8bn4B;r06e$5dK%4&>M8{2m(`JBEthP#EzutV&RDHgQW)3D zh{4OADaEYh2D_uhj9~#icnQ2+%)nJjvzZ^`0|%k_e;?L7@mveEkj08uxS-CZzdjU>#dXUy$m&32HgGr4*Xk zc)ZHY#^b}Li|k!O8KXlqGSnpATfxop#}=r6R+D}Jx1)9RU6?*J72FaMgqN7kly9lC z$l0X9k>(L-C$%gj4{J%+H9DVIS!|-k<^&sx#s#zr@3qxkqziO=o=(%s$wk;izwR70 zgnwGgyKX?!1fXECO3yoNz~G*ZCxu2fKQXfLZlRriqYVyHm|%{9Us3|bM>XTg82bTh2`JsH)Q z-uxy(IqVH(>V?}kX|yWdP|V>6>Fx&=P}#roCsv?arwM!~-bhV+$jpa;YL89={yX^P z0uRr}t;w2b%1BM?$-=Jm2`J1paEc=9G|gI|!C_4SRc}-6zYrXCP=(DT1^4~M^eb?= zY8KGefw?|RM+7xK(N$LibQ-Cx@vV-i8Jx9xXv~4Wk^#Q(+6+xC z(ZEQi_Gq-Ve9gXObpd(S@5R%ikSw^~0fc`TVg|VJ(A+?!Hd0fF^e#+zucn;_4}uzY zZ*k-A{sJR_KJt5JDnbY>GxWgI{R6H`SIvUjZn&nVX*8jHUGDj|h4bzQJS^J@x=SoB zZ@nf0_|OHKwUP%!9nxr5!iz!8O1}4WEk9U;8B@}vhb_#l$IztGxi!3WZdn8QCa(fT zUzwGPGxJdk_UCVMlhzUs(Z}Rri|NGUIYqPPF@B@krqPBnO=4v_R{wV!{aI*#Q_)BN zHa_EN@u(1wHhM$6ss2I#8~;k|N{B7skw&kJU#fTL?Zn@({G0BBKn9M1rVR1fV7m@j z*woF@2VW{m&BY1}#ImZhpe$tJ>fqY;T%+j17sqA#xO#{ugm|J6F40))^taM429Rb|4rNm74$!>=)%oo z)4`?H0hW#qh7DB0u|}h<2DI;`E#VjW%w4HqUsI9po_JsFmUznjfdZFk&J^~+#PXi5 zs}(vejIZM$4^;L79h{ppg2Xej1&JTRs4<$H*+i3r24G?Z8UID^0C%6U_cK7`cv{bx z9)d4_^6-!tWLQX#GAulwXuJZ>W0?V;y^%6wCL?4fj|_p+&q8{ewD5c%d#toJ)leKk zraL$!1~T*VCNr;#CC-|4;5^VN1Q}&as2$COSB4+Aas{A$y~qL-`apuD#s-GNm@_(D z>)zAty*eG!t;;%nl+ebQjQ~)%Z~#mJT=GK0-e}OuvOO3atS8ZJCuQ;~Q;atwV27S% z-Ue4qGt2qVq{9ieC!QaFPw!6A$!jsmG6c3y{7WC9147k)SEqRiU*}Q4Ci~M!4;Vp7 z2g&Cq`f3Y<;g65$qPMQYXS1*VJM@Q?Y)xTk5?g>lQ_CiPS!RY!`f1$c^a|l7@A1@ z%LUiVSS@7~2=+84Kjq(|RP2r2ot8C5D3aa1u{do!cc`)WP}+F1)3m!b78^r9JX3&$!eoGX|I(scK*W5_>qoehAE|>Gbw-t3;Ln(ms+XE@L$<^UMF!R z@o7F&OI{-p5RUTTOxrF7d1^0n17m*ueS)x#DyJs?$I7wiJ>2P-i8(b91Zd?*yZlm41`3u}em#y(rJ zonb#7O=e3#Dv}NZ(qbmEK0zsfTI{W*Ptj<6!qn$_HKP1SHFzxl#75t}^0)wSxD8Uh z*<^1dT2fZ~j1A%;9XGhCB>htyV)B)e@1h`Bz+cyA1L*X(EILX2zMar9#XT7O{;CNf z|5rZ*gEQId%5v`or_&wkY4IT9@P6jJMQ@b$3ChNY9jmcOtp|v2J0P8n{^4syw?#h~ zJpRt;o}U$lqw^mqO3#O-1Y?NJjndnLUI*I%1W$VeTMN0gs68Iw-K%~&&Sk(dc;rt2 z0}Zj?&w8>UO?1&x3K@zr9YXwj+I^*U=V@l8n@@>4IK6_(G*nNC`%uxJIKQFS5-W;M zxIGyi`K4!|Wrc;b9AFG<7vVp0+$V@J3RRs=n1g3X!Ekns?dXZURc%4|kiZgs+r!7& zkm^g+t<13uyZ#>|kYtCFK9e^fy%fmam%Wgj%b zTI<2Ff0Jy&VA&~%1}ZR}-6owd9bheAG*#~q-8Ab)BQKA=ljD!7txhAV_lA0p#2+yD zVEV)vcar2KqV`%&S&~fDq852EE?cSMKYSM+FfSHGg1=<{zC zdeKL+i^6`HDfTw~ra8FcO~kS>SNaN#qq7cbjZT?xGfKOJFbt#7N`zV&nMl8Dq@9-H zg3)NIDF#Rz>2Wd_&$mev=^V zDNl-TIX|NxBs7K%IBxjM;;YUx^v#6lsC3A@Pq<&>?uTE^x4(wFQhUO=e~B8v$)TV2 zIVOJ!<0^Mhv(CY&l{n$>4zE~rk^p8#1DL925>|Nh@$ZaF#|mxqP4fbYry=+br$!w$ z#AMDYU2Kzz`%52T@S8233-ahVM7Ng-Ii+^5wM|5)3V2ApYi&MFm?wU-wpk=zIdE4R4 zZJ3CHEHb>MhFBg@RqZm=F@ug6KuU_O4X!}lw>(%!OQ}s;!Sln{tU(&}PN+f9#R7hD z_~&(#@E7N0cGB>`5Y$Y^u21WT(JXnQ>s{Pn!+wpd_4 zhB;=tofY*_YPg~TrRFn8Oz9-%b0)lrejLSpNZX1}##Bu=9C%|nDc}+B9!{Sg25vPR ze%6K6zA$YIm%fa5(;vLYhgZ})9)#U%frC_c#+Ac=`0*)m13UW-8G&bDNAnd3d}gGx zE3R>JS18ia1q%W;=lNCyNFr;jN%;JA+vTFT^d)^3fq zB)(Pr5+bth#0G;|B%HMO19jTT_`Aa|C`0{+mG^tD&40hV|ZXU!CH+JN5$ z69uklx^*@L&h6`18SB0pav??U3#pSKx)4&$ENXA5-WK(=z7;R4xb>KGkjXrVALBIz zMZ~n|OYI7?$%{US|6}>?G5I6$izLW*e@ZQRnX7)+Z1{?Ra*-rF!!JV8Vs(bK4N5dk z!e4)sp0tbgils`yV2gR)fg9`ZB|Nugl3YNvm6Ez>beOl)*hCKoFdj+}-85iat`E?h zUs@fN_&pXMFza0S?f2GOA>B`^1GX5!R4ih??XI=O23zg2>9DQNFqMUBt*E6+Xme1B zzx@~-BpV1jTx%@@$)OtN83nJz*z8pQGUC9Vh~RFEOXu!x%y|3gNLt(-Ps&u~ZPPn!1pkA#-0q0IXIA>7II^ z5RFY+p4T0;;&Fll#Uru`SV4U8%T8O?KMWwz1-lHp$^}F<7Lcg<3QXE2|hl0rG zi<*h6H$tD`c{xT8gOzY1>b0oFwu?S5x)9yamxqj`t}OmCMD z%qQ<;p6G66^~e`f5lfLTt|z6>sVBNIx1|`AlHRkP=#ZMdzMdGG=HmIo{#IP-nUVk+c?kQ+tm2me42Wj zDymQK-u5IOwXcuexp+PY@}Pi-R>yrneBSy7eI-84KGibfEB+J{w%=R;^--tYfKveL>;oX^?rS_5wUG^EWD%qVs#ZGjSas=e3FM}*bETlAlybf9C z7tk;b)}cQLx-kRpKiFT0y%H`HjIPkw{-gLe5B!hNqUzZz3 z^el;E4C!HQKw-O=JUIBB4?H~EXcoePx&*xreI0+4rQ1q*2CxUe;Qd}iyFWcP)lYt* zC%my(fj&f|XnfRe4roR6uc4aLFH0YOe{UF zY54jyl5I5HcX3}0IvsgRF+W(-GXu|OkPB+iophX_Ry?UU!XMp?ug3EG!Ce7GAR@yX z%}WS};y6vs)o5ybFt`UG&;Cu}^3j6a!x|pAS7Rf$`T@6)Tb>ZA|Jt&Tf zjGYk0rbi|t>_5^uK8hWVG{37`CfY$!gRq0zB(V%hZQ*m<#RL$n8U#Al+N z(_>l37!PVj$Hbmy?_Dz6D?7_`O?MJ(n8<)l zqbi&_w{9bYb;T#$RrbL9GgiizIYl-$ivUbztxQX0%$Xgs@`LRA*(?_xl-N@EWuaJ; z*rWQ$`WTspRNRtyU&8%~0RO)lpR+HGUPPVl7!q;ZB#k@?EWwlWbH}1if6DVA`_O}# zU%ujtrK5bu;bm?85f3`74>K=j)MM7y=(&mkLNgabmT&x>0RItuW>`?f^9ditHTWp5 zX>k*D@a4e6BDyRO(dSocgzhRZM2<2D`slU%;B%f&*~cm39x*YV5{9XMw78HL{TCV#GG=u_V1IBc7n(8hNY z1NJIouO@FH#A&~A>+Sr5IxJf4g!MlB7XLxJf1$rO87q7t2lx_qpI1k zEau=#2k(Tpy(u+j(8pV7aJ{`~1rnx=bR;hu zFIn;N0oej!Vuxfx@jNWS>kMIHl@LPU0-GjlD9#aat+zfTm_q*TzI=b!87u&PX|7~l zo65S$%F`N~vNM zxZKKLn|sIjEA!ot1^!-yM6o$dgqrrawuwN54>vT7YH)K5A`O!FC;-|aEylvGxr?+P ziB3~2V*5IkN51e2PJGVkLyHr6-x%g{_rF4ZroM9)Wf%T4QB9G z&jyN`-%EE_QlUcKCBBlsRE5KJDCsZ*%_bFhk4(=ng@NQ0p12(Z$l7I6Zc5Z$(zy`v z??L%uc(>-?oDA0E+bWfQDef$V?|(i}kC&YazW?;o)RIA)eMCVh>qqJp!~>AF8R-{D zS%&~&vbB?8A5m7y>9U)LwH^hPO5iN$FPh-C<7k9t~rVy~$__SdF@j86p_ z^a|420d+uX7m0qPXbiEgPZ^T$51^VyVj?-Xa%2Jfa_hqo@(2GjlP z0-raCJSPc;Hf(x($+kg6<>?4Xog=o49PcsrkpHa!!-|_ zB}q;ASHu0)`GsvI2|O~bB$?}tOT!tK>nYE$ye3?2f?K;UP*RD{c9$e__dTV#MgN=0 zjd6?j=kSy71ycCQcz+B2M0!a*{xy{)^KBmlGWnM$CS>uK$N6i)+G=a)e3Z4+UZp?Z zAq$9=`ghZrpuPo?q&#Q5M{oS9{lC=@K$B70S>paC!Pla(C7aev7KbgNno&gcMaMk5 zRw$cyzB`!CJKP=2)Ua<8R1g~Wzp*_Eh-l2{guQLeyW;5N6p z*+{p!#m#286K04EG3GQ6op(dJ*cPk(5KF~zqGEZRHqk>{;*0}vQFJE!qqQd)2S$2? z1%TJ|`|}-PT~_Q0hsk*b>h7pZ0k;U0x&B+NGu=^*1$ce91!kKfR@=hEwc>_{1w!qrE>s)&DK zW>HL7MA4EJlJ_Kwwp3#?Esp_~rf3&6)?cJiVwbSk;ONZ=tW9N_iQ+CTXP8d?Z}DUB zPn5ui{M{~C`kJbNyCQ-1>5K%Wg6u-Ponj!9-)~tO%_l|#(!7b}2}?O)^b3NvTA(z#$pf8ex)RXcUk2(`522ofj3*>&*kpeK+P(UNGof~I%3Hhp78^b zHT{#91gID6NQ5mA$_H3J_!^793g6Zp=fC_;Nj!hEMyXBYyT7Hr|h0^(m3*3f@4&{C$WT-E^sP}K9)(! zC>ek+Wr$42r79@*E$`!&0*L8;8okSy>j!cnvRH5C!&L@#5}Ze_Zwf@_^5F$=x@#zx z$e5mtD^VzKP~y>Y52%cB+KCA99i7rRq3vv=m{#Y4E73JDk1aE`!#ONuH*sK_-8wXn z9keIo#P1zGZAUg+?!d?SjWcc6g#Gsa6{``>S2T&27KS9Ffg#-lg2A&w@3gH)gZ3HS2E8 zW1DN5Lvq=Hn&Z%>Q|*NB>$9=7K>_Y#6Y51@uFuxji=JMeov)|i|J?-iPPhtU=N3jZbdABDwc_{5TEU)T`(K4b5H3N5XjWWDV&!ySv8 z4j&hn_;4SwgJJH9Q+M2G#qrO66fr|cPY7z2iU+AU{`=>b!+0PH;7g@euv&r41r!Ej zerc_}iOu?c#_m`4OY9N&2v?BM=hl*VJ>i>#Zie6+5rC5ov0$^Ttk&3A&Dl!_!C*Z> zR%c$&=%%K1(W$R)&eUmSn1?Z-Tg0cylZO^pii5bI>tC_T$)B+&<&Rh!N(Ra1C`#pJ ztBRBPfSt%AIl~i(-Q`S+Awz3!ttlIH|ZsDoZn~_sLs`o10V3}9|s2Vk3SB) z%{y)_uKf6482d|mIxQn`OCZqa$R^4wWMHW-%1V0+UAxmbio$^ryFbD4(XkdmM9u@A)K9lmGAu)WB(-A!|I*x#Wdd;SPZ= zk3StiDo|v?7IBoC^G90wtMbSjurthjEKr#rO)9Ni@V`(@d7G5dbpG;<;!OU$0qe-F z2_YMwaiiEXpiWr^|MF>Ag5!DwlYBs^bfsEKCzbtOMvMepsBqmbCM|?WKHQrHuqnl_ z;`_9nQa~;(a|PZ*xtk)OX}c7*MwWM4fJ}lR^@6N@ry%i^4wvdui@w=H7cF`Rg(fKa zRN?#8wRO1gF3$_Rwet3TE&?EoU z`m_A4l7#=P;pa6k#_j*d*R$n$*oa_Ftpexe_Q+e!({aCD}fio zcB2OWJG&8I^M1*Fd~hl@4x>9n>z&-6E!LevelmzvY1aoODSX>S81ZJj5vb4K{jlUi zes7?p@-su92GAAu|BsaUh|eK)ghfD?VJJIH%6Y+fXqy1Hkfh*?A0R2mgke}YgMeHK zwx(}n1yG~|a`VF$`o^N{x6o`$;zvxi} z@l)JiNm!b4_?vY@G5@QtIylN-pWo;L+Td34u+Wy&4PiXu{rB?|T|yo{WDLxv&|Vty z>wkxZt9sW^nh(ekADfTWXucFTHv%E5=dt*#wrC3@kf#CG`VmTE521Odz}TQfc823q zi99PZbkv2jK~;eSTBJI+AplMF;FR;K);5BAN5syEpa~Ji z4b|aXsV&(3k-v0{0a$WhefSI6QwbAg z*m$k|WjKaC$V_)UT<#!wc1oZU#;w9CxI)C{nP_-OvI6#vtN}fR4RBVb4Y3hM1ZU#ta+834&3uu;nbN5@?Mb^#5f}+td8=5 z@E(tS;8gw4QNalvW>1vgV=qBs-n(NxmoI6h47j zV+3i%A}&G$D00RxH&TEt2ay#a!7EAaA($7V@NHcsqmx9vrI_Ew$o~uNZ{;L{q$YN1 zIJ@haizN1j6EQfwNX4awONIL++IFYVcXKGxAB?AJtE8h&@BrH7sU zRpqb)@Mid**(}}B)rrIhSPg(-j@;~EgRF3les8s-xZA3H=X0k`*wg1CntHE@MeUx%HjW zTG;CwBR|06au|D5y&*1IJ{N}zu4Da6(Vi(*}HuaYG z{zh79wQ}!Nvmb-Cc#|iw0SbA5SM41vvf9#M9nVuAz$dyFGT{__%-S-fDsTjQ>H`*1g?=K7ROSaaI2L=-{XPzI-SZx1C(!o%KKN&fmef7`Ka;mZ{oi?yvEM5 zc&?uaI{9mv0Z$=}u@Op;m{Tbx=22juPE$sJG*B4~ucJVEHBzvlKA?0(IH!W(isxWN zn?kRTk!Xm-Z!|7#%}?f+7VuX7U|!g{#@7!H#uq{q{U7^}d06J@S^}Tw;(PF&HE3E| z>$bnGk_(ubH04!RLwT9yD=)H!&A2@Q2p4$ZQiNjtyXy%r+gWnIkdackdz}9P{`p6t z2e`de;E}L9tNg!*zA7o?Wpx6%{H^;-EA!_cDE$jR`ao$4_f87-<~=7uMZtj-QP*VP z=CU-t{GrlZ{_gZ(k^WptmpmlEVUDyzWH|n3Y5kNoTHo|v>5b*Vc zS&5K-4cXZ)Nr;a`2%0w6LeuX+jD>w9JnKpz-3Pn(VYw^WmlOz}|GIo|lR0MRvrUpR z7WNz2JqR`O2LOdzBEBwwXG*=1k4ze7|9s>M(#PhqgSx##E<3B=fPd?>Q@@Z8Y)8yb z`D~D@J9hVRQTnbtr1Y^5&Se8*v;ze!;MTk5vQVu3QVu&1tN37b?ht35%weUq8|V*Yy0 zAw_IXJr8d8K)uYiMXaoT!ihq*roIRFb)vp`E{Ao>_8cx?%F!^2}om>1^J^&`Tt|A5HV@1u-W@dvoa5T`c63$xF zF!L94OANhFj6EKtv!skFL}0SLT_Ixr6%1NXj=x+0dVOfDvn&yp3fVS`y0(z*Qq2>1 z1Wkuge~e+Dna3s~7#XHCm%g-+ZFPAU7qYXiwix@LqI7=&yBKX>oyU&GsMCwsO}9Qb z4^b@kU>;i@r>rbs9ef@W^9&A*<@n)MH#J~Wyy}KLHZ$H_RKS+Ri?Q#Y7`LE+O-WSn zzGft1?E5AuBO5TDBuFyGroOkZkd>yXlk(WNY080oHaks>{iaHh?F!i7%F3~PR+g?V z%VX`Ucoycd;Z@pO;MA<@oSe^wS2KKP3fOnml->F4c(u+_w*vOlU1QMez}m*C0ye5P zlFYH`^~_=U?0P-5Ujds}-_xrh+g;!JV*_@sz6ZBEC_8gQ19l)gVNL_qKF5Rm8k1ud z=doEio>@g~dyY9GkNuc~vG19i+`EWP%1!QE#5U(9w=QB=a+3%73R(Mnb6`G=&Nt^Z zre*nc);FfB`PoqU3(S>`sdJ$f)f)=EXA3DRx(M9ZTM zyj>bnSwjWoSq&dVo4$?S#nJAKE8(nA<6HY|SS$`Npb>g)=CmPFtw?`}nu%qH4@?hK z&O-1n#Axhn8k{v>DZsn8qnCh)BBi}V0PlpI@?qWe$%2w``vO-Tkb zmr$gGvbH4|fg%bZVZAIuCzuz}le#3c)!LC^L}0sR8z$rzh+XEK{)!xqXGn+nid zD@=h-pW;#`C9>0zBWPq2>lrPYwvYX4S`up;Cy=qdy(Y@TeO|bvPkEJd;H!vNcp~eV zpsh+|OA?&(Q`oiy=in4}EWz0(g>pLc>zbsVTr(892Bw#oU%c>r!s7%r}QtJhbn>^3)X%{p$aVr{?cH5@^mp zek9Py*9ysb%fm(NYjn6u;hsiVqH$6a7SE14h|(g~>BvqfQfM4dq9z*bf&%g=)4JQGNGnKOV_L!Z zB+S;l#1=^4PrOu;$B(6!nqkE%@{T|ptsG;(cSnO+BaHO>+2EVZXFnZi8pap61#8If zYelhq=E-0+?ti;<_CW^5>AYn&1<^68^igS z|A$CE9vF;gUh{0Rmp9%7AO*~^ULP_^)j@Vc#Am?Y^SJU8v1j0j@hS6#BBEkRL)iIc zf+fW5s9#$=UpDMqAE|gppF`T?)ZkYDpz_DaO;+b4 zA}CiKD6v-J8vV&ORHP(Uu7@EBql6Ww8|KLtNd;)*pj30HO#NhDmKJ#Sd1wRS^Z)JB zZ!b+@kugqF5S3RQTX)TO5PC*g<%o3dD=2Nwvj_RBCm`|1@3#??_T4c6yd5)xHFJQh zs3|z!n`m&r|49Mv=>zj?fp8Ug(;fob>ZjOif`D0Qbh{`PV62~jZ8;MKP|4ydfrrcS zBr}_pCO!5$YFGJQgn3XKW`k^eP~lnWLck15P(Ekr`g1Ht$B#zXyWZ44qBcNr0h53AIevZ|@4ux>g?}!ujIVch zGOWu_kMXC6btwLNSulqueuy*nyMi@&YF?=J^da?2Qiz{~Ik)`3%?CG{j8?6?l-#va4D#)`Y)hsygDDuXQYk-i3X`{BY?71e}n;2QrD~O zq@;c?lHaIPRRkicy)6RGS%fylPf|zNzq@Iff59K{L_eV+D7K6UU!I=WGzCl*k#x)XXT+z*M_=*=ZAt z{aX8{E4*xgQ%1&1-ymmejNc%a{I!P-byb0|?vi_Y*g{b}>XI+Su@kNo=ns+dZeTPc zQJfelF9sen5^KoXNVzPIZ2;#BQliR8YCSXxs|zcRcH)ZPM&nw8ViLA{*>^G4mGQJV z264-6+{REhb#se~ac;vm$4zD7A4}ZEJ~yokmyf!Q_ObL+xZESwm=H@mR-7;~)>s}( zGsEQ#vBrs5+7&Keh&6i0QR_I-W^kNQ97o^88S~<3S)8#oj`qbFr{m~yoYC1seLTh} z5BWXDw;r1BG1lgJ=(5M?;H7C^bCH*hd)3MDbk_SAI$HRP)SSPyY>u!6G9P`M9!b+L z%B)BvbsmJcW8t4tz}$9*w5t;MKb3QW0#iZupW%XTu!F4hk^#2XHp+BERu);Prv=~& znqrYx2o=}MlN$i&cD!;(=ZUpL2_}3C6*kG~&GJKo2#cTl=ZKM;goWQ+F3=4ab$khY z`C!-|{2Pi>`1OKN^zRu_3PYXw%+s*b4J-r(?v1BHk$nE-(m1}ZFw~SAQ%WoGyPgi^ zOphxHHKSBu79({qB+MoW(9q$sG!Fk;l8;(wmZhG!BDcO@mga-4ECUO*SgdUT#~0Jf zg5|&n;H3Z}DfrrquLWspv)i9*c%cUp7lQH(S=}bHow9aQrh{^7MH93U;u?}1q5=)Slb{G7F}bQht|Zw9DaL2!NXTpkBe9c6)*Y}X_t|^ zOaiehb-iPsy*c#Wd#EYH7x|jp2T2}D?j8X+iQEZ^J4wb;HeHghtL&O2gFJY?EQ4A2 zx@B{oD2d@OzYcigwEWPk0vh=z{!(QKH}8B{@)5t@1&xQN2NJor z09IN6O6rC2pnPq^kilo}D5=hGWWhCG0h0WoZsN38Lr2dfws5umA42Y&v zk%I_7Iz>nGh?;>qKJhUdMtv5I8T=czD#*soR47?b=)>XNQlX2tf-@yV$;eR#;KT`m zfxRsbVuoUp+}j!uZUC-;O3{bH(m)WWvjEg6R_?1ZE(2NXj# zrzmhUD#H~d2~{pxKo#ZOCWs`Jfht|Fz}FH~s-n14F@~vhR!Km)ry9*)X%s5pFTd!o zK7B-^&?k~Wux4QIx$Ca!k#~o>kk1O!!%>279gm>t%BvyHck(wC7t}Q8<&>TbX73@(E0eUNKWz_VA>xs?R;&!F7 z)nHZ|n8M1e9esq;hMV!{Q<&dwZ=1qa*qv9C*$%sPPBJ@Vw_Zs?9&BSqG8^PjZbBh< zh!-%@Y2vKTF4yi97IZl`rm&w}uJ2OV;7IeE6!vwbR+7SIMk-TM*^x*S*J&4J;`+y< z^l{1TeAG|S7mv8*9ZBrC`Z!KP6F{BuK1mLbACajaDXG&nMHCns4-TggPRtt9sl zdED;kH5^D7m(fWi%XPvuT8afua0A{aeCH-ACP?xUiDpRZDv9P+WJbE#5=uyV_##gP z1t+zF0n)9;{T)bp)&E||XcaB83 z)|0qscd`R*HAGx=Dp`T5nisz4Y00`p0kbJCI#`Zc1WwWLMNeAn-(Xh|7cEgdC@xi! zk0|)U%`k?_9IVn9HF=pz^Y6SUVux}(k0Dy`7XS-D9>1hd8O#^>i#(UWe$?eo3GAqT z$^xUUy)*4gVEY{B@TePILupY0>mSvbCMU3A(Li9b>oL6u=X8%1e6(vkCK~VbG{)u$ znJ9tH^_pn8(u6ThZv-D55p2vSJy%lC2T(h#)^l+F93)9aB4zoW zo&{{V<;^QVYb$le!nCRW`5Msb5$-Mp>`Fu=YDzRw-mKa8TdAwkpYv({?0@$uvCW5a9<;tBR&; z)5Hy4OSA9EWy33p8=POsM5pa52X#E%?3!_NQB~`izWF{jskVJcK3iMI9G}O=)m5+L zvUzn~J@VO(x@KRzj&ON$eMg%@)+<{^{myLBzIBfMY##IHsAw}MN4&V5Io9pMW{Vj) zEVnV5@6R=V%BA6XbvEYFt~}#-9-YrKJLOX_-|SsPOY+Ta`Ly4cZ=T7geg$?^O)O}1 zwt#vTRzi6}VZ*LP)VAo(E$+~wNMPzuwtx6iLv^caHKfe#E+k%UqRy&G44LFp}S3-zQb*z=5TnZ zZeplrV)VQ=T&aJ2%}((2BqX4`K0H*tlf-GWlI$Dv*{&ozPCFJJsvw36KPIGAom}8! zd(*@ncCTbVmCJ&a?6}0bN+x>kkFmnzt*RNfCZDaV^$cF|_qFX9#JzRQsd;QlUA1c- zTU*yPJf9t_YvO2!dZN6bzN1ee8<{Pmd^}sU@10|Bo6lzCsA#h~$BGwsJjZ%8k6jc) zb$=kYG1{NaHQVP=Ft5(RJUWqQT+5>l`6kb&+4<(EBHEH~9?7S(`DU8}8e3pT&Afs} zZ3}5cVI`C|6gC`EM16~*`Ki+4nmpTprK)WV_#{=L){=7{6?_2Hh*KJ-@#x0BGiJP912b@=7o+J0iSkm(J( zkuZvNrkAkgihvme+$rruh-~?U<#Q4c>TEm*L(7$IC2>LsP7psc`1S6vhS-`zybjw+ z25$EMiC=dIfVKN^0*stfp+TwjU;)aTR-E^S*pgrn!=Lk8#ODa(D3XA$kZ8d#_egNw zLEIOF(J_F}kC5Z0Sr7w{J+d`uD=n17AGXFc^2z1&{kT^A4S60$|(0&`1N}N zE%|dZiyy5Ip~;MzEh5@9#7*_0wpd#FNKQlt1tpP{bRNVvK5MUd+v#k0#1ul+ zZmkkpcGOdfb^1ov=Ib=0B6GD6Y={0EeWv`gPPuE0|E~WKKpR%_9NwoTkRX5`l?f+&VM4s}ED%%S z(rwgGI5fV1u>z&D%wA9r$uO&dUl2NxG7A|g$cBA>Eh*EX!;=D<)9a+*BWWuEk9$di zWDc6s<{=ARLQ*&jwYMZ9ka2WHXnX^n-dEfK@KyiU;^RR|QB8q`CP(cpBaGp=_^gy4 z!LvcO#gee4W8wiIze{49!g;Q?i}?7ph>za_l$z`~F4I)OJwx;5MDW<`mZ9kR_!)N~ zoe#+h05Z+}9zN~0z!&1bhWyQDp+x@q7}#+p4~GB3JtmOEkDI}#`8R|8G393EyJ7(7 zp3$r{`FGJg)&7cJfab{*7@h=P*m4mDbY-sYQI!Ls|@ zR|u(e`eEKZQRe>}pK}%M3^!~JNg@9{K4PN(1AgfnAf1a$|ChWhh__(>#$V4aRx7-H z{5ek{U}xUPe)mJzm%_=1vcVtP%4{b%*)R!bhe-vO69PakP~l7o!K1gelrZ2fOu-bj z1~6{H5IdWkD6S`iH<}lW$@_zY2Zd^XyBjPkg0DwlD2B-KnCMgG+Wba~P=W6z@*%-1 zgFjCR5>5!x-#L;EjLBOiR{*&uq*rlFPTwe!7kE(J!vft!tWr?O!qG<212u$XgW8pK z)e_1y`udJoXwgpWAK2OOXCmaPpJeBP69OV!5Q4%QD+6*`bRal=2|7$^~e0NLDb_ zugTBtv(UC*_Vo_E!Crx3?3K87Hum=bh6?m@9jq{%e#55b+nm7ZPc%Vl2|-I_@Z}Q z^U4297v<&{K<@uDfjK`Dq1;;X2RjiUT_YVqUE7|5=?+VNXTICzZxmkd{+}=TgLuXL zeAY0~hMyc5D3)6H0@`8$j|$B<1hH*1^op#jy7=n|ICjLhv6LyVqJmEGxJUl6|pr`Q98)Egp z>&7jZW%mCJV98H={nKuPDO;3#{1zwR;vExl8z+7mh#3e z@DyMDDfDMPv$?;s?=$-7N$X8r_+~oj*bSmu1KdFm?f|$${@W;nbx{-unBx?0AA_|~ zqppG&LKQI&vo+^3gRRk=Qw+98gXd<6u5Z%mtgc+vsjH!s8Pv;wiZRyEQJiiV3k+Im z82b&{Y(!SL5Ii?2ZUM<{z@SehSPD-|@;nP57FUU{K3+QCH!Fk2rJK{zX<7O)!jCB# zckV(0J?XL{kKCCs6KzK+cD#h-<99T{B8fIhR&dONR2nRdBc<3m5>5M6o0sUB-PGE$ z#0vGi4Q^wPYMp0gr&Qmgi>z#Wg!pkj!dhx&tu(+r*z#}^n+H|w(%dBj$ z)fjK3GOIDuN?WZl=dE<&S1AN=p-psIo?>OI72#N1ty+V)sQU0ED_asF%KIa%gRI~h zz;*U&wM0#O-P+E|*5N{Ebji@CSrKw!^cCP4V}cb|kJ)df?d2EZStm<_K5+Abm_(41 zOeWa8E~0DS*X=AN}s!Brz8MW=DV6kBHy^@B@FRXrayyS*#(Qowf)Q<|x&y zi>jddAo3Ha2gKoB8cd584hob=s-CBt*+y^--ue6#jYD!DEG99 z@R8GfNd8x9yTNWFaZVzR$ zMd|jRGT5PXarrJ)?58ssuL7xReU(Si*~ARbr7X50!$gqtoYLE6^@jJ0SRj#3wFaFuGoniHXAF-NWt zyxY5Vqbvr3)C`u2<`?I77b+ZTqx13 zI~)kN?M(ck_Yih2?pAoaZV}vkbs0*}%QXWBV?e+9lJi6Mu`!kaWK)L|4FHs<=BI(0 z4Y5Xk;RFz;4{5WAibp_I46Po<@V^@ z9QqtRSt2=La2YN~V?rnAU`5&mPpe9o z6=Q@-y;Ke5392z)CGDH=j~OaowJI>&hu*p5SczmQa`aS%O_$RL!p|&wk$QcYCH=6% zR#+S;Z@0jsdck5xvAqH)=^Dj00|dB=(Oac9s)q7l)tIc(*l@X2Ew`u%g$Az+v~zQS z1G}taU5wn1mB%tf#*eay=fH>4O-mndu!$O=aa*)#RCm$SZ|H2Io{sV%-F8l=Hij|M zpl*h3utCL!G1H()x00FghM)Q0^|h9awW^3q9|Z%GB^m~%8J6^M5kO`}BTHIeCH*97 z6dhik@0BRPr4<#$9m?O~TTpF-BIt~2jEJDt5eCX#BW&}-QLRfN=$i-)gZ*H~jrDMt zsGjan<~V4j!~D@f+Z?tYPCD%{`#I^lLqoZP6M-dxw}oL4$}SL0QueHWb38K zHYPB>`ZXJE3%ZOSGmPkqHg?2Fzki>}dRpN}9$}5f(RJ2zjy6^pCVSabG%U6? zL3Ml6w#lR+rm@4Mg{F-164TbrP6th+kDaaqU}dLvcE0vYgwt2u7+C3hnjV`;7iotI zPp7N&EulK`TO< zNBzPwB=(7Wm4M(ca{@cQL*z)N1Gn~x)JuWa_=P4294%{8QYl3QhCdD76!|ag&zMYM zo}9md=~xC>`J-fjwYFUjJjiF>7kbz?bfQdtA#{pV!`8i-Ab*>N52A;q1K~$su{`gB zqXXp;5l=v_h;Z+K$fIqR4rQ|bz>{9C!j_l@e(W~Ik)KR+1_T@I|dJ61&(ZQ|~kS%sa9>p&;d*(HyGAKks~4prEcq-nj<+2%B05znQW{;F(5rT5yWvw@XOUX{(P zoH-f-AtI(AwpPYCY)-d#s7hzjjXqUrd=+y_6nww=s z%jH>ls2Nf1M^wAO31vChCg}R;3mgko2tvdtoV_bAmKaM)^m97i8Nt*EEBT(eFad zVW>3*JFi2j>|~gz@Ec0xM1y7+vFi=mVVI{4I&6Rz@M93lK1eORI*>#edRK+jg4Q~S z9ss`PAiafmC7EY|^^yJx#Hl=zP<4 z_6~y=fV|pqI)e4@*C$D=xzo=ro8wE0WWC5rd z$3I@0#k;okXNVgr7k0~U=vI)$Ohl#su>sM;bH^c~pkk@)S_;wpt4|PSJI4(-Pg$_I z@@;QLws5n$_^Zz$R=jsZFjv(6E23jTEM)Su(xv)QSAf?-yinbuB)6F z5=mUb=kXVOrFZk!eHgwA4~AOu$4cRKX>h)zCNDZ)Qp*NLwMh0Rf(-1Rf!w!QX^iz( z6|p|oAaVelbC&dW!aIJ4E`lfh!(&iEpHz;D{D#?hpab{??|4k1C45F7_Mpgx8uN`5Su%ejmtR9#Ho>Ckmyggg4O<(OkTS(_BZAFV z06^=ZDmw&T$b(}`RIHH~)hHCZMl=RTTZA25wb9J6;GfZKopd^^X+3nhsA(wQ)Sx@} z*R?VFZH4>h&~S3IjOcN`WLALf8eR~yeG)!QE0B0MCCD@j ziNsic?UD$*3Xt2Zoy~eF8Agxiq1@RjO-TX|v3)s0{sg%h8{TGZPv;?-x z8;|zaz0T>$tVjHNNEi{HIU@aSkits;-%OA$if7KSI=_8dvDfV0VIe+(| z(C2*K4-jvT7l4DTXegvA@I$o{)T^ny`op0ZpItvET*4A8o^$CtyvHlDcbJ9x-(e^# zSG8}YJopWOyT_?(0B_k{u`h-Z@lM^%G(3%#U6_>4cd#P z7aCrQFjm;0fUZRSYMZgwMqBUjq(Sb~ZQ2VgI!OG~%3?QvJR|6RBkHPUu)Z{gopWqZ zmdCKgF^`4SCSi0EcC%rUeY*w8C4~|6n5<)`|49bg@jHvCUMB1k2QAi%7CLpu$cir> zp3ZyZ?l5f0?*b+ucjRYw6h}c`46omH9x-}b*fV0H?xmnB?Qck|1(MFIq%&6R1jtnC(5`IsK$DkDzB4-1aOHj)Ay?KYUL7(Bend5H$g>Is>a$jXm0 zZIqRLGHsK+d~X*724rt4uI3X~n8)k`ogy7cFDEkg#!q&#vk}@}2fL}Ako!Afi;bG< zWasQM=#08L8kT|7$Pu+4haGZzCk=L*#ZFr3Odji^t4{B57Y+C&_t0nb!Fl>}o&%WG zgzp^eq~hG=KnQ)xQU_w1tiC=D))Qohqn&KBRa;$HSgCzw&8?l*A2`1s(P~l}=9nJkhs(zBpnSPg^}0-3WaXlWM^etnbR>-U3Eu?% z6RU`>)n%?m<>gz{QoHXDrE#rmC{8KiOF~7CYL)?S-Kf5kT|_SDp*G!Z{>_d>_E= z$VkR5kC1^4Pe*yIYgbpYUUn_oiJFx$b$5E$Qn!rU6?@$^ zP_ro3H8zedj+0l%(djt#Y8(ysm?2LM8tRqDdTFm$KJ2BQ@zy!95c-*2hrZuBUHrS zdMlKWA9g)zhhW>6kbDZZH4Rp^BeD!bz*tL6XGA?%w6+TQ6?Kn7A*C^V(Mn`jmD;L& zR1fSY+b5USA6)qq8)qDf?w?E0S)^mCt z(FEk&qe7{f0$F6fYNEVa&4iypmD@znWtI2pQC5`)yW_r3ei*9CyASpo{A5c6u7$x5 zNwqL{5P_C3{oThy&hl7CVINsao&$noNWDXQ;U7N{dezrmruOm>i?Jk|^@*_d%f>?4 z2`7xz;udAI@3h`1uh6YHddg@=s5)dDFR!c5COBh8*Jl@<8p=1FFG8Mj#hk0hLXo0k zdZfTDb&Gxh<=!zdi|VnxF{1u(Ojp#Obz8e|D4UtSe8gOPlLz z2kKIndUBt7G`*fYw;t`Sr=6%rJ?m@G-e=XV_2nD&X-&4VBilh2vcJ5VL+5hJ zcZKQep9nodzQaV2q=!cUS{70DOa`3)09ryde{@MEvRRs2GT2C)eNP6vX>;DpWb5p< z;~DI-qrY@CgOx;D@nd+@G1`>D*2ToE&R`4NZ3)c|#?_vcf&9@uFtx@c_7qi9lT1|I zNSaQ5{788T5bacLLxzuimukh~#i=GPvO85=uw9xJ7w?${N`b3sZAJUNmE+eyU{5zu zU!2|m?K@UUUzEv$Rnl>EW0eflbk4{?d0~d~V-_vTfEDt)%yESBo~(*pP^?Jh_S;@6 zd;9%2rqY60VVwkhk7sflu?HmW)6 zmgSz+l$B*Yftnt^s`1mCvKduP{Mb;{Ii@)~P*pfsE>!P8BXQMQ8mju%5=yVX_B6te z<8@5jTR#LaG-vzkx>q!1hwF_OZO7$kdz!L9jyP~B$BKIn;_xz^pMnMCdySZ?!=&rPZ2d8anV4{4gK|8{aK%;r$ z$WM(k(fQ~m9yC7CM6|lr1i^m(yPa2>vpIJcp}N;S@spae$@e%9HD{~t5nXJ*2l7{& zrsnSE?EkR$-QiJG-{1Gn?99&2mTYKG+gZa9d`nVbWy_xE6PB%AizN-a&+Pu;SE$GG;0qo*SdO6?j)^U^! zfO@i&idmE{r>shM{RsP{uI|kKp}Ss>MsTYmkLP$j05a zr(QD>nolL^JyJ`7AOwK4#&eC@F7uSAu#I99V(;~YeU0a|b|Du_2MLqk)d~;D0%`?A zUxiH@V#=l2fb@0^U60ItRp8c`QXByZwKL!iL4sz$##4~|_w!fv*=%Gly+>VS+h{I+ z4qt)@K;|qeLOMXvvgN$)mx8*cTX=5I2|^1LKRYD^On?|8D6rQ&^ww56)=OVhgNJN! z=i?PR6mZv5LL}Eb>}XCFop48>knmw{yHZYws1wH9d%PyHKE3r0Jm{{Wg3!z^(n^u^ z~VLKyHgcPSLdZ2~`VTyUM^kkew2Kt+3|32r$%u12z@Y_4A6 zU0z0*rwFXLb%Kd5Hbo*res_U}$sOn2Yx+Y&YZXd5l2?me6H%hha+t@B6-WKEYrJ~q ze1RX>Dny_*;aMJa_du`%?fOix<7!kwSt-)3qBVy<3sl2S58wx+lKN}7>C z^;68sr>N0nCbtpiM?Mw??l&WpgCF)tmeq)3Ln0~Io6OG7%tmy&nI1A*&zk8avwGW1 zADGp#3gWs8F$o?*5tBp3lOmAAB2c^^3DO)BCf&LYim)gG#yi2JOf!|I^Gw!NCc46u zC&n969T$thQt=UiuD>G4cX;*{_H%DNJgoz5bCilpO-OPf!ak3}ksnArv&DCS{fd^Q z5;nkLiJl6?w~Fn-BkUW?_tqNiLE01|?5Gz6kT zjVvjc6a|)#Z+Q(LWS;R(+n%&cIorRF-oS*+%)TpVQ`qV6(Sq_M;OM3r;E ztyt?4pE<#~1Dda(Y!&E1K{_MQj|2y69;c7sNe>7Nx=kS+w<^hY#_4a%fl?h(q!Amq zC^M3q0!jk@R36NshvhZepY7?nHiUgUOfS(0Yp{3`s0Q_5OF<3bT`&#_$_wPjzrK#u zU7z(5(@w5cx!wKG<+s_!w5;MB!-F77{uI=?nnHh9k5jsps)s1uT?kjg%^^jhS@KF0 z(kHySAvTbwRQ`j)g6#uPwdux$EEk+GQ123yZv=W)fRhQnkbKjzQToCjxjGGX5J!PE zQe_9{F9k$qKzDq?u-BG{WpM_LhFReQ`W|0?Y7Q^C2fIzKJdB$H3zJO=-ug?*cY&l1 zBy!Z)eJI=yA`{Khj38t%fjRT4ITQyTDz@vWp=MEz1(8*jv{E?qRITzD#jLH;%>a^R zv+}l0`YC`X96@`d{TLqmXNPhkknHu5^Z@d`b1vN(2nj2lX2Ra&Z^xIf{q1Ov4RDSN zCbI)v_}zv8aAdM6FnDD!JrcMC?VCZNXip5bXYo8B655M|-~hILbY_KGJl*6-V3b0j zOV6NK>xM?=AQcIzmjYuVhiP1pK`E!ddn-ULNy(e7%K8i@V~o2hekSvnFA0I z@#CvdfnJV>X|(GCR1)km0ikRUI_qUvnMIkd|BQLpkJn4Hv%T~t)sW(-G*5$7M_ffo zZyEgQJ^3*u<7stnsuV$%`>1k;yQnSqC>V!*kf?%00pprADcDEh)Rb3! z2zkSa1TfR7vXN305H+0V`NYemBrueo@+1KP8BXNrzCpv$P8XEf9M-Dp0$uY5Jr8-~ z`zxrkG@i;xW(_Z^E`Zfr;cfeb`e2>hpcSxf&JaT3o!G#4mD7R+sjLCB#YQ(tR3Mej z7M&mP)FUWQIZ%&7y}FkOd@T3`Vn3QD;^)~SDpI4im;56yCa+@SnP*a#o9H@|y4ytG zFW7$g6O5qAh^#(s*`kE*wI5H!BRfHS;rQh$}mNmJk&g4^l2VfVy6e`UHKh?62%V@uR?hO zfE6ayC}&rm)tkIAxTd&BL?nsbkS_|D8J}+O#oe^T9TQS}iaCIZ2zX?2-=vO_=r1US z7n!bC1o}@8uU=Y6B4vB#(pZp`N{T8;q>{K0*|)^GsN?`e5OB5P7dY?_+##05|C?~Ps;}wI*y8nBF6Kzm>$Aky^dfaImqC^zh)xQG8Lqnp zFtE1+A%RWf;vbxoQ1DMth)|uM};tGi(zrhdC5L+-D+JAX_14uPCCp%&%e{ zG59F<6wmS)IE$>gTk1bqj zOuDLrXg}{HZcW0Y<8(-&KW&oX^gfl0_cjGZQQ4|wWJ0Q638Zx=S$|lI197|CkXAL` z7k+}JfqX=5f<`kIok_X8_gxB_u=%m6i&mv;-ddmiRNz z1}I`>en>4~0taaIAP7YJ4lu>$%i3=H%MING?UfwSkXwyGTA1mE$5kP{;ts zrVi8FHRs0I`r-cIPj(B~t6R^CzUgbp#z!@MPSe8e-`|q5#rC+uCNC0H?@3p$dOy zE)3#{V#Rk!|k2LblIjR-et`!$qgqYUZ06nwo3IRHXEKz$YiC@t{v$D0HU|69R{ zs^w3(FDFB^ZV>4QqV1SS_ZNC-KC`fI|5dTxX3id@w~|QX3yqjxU$|Irtz3qJ;o8Zt zLKv^SN9avRZ}D}~7aEfBNO)8)E({4wkoIXuAH<2>8m5b} zUD&)Xg&l->aJQMTjUBr`8MlVPq1ho!mn z&t~dTg4QW?g~GlWsqZMt#pXpA<09(1#n%D|;0GFHIAyZuysf`4aXn)LmG@E5JI~#C z!k|pXzFS{`4IQmdcy&4Cp6N>nGwYF+1j;a3|n!YKC;o+209Xd@q)?Ne+BivYtW+mH$hr$uErUZIZVE0qsmF=7831g|NY4z+u0Kh4(CAXgTLtzb zL_?ilEg&G{d%=ZpgXyAe2?wI6J4Cu!#D=XmL<)vd2=L~0QKMIh0I%WVM}i9q_YBbn z7)Yk50{ODV`zY*<$$Bj6PRcn0Q=eaiG^yy$tL^-qb2jD%pjs1wg}#;_9*2Isg1N_(U`Lh=)O3mYhf_2siyHu32EN*T|Nm zGW}4tjyBUXvT{kLH)Q3BOz+4x9GPNP=9}q^0xOl*VBs}vM8mes^d6>p)f@~=JijZ@UHR2TC(2uh1^T-Rurn&^Vn4E3vFvja-C{)>VTrnv+^{;* z@a2*%`iUQzW{+O&M|RoE;>dS)3x5094(ef!syOhmBVekN{OX9l?~9y9GEVOFvEaxt z9~aKv^pVm2&BuAwNzOP+&G4f$eQo#r=w@H*aerhnv|jV2-}|b}kB;@T;_O;K^|2pP zDTdthOQRS4?1%j6?|$kTe>&4Y5I@-H?}H<|{fp!?KD-{zpt zy3Rq?n&neCZMNQVU=t6(>EFy297$JXv{xt<(EiFI&q7p-#k$ae1hzrw?tPUX*{#ZG zpEueURmdS^v@Lp>57}jlp5jBU*`T;Au}432kOOv5_;!c&sDoZ{*v|CyrH>uzI3MZ; zjKqiD^yzfQmu`1r559*)kiPUcrvnGvzB1Y?e8bSr-wO=J1|!Kp2^=GnDo~R)(T;o% z<7tDC$+YcWy`&r_H6+Di+3I3I z@+&ujJ!B!3AoFB!%r;V}E)wYM=iU;RhhgQeY3@lHfOS7xXa|nK)qpf`^~`@(0KQrZ zc+}P~67uIaBu-ph7Ft;am~srg`ez~d1HNH9S75t0OeG(Q!a0#1_io$XfkFTNN7n)4 z&^mAcNfO6UIt&t}ch>oamGlgx+PkF5$VH156-iK)Q9n%7s#=vZI)nx2kYD|I1u1>TmU8#MOlk~DItp? zSl2emd02u$U-?|3*Cpk9iGKTsn<65@Y6 z4Y5}CM^;2=yN=k%b&Knejr__(5Il9%^7!o+YV;->8E*|idy%yXAy=)|yH@(6)n}58 zF1A^-xEQSNwb5fX^|Fng_ks~wy9Ijbh_J2HvVjLBT6GB^M%MvshRA;?k#&f;0snk& zp^<1M2woyM#RYL5ii*NjBqC#DgqJ3xX(V|UffxS3m#!7;7X^4yEay2oftRkkU1+s% zdwJksUl>K-hJg|*U4}7pa=`^46DL89Qhe+XiJuBEVe+-XI(Oa}&A#Zh(Z=pB)W_8b zlpB$vEe)~?ttfpdkT;}xu#HmbD6AortKpXcEHTd8OG+uEr39OQyI$U#V5<9DSb&XvdRiSZP)F^(doc}aujFsG9C>FEC=wS1Q!ZNw)7|BQeND{MTZ znJ-{AuZx>GmQ99cj3Nl1P}=l5m0(}JM|n!xN7xne7LAdt9;FN^DG}hNu>C%ldBC8?*h3^hkBIfb!1L6C{sgcNXa{2VtIS!p2w6&{u(V zH%o1ZZ3v60h+^7R7VFJJ`D~?A1y10-)CH#c85d-7*(s|nZmiq<&sWsqmSlB>Ko=IG z5bm@>Pk-#K;96EaVr^}<@-@9|^#63J(Jec&7@2!dEk^yY|M5@!A1-OzhqnHJ2Bn*& z-GW_{&7TSOA7%4Rfdfl^G}(WW%;R87Ls~Y=1et2G<$+As$6{bWe4KgyQzW;(}g zM;PpKvt^%|#g<(g#HuXO6aVWSH(MLh`oBBW|KH<(=av88o5uxa@I(7T+5DAYpJ+Be z5O~JKiIRPiY@Wr*a*}MB!!hs{XdWNR5|CjzoGd4rEwjyZl^JFsy2Wg{0J8k=kC7Al z5)eB7vxzyD0$cGv{u#y8rFxV6>*@xC0Z}{%74GflsW_r9H?3Q~WJ{I;06uG}9+CFP zQ(Q{~?TJ%Np zlsg&BvNS6+jmxZlauHfYiprN+!Du5}Lfp-bgW%B}=co(cVQN3ZQ%V=ePF!C8Pp<9s z*B!g4e`{qJ>0A-g0##;Git=*#JEkEU6zRx8JAI=01rD^9P>W9K8rC37M+KjcGfTDn zPlopV$k-LfhEh@g03?6Qb z3H;m33Le^+?Emt$tbB&vf>q8yp@ESZ@WkLxP+BlN2^>JLK=6Z5wTTN=3;FtiRAdjd z0P7eX@*b%-*jP{h{bSYsS2tmkG5}be#vg+JF)KEEJK}1=-pkU1jm-B1nruBg5@&V{ zhmU$Fbe6r;j&zgfX!z$mu@huoZy4QA0`M$(`V1%yZ^&+k2_`E1OGBVL#w!-Z^4x>! z=aha*OXOdTxhN78d;*vd3ofcx1aEsDb)BFwWHSXFa}g1pbypz<_Xoetq;`01vZ)K- zZ&39|3fa(j-E3)wUL=hd)*{V#Uh_`{(rrIpz^D0C%?!zlxxN1;$I};ho5cff+y< zKDdZy3DQClF`Bk7f$kENk3;~xxl7=>s31w)Ni1{Q1zq@ zZ~%3o4bcwv6*jU};m0p1b{v1I1mnmwRl(U6DnEkkT{x@R_>uM9ZPmU)%_3W5p^mv; z4|9G@bXU?teVq=-e-N*pc?H|t6+v1pA@1`hwE2v4{qq#srvwSGtaHL>fo;uz9=am~ zie%oOu=3m;=e4#K2V^Rn$4I&b3p4DjMn{H9U`B2TTTQkx9fiUy?KAD{X@)+#VMAIk zQpP=Eq-z4gt(J=9O&J)^i7+p4c!c;f4=ODKu*O9p=zF;1L~*`|45lJx4?&N3Jfj9;Dq^qB~^Z+U`wv80A2{{ZSG=)%D7YTL-T|X zl}|HR4z*~t>I%Z#>%Rk+0~NmmsEb>hrV93PB3a0PmL<4AE(e6h91N+<73ow%>-SFQ zvxURx>pw zHL`t|ne34H5j^-#Gr487_nMWD%=C&``3`V=bMy{{E>WHvcr`4<5HpnX8B~O#{-Ia~ zhUo=JK?bGW z!}Urnn<-seXfwqUanx48;Cq;1$M2WOK3)J$di3l%o9tEX*prQ!P2i3QQ)ImH2;>xR z6AW!Q9vj;dS|lgW8_m`%)4SDyTR=fhCQ?KhPMQTLlUJ(23`1SpC|zIpp4|B3^m&~` zfDb1r@6k7~l-Ze8`h;-UqdHol*&+i7ykI-24ei6+H+q?dKclQ)wjR_0*EF{Regl$) zg)WO)(B6uL4*y~}n%@`&f*uySpTQNw2^f2Y3P+$Yk^A@d&`=k6?|gN0>fg|Oov zTyONB_JSMy+W{eIG}$FeM@^`P^iLjuhY^1$NZUk`Bc%P4C;PWEu@E;{C`hxpf3$G_ zFF2m|znbb7bY%4NZ;!7Nz#RVkj-6l*9Jnp*6yb&izcD(8K^5p<2_T&rMhYu0o&4>! zW3lMPHRvmkrXHdFNRSY4@w4y|rxD!W==@J7jN{I{J#W5oxMmF_90M=ppGS39bVa!VeWurh>8c0XP8o7lnA#F4!S*NoJ48rM1sY%GV}(HP?AgSl>1J76P~FMbcDU>fgbgpYIECjxZ!j=n=<&XqN z#0%XLIv9y4fC0ZDst-hZPb`zy4}TT^{90g+a*>E4ioG0$`o)=2tA!Hs%cyfCI!l6= zlMfIyf`48<>xC}OiuGeR&Jnc_`=OZXPVS`?dHf#`JS%p$F0uTOP zF9bh9LSq5q?o2TpYwx%i2vWZ%mR(??nI`316WwWwMCpKwM*F%c07GLFHtJp2)Qx&; z<4T$_jdll!Y=^+%h!?~V zv>%Bo3Z70jDf3KpdLiBiKIPlNA6U;hR36Xa08T+xybcgVYivm=6Z$!J8$@t_Zk219pt^M~bjJas&vfJ%YPajeii z(_U~>W31?60abu0Tn^KM_Xd2`#ryxr#TkpnYYhT2^$S%e@OTsj0OPsOJul>mf8eC` zL*E$Db6#4XQtN|QhfR7w2Z$K|nJX5ozk=G8)QADzP8>!Dvnz|&mg2%r5h<2LG-4Ht ztc~~^=VcLga})9=@7bikW%xaj1vk&{S;%pV*YvM_sfGNouoE|w`n2=cP6J#;7Sx|VXhMhTx7d9>($z!B3X0ihXM#y zMrhJHicNQ(zz<~dz^TK63+ACO3#j$4dd=_j=4SnUp3m9}5jk9pB~jQhy7&*JgB)yc zugo&p+qWQrX>%lr&_pMYBa20+4lz|!fZoXwttUl_V#+Y{-FSXG2W0vXb;9aXStt$5m5=@{lT?M7&HqM;llHjJin?vGkkK%-dBtk`vO!2vPz-lynYF z&)fewnQ&q60;cN%?Q}wfP%iEjVFDfmETR~M1E)pnb&+2D{3b$65D|yGS@1=BztDh#Fhw-SizOlB zi&iw>7hmPr4ABa)CcS_e^N5QYxw4Wk>fo*x+VW6v0RZADqIigh*S-QxODur{Q#th*#i_>92H>o5%`Rh0x%w*lLG6(EJC+4@W6BUGp zj?wm+l{hEywKXPT*qO8SVE)yn)FuI~+45{XGYnB1HU;Wq9m{A+nt&hgr$uj4`i1eL zS>x?`U(~}$C7lWB><-J{UWiWT`Bk0|O_3caATL_4FPAOof% z4QA1o$W{}<#|g9IAyeQCo`@V)=Q}3nQxh2@DH=~0YFQ=Gjgp!p(d`A>GoMQy=kXZ7 ze{6DQb8%3@0^iCL2ac0nS7owD#^`p+;TL84m8||C)4R_pc`ReQzLrm0NvQ)V_Y!Nm zLoXNoj0QGAokP+B_CpxXWi&5Agy;XTRVYOf8WveAJ81{jTv`Zu16V*sN0=qnccXr3Cd(yptb%v~^$RoEEP+QXkzLse*(JL& z709s;7;wLp?H+~vB3qG9e2Td$?9{u>n48n)(ezV=o>sc#%jZTc5J4wHT4Pb&p%!E( zm?1=>y_pL>>7onG6(WB8z7e>8UUWfBzbi)P3AM&xv0uFtIFpTey566q?$p~BBCvbC z)<&}ZJ9Uj&kjB3#}qD9vVbc_I*HkXQ7*AMmM)xary zZAwqX#&sdD!`e$z^RM7@>k8;iD)cnw*%FBKQbl>X7Q)Kz(ks=%salwBadK*U_Ig!YH#ubr(;70KL25-rQWky<_{S9VXWcG<+IYkt!j$ z>a6f8F2v*c5wOl+JLafdI5gQ7gN*_F_3==s>4=)6c3|F)(Qx<)<_aB=jNxkm=A3`o zU-s!;dPT~W)xWX_WdFQdrvlLT zdgUNs=}I{gNi_%sz48AWmPue)4%YrsRs~+*As>*1c7EJESL1E)`UK#;HBvg#mX7>6 zG}zp8=UDhCRF8W%M{kX{hs+#KtfN`HA_m?X*I5xkfsY8w*q1!gb&H@L*P zB!)n)Na(8FQuuruRPrKILjJh`YfTbSjF5)b&a}0+GvhTITUm80O#RKQ*C>1f(YW({ zZi7L(F@)ODwSsjQuUJud0Q`Yp(4qHc*c$&?e^L2_X3Wxy3?ZYkbXQsdF(2Z@yz8G4 zGvcAQ@jB{-iTN*$9^R4nplz!PTTNmg`7t?ZwW}Y%|E09sbWEtMZr`U z11D7osS?ILOZ>QOGcZ-i%wwS#CcAXJ{=C{x+L!QL9Q#lRJWL= zYbZ%zMhX&=ZnZ4(A+unPKs>fh{25?$8{dgPvAa(Bl1FyePG2(B;acZQ^fZTUqAxk* zaNTtxg^vw~essXpN**}XbAI%R6IRaMzEdgM$Nlo35zEyH6^+M&_+wyS(c*m25TRjj z;UIhwxjANuW^9EEcnQ6ECf800;T$l<%#~tJO7u{{wik~d^7-=Gz{O=UhYI5nZb`L1 zlgVD$_pD4mmciZ%-Y0HU0r3uyM+6ahOD+l@|2j(}R?A0EqY2oMr{@jXW79kY>Mg!FO_A+H;c3D#X( zO(q@0exx(ZsA=Lj779Qb?#M?gk(}za}yQ!)U1}?QHX^T!qif{{$%I^aMDXj4+ z4yiWr_rhx}2|T>#wLad#{lQ4m3h5WiNw7OrnueESJdjdBdXrRvD9igSFAXJ?`x$LV zIUfJrpF>>-<+1MPj4$aU43zF%+T1CQoQd|rmZqD4mb%0FF|UlY!J4!}OV zI&vKn?D8sbU3#zeDe7u&#pHIvuKX6tv;zxZS(Wb$*UPLg4g*J%9tw~mN#c1P;BQGs z7csO6cOTG$hP7Ya^bIyMRFeu3^RV0zCu6PiU8s32FVsv)@_Bp)6W z7=0QA4TMmhA0adgK5tQ6$%6s`<)C}T&~HV0NyJJnM6|d^9vux;03CQMpB$d`gdkpt zz{B5NLbku1RDv-NndZib$TSCg-vPn$EBC++c6&VjFcK_fh_D;WM^wUPvPLN!L&TL+Os^8?rV5VqtX zP%QXUqYMw$4MJ9f7o`q}w&Zrj*ChMkpdMw$Zq|YnZOG0Z)JymkzMFU1vIhtCMy%`P ztV*oPA-yjDGa48wN4cVJlcq2{OrzFCh6N!z>yVCczrPgwSwFHzAW5jRIEh zTLiPScL9U_YY$p>-J|*dq1rYRsm@_<$Eahz339yk5t7CWT>RQ2T5;r*7=BNLELY`% ziEc4LiTcQ7y}+g)Ljj*f#{kLxi$4?D6@K;we~`kaCV@T|ug>NcbzXjC11)}xTe!=i zy+p9=<&~tZKsBBe6rknu5RL(SgJPc^Lkt+YeUsUb0xj3&xL(2V_NKv8)o>bBZ_6+a zP6qQ|CR!nqofLg8$Yi=nx+4Rs#pOL+j>hpzGKZV}Ap0ERNOuYC?1DOEJj|=%7^Ib# zki!~<|RkEItM}Veut(Sl$Lc8q4+Ps6Zu&t8XBwG=)~G1)+m2y zIC0UbjnS`=(TE^_Q{H)~KJ$SO_mX9<>d9U?1z{`hlpX*em$gUCGNd%5>jlVz> zd}y55#sFW=-45QKUUbZxUCaeqooVQy{IQC`a|6$@s6122K2z5*D3vOmlwgWhEok3W zUxoo=&nf*-Ow3JF#9jxPtyJIVAluZ4-41e2g=C62;wi$14szFy=iKP99&nHyj%Y-_ zoz^QfFHVq_3LoW}m3(E&pkr*XY=I{5BMaJht?2%rj3Rr*Y5hHpVzaJA>09nSd5eXe z0np6IXm)Ho_*G=Q9?cCtWtHxvN)wiK25X0>-evdB=+XYUg>Q_T<)yQJ?RT&ao;xU} z8m&0XB<)woZ*s^q6wNim0(Zmg`ve$7vpPkg>lB||3Vp1o6D{i!%y zQ@i#xfeh!+FWrDZ9uop_fWteHn@p4$5C1GAtQdND&06qE4dcIAFSs6a0V@y(t_jwA z0-Y$zvqkFu({HNP`3#V2Zc|w;xF86i?D=PD0)jRzw~(Mpklj3W@N+kU$Ej?|Wddo> ze>72Wf$CNY7G0o61o;!r8}hFR%X5oTKYE>C0_g1nk@g?R$MCYpV6Yh!6|(B$q)dO-Hb zb9!aU@teO1F1P@gkx_KLXhj;4Bcl4bNY5B^&sLn*OO!64HbY3qs|BRm0p!?2!7^5) zPx2<7?LDuDsOo!87z(FCr)Fo)>+Oph>M=AAn6X^|rQ{_yvLc_#1tXv6HIa=TrI+mk z!(|!k+oY}ppXwM2y%y=bY(P_NhPqr>69EKvh~(yc#R?MGNRj#i6Qg8s-z!{?*sLU& zo^B$}Nu)?&ihM%L#fnUSu(niBWb;S1P@XZ=am|c};Av8>n$#^o@S4ooW+a8<8pu?$ zbGm~3H_l(pWT#pE#7sXjtC!658?*X@nLahE=?a~tsH+sZI3J44LO;=CtVoY)hxhnL z(U)X5{Y3Ydc)HA+f`qQW6~;^Ky^DHRw*I2tL2cyhOuG3RUZeXL^}3Z&0RmK#&U5yF z>A_yWX)48usEe^YTcGjXPKFXPR9a5ShyjFEy`)FScH!X)*qD$J{1ZV!PLhj4iRUKE z(5le$d>R7t%m)s`OH%MTH+k@?C8qd!fn8oE@1HcQa zz@fAOs=8PvnCS1!=L`MEC|Fs;kjDeVF-dTTrb|JPRL063wwdWCa%r^L(=YT0Uw-RJ z81y9S0-UyRli0ZJlSV`6w~n25jirN zMO@eGMmmg86~Bv69xxO>JzVS#S6h>IR*tP??XK&kgF^_=4R!tCZEHJ#gOEzxp>Xun zVJX+4_k4L>59$InnOqjy9YN|av4JrXhp`fzuse>XO^lwO(U|yUbd?42-5S&^g9{3@ zOfuwHwD+4`IC04gv-CzK70qRqQY3rzb=@X5d6~w(;Y4YkS+oQIwuh+$kh9CQ#7z@W zoeuaAHw!kLU1};!|mc}JOF(>w}^jAT|kUX608XLo+*?mSf!X*C(WO&QVeqY$x}7eHGuE=e{s7q5A5V_?~;78~#Gn3rIev zA~4`1iYRk>Dvf)gy{01ESZ%BVlG&!<2DK$z-=N?I4f*d|72Keq3KDFUf8I6?sh4@l zAMAI0!2J6R{(TGo&W)#aE#M(ZFnPcy!ppi9{fOFe9Xd`t3Y#|fG`YirC zy>II_Bn$A_tfIlQqsZZ+k@q9WcSVEON0LdQ&Tk{gqEHvw*`Wbv!^z1|=gDvs0&u2> zlZTC&NnEg>0nHd&};$IuXwwl<7-|1ts!|tF0LK=U=(KVp9tf$;qx0!JX65doqIjUVKTuEknhS|ahjJB zg4bNI!>o8w=!etg@9NDu1+SyleLR(LX|QH$hgkKUF%!n*Aq(76KD>$E$qZUSC7>}f zX&auj%??1sSfO+7Ep51V6~ESvyjgek7G@Q2I%vG?x6o1uhCwMY~;7Yw{K)=8!W z>4GP*UMTQAbDPP3n*^Q$o$Qjyf#x@+ZpO8Re-~A@9RO}4xo)~qXpQC*0bV2|S+b$M z&;%}nf9OB5f)!x4nq837f>uRqA9b^=ySh)>Gwk00_~PS(DxFsa7#gu^YJaVwy0kQ2 zh5fwL29?~A524r1N*J!WrWCnvA(JgGT(jB|iuQg>81j5s95`^-0$Ve`B`50$dnU+G z1;a;@m*o_tWecd9X9q`#V3u=NuU;aWMj9Eg9YEJYPJtg`BIV9ZUiy$PZ7zngdv}dY z8KDg;zyUej_Y0&r5rmMMUT8atOHErm~CLO`N-XguVP zbJl>VB4V6;@c3IfG;FcJ-<~em_Xq%pM*Z357e-n6dwTJ-im2%TY?kWE3M4bFd!enI zarzz%B-fo#=E<)C_J@HaJvoWXFl_ZKRGOFpH)=MIwT1mm&)R3 zcFKJeDgc9q!SfXhoCvSR;;3=86FET?E0xWXpWS zY85*6=l*<=7?>vq=5V}Bcy#z}c%QyxAM`5dSC$R%TnmLyjK@XesRfyTJ@h2lllKR9 zl7s*(3q;R1WAlzVk#{y}W+VE#PCFMf^K z&9L`az^K3E$$!wFgS<(|n-)VnL2uX_jhh_7O^yhbhk%FX-((olk^b?0|M{4Mz_9lY z+)sF2yhGlfoum?yY5`_-lyS&=?9Vfe*}~rZ2Le)xg>)me>lhu`45z$p2zjOA3%>^e zroo{a4!o*E)NzBy{x``Tgj(8u7*S>({}9r&G28P%k4lSyADGuYQa8DfkWSg?B3D%f?K^fQ%SE<2viON`VF- zH`-3fkUXxDyTMoFo%bp@#`#kC6-ROS!eq9L0&+J+D2wJaF%Z!2)tyDh2O=^ygMfI) zzGMcTY=+4?RU(T_e3SGZ_d}#MaA8}`R+xA8nE9eKt`E+QGIM;WAoZJdheEcQkp}zo z2YSV{;8iB;b%|t2)~gcPDLGC_Fjm&{{;n8ON+DcCwk}cNd$%q^U01X3B!yfvJAObo zuNkIiqkpBS{S8tY#D%drp-ggx(gB0V8g6UAv7${a*G;6|Q&9Lxu@Rc{Ope`v(U;U|J|K+tD2He=QwWXot2tJqanTqde{McGti0>Y>7vb|t zMkwjLG88%-t6b6(#4_%r*Jnir9Iy!~sjTWx>BZTM-_y&mCWExr>_MhSVlkp-H|GeE z#d3-jV`tK*MX{->R*g9;xNWSxqIF`E99jS?Z`0}vIWcVL8Fx{(z(=#QNIy+s_XD)H zEIm?d%!*Xh>N4NTT2&-}omNE)WF4#Ez`HMLJz2*_T2WTNvDTlZo^Y38cbjPy*tC{f zaaOODR)W@K*SflkFsY3eVac&X#*avd9G=Xs%+MOKjMFoVv(|mIx7o}%tqZ%6?y1At z&-GMh_g=%jYq;DsSn^B{YL5-Y0CKW5f41>0&5yl3MXSQ<&edLHGq!3i*+)CIifq}3 z8e_vZX*IpSc%>Vz(|2p}Z0I4a67xN*^<^D)Pm5spk4#tDu`}8j_U@NjGdAZYe%tRh z#v*;K1qqQUY}hf(M#H;Wppa9VMa**-WA8oE8nDVgw2z?RN&hp}FB-A-0*r@IncdC(ojCLMA&pt0=C`D6mqYuJkR}Q2 zJ%)jN)812&wwN=<6Ud5nMh~xa@f7v<>5}w%Qu3QgkuRsDB&YC)64<`pn5>WEJW*`l zMD%~t?di-$&%yH)pW_JumJ^THPtbhXoxPq=c7Knjgq)B#kk8YzgE;@-pvTGl&v>e^ ztDkyItnX(YA9nawdIW3pO?nU7iuLI+ttk8W$Mghq>C~ZdxHB6Tq7`Aw7i%xG$eHN2 z?YfyhY+!&^j>fPt9j6AfuKfJ^#af-YGqG4EMPXHZSw;(IfhXLdOsl8G(7LQ`2dxhK za)#EB6Q9C9oT-H@WD$e3@oce=+h!RQmlU69{CL6ZS~27921!V%gW^)+S<*ZNf6Aw6VXSvL z<`>Jg9=qCIi*m-r$M;Q68T{(tB;1|k6l0a=Xi;+M925wRWix)88p*z00E%XdIVr5t z%Cbvau<-o1Y0Z&6`qB;!@%cM6Kcv~ce+;Ygt>ZXQ_hW4kJMj%}*z=B7lD%_RE5|Y( z;D*abV-jBZ5$m|pV=TCOKWb5|{Sz#ycNF)#Y?#Gef}OSCl5bS^OKh>tjkLWXIL4=w zzf>qf zv`0Umc65hZ37}p*y4(Kh_N1bjF3~0 zJ*C3+qxPf-qXe7 zBN@w?B@Xa3Vb$Y3FR|&Oc_OGkF%cyIV7}Rx5GI?HPEb)-_t0IXlp}e?7gZIc~)8L3|{i z?$O$@sX1C1f1e?PQ&TyI7&tf~G2Z*c9S?#RXB^Uov7RUJNH;^=EzJXxlZGd}HJtgL z2LG*l0q3rKrVVBXz6RYj{8p>rDl&Y)(8!boOk8qGq<0|?j2oPo5YL+XxvQ{5e|JeX zsg%2fMQzb8GJ!J}W-sfm$tqTMH(@Wmio4Wv%*m@D@r7=6b6oj3A8N@W?2e8S|#qI!B zaTB`vDjU2qU?&*=f!&~&Hv8NSX(ca1y?)m1q7B%?9k{k_vSwpn^uz@2y@c)Um5pwN zReKD2(|>kvW933Ub&({yB4_Mz)jh$iQXP+jCD*}b)^fX6+aM_m<|%b}YD`ih+u9wp z_U=ee1?E52Gm6$=?cel7u-7JfO3~_^>l9~wCxZcdIS{Kh#nZ~-9Ga3mJb6HJB1<0P zc{zVMI#~8B+-~wJPivM(3uYF&)YF}{%fQ_i`MB+-p>Zj%vom!)v8?rWaO!INz}Cxr z*ln$}IJV^m5o<9t41|^$XO>(|YW~_EW)u zgS2QA{Jz#{YFXx2RI9<>p9-QMdUduRi;U7b%zZGk82hOt!Fks|>L{>RUi)B{_fbcH$2Xk7s$lX+OaRG?6U+)eOE0S<_ zV!7MJ8n1BIX8ks~+X*?P*u$IH=Aow(sHhW$* zsLD%0mv(xZvvDV}&CfdRak1Eq8t-#Uxcf~#Lbp_?oL~K5ZBeW*$qc=cfkD|a;+a2*(m^f8y#fC1$W`=DjKut|d z9**sv^TgK}NWV05&I2dC&F~{kry;sVu*a)#ujQ+?@>u@0b4V?|Cl_U@J3!deu4~18 z@-{swvUY7gr!kMUF|;L%ipRz}^fs8t-k(6OBWw_)^&kj&Yr?=0k3_g@;C>w<-9fBD zxv46<6bZ(4r8s!v@`~>1?Bkcfv!2#~IC{7@xXZB)pt-|cjNe>&7vs_2!S**H8;|G{ zqd8cqbo@GCj=Q0lG-3!_Hi*ySEO&9%bEexS&(3ea=(fVy<0#ApX_PVFRzGmt}`~=k8g|c|BcbH?h^yvMln~^g!0> zm-H%l2&28?3Ak9Ij7=!b0j))(U~gA@xqaBBaLD$zYT^w-Gz?@{OGDdutsDrYDaBSZ zx`I~RG@^2qnrzu<$lJYR@OtpuTsd}aZLFM}%B(?SY_FFZVc-3%30l{iYPBF)8WPLL zk2Mpk*a1T4tgc#YL|AG<5`_Nb_>qwi|FQoK2Xh%xu*f$5fVpma0DDr~*R>EoC$9EN z2R$it;JsH2)eC5N(*KEM?=8tus|CLjSr0ZbS8v8gCg^Zm;Js@a|o4+<&Q{V zOV?{ocJPSST*zs_u8y1@#>$;Shtd@=-i)hQA-BKR2C#G!2r<^zT@JIzmy!RQaf6}7 z7`(M2Dc*i);#-l-cjxIqwP10x;|;Kn){b?TQ|wKWhr|s|dYKIy;>lIv+I4eF?0zpd zrVXlLD#(7*o8XRLOmaI|?09z!4P})VV+uUUn!|1_ADQshP%LZcNjWTbySpMQav38k z`^epfzl8+0OY$^jEB!!vJAJ_BGJVj>4nzy&7{Drop_SYQo7~yXo@y*T-cy#vzT>IK z-dyI1VFQms?0bi6BJsy?@nqdoi*I-(SfkIz1~^jVUyn&m84#1J$nCt5p1{8UE`2E0 zz{7*!8%f`%@8Zue=$Jc#mGjX;%%yXLG8IX*SM#VC0)1q|Vk}2PFk2f2)gw=6_G3LN zp$B8Lc~A$JU_WZcZZ_76(UNRv$60}_b{~+^jD8@csc(XHKt8L*9Nj(sl2@yYo(|E< z?1Ig*6^qn0Z-~suGyCV2;^J(816Rq2dx)d@I`DU9ut-9uQNaBOI&qVR0ni@T%emU6$s)|J8n$SCa&2@1$pXd%QT8SjTL(akaL zsiv@I3B%dGpD~y^Rowx8&Zco-<^x&}?*DSGn#kgQ#Vfqp-R;Ztf#9yIx`B`F=;=;n znSI>V^VNbxt`||= zjq)_64Go=Ay0A?vP%U>rvN3*Akqxbe zO>I(D{4w;r0Z!KK6b)I8eeo?i z9c9K&crgG(HY6IPrB`vc&(|1iW-cT4O&-dIHh{sUZ*!PO?sS5h`g<35RW^GWq`|8r zv6>zvfFJGc?v|PJZFhfmJsm6!J7^siGaVAy_8Fk9>QVUmXf`?so9FJuuFrQjW4jh( z!BpqUM86ETNy?#-Ipw(-sT>=$7N;Ky&f~P%22lNetJ)@#sF%IWcN)_ zX{$IuICZLl_id?#-TKRhT0Pp7%ZyOdEOLV~*27D~m-+B82F z)((63({@@hA*vJe>8u4hlanH`)xI%!07OxQr}kvMKbacJhIhux{;r$$l8|d=QM?R1 zhq8||@wzwlgXAXk=LV)q?w8s2AzHZcLS1|qF1F93H8STeNcQe1*i!-~fcVZ&gcaq{ zB(0V!n5(&|3BwJ&Juz-%!5%+(IvBg}T&u4U*7~r>kXccz!hWoh2M4ilv^}NukwP$sec9CqM*>)#ue9S*=-}kHs;~`y7~>Z| zVj(_!qJ={s`r@tWAuQl`NC{@i{Tgdw!y~ShSYE;urGg}Zm|*>ygVt{Fhx9Q0L5)+U+BR7`?(v#5@W~`?i6el$>ZHE zk)H-X9iW56OJ}EEJ;QlyI-jr3tHA%oFJ6Xp@kd z8V5B1BGd5NDwn1W4f9Ge7G({9e5fubQl%f;^VnfRRGrM=8{Qe71c6M)XcXs!kci#7T-$L}x6%&&+J(o>W(#Jk?LBTuV-KtZMI_#+YEega8zn~} zS54nrE5wfT)}|upKa5%Xf098CML9OmLG27|jPAmY4G_N_pb^|?gbS2^%-T~kd@`HZ z0%{G0Sq~Wu_X=%;eRO>>tuY-%!fc$Fle27%;Yb&x(vzIM2XS-fX&dC?OSTMg=XDfx z{1#g#b+t`!ceEF=Zy~UmTW#Ln2BXv)$>O<#=;r^vqR$w8!q!gcFJieKzi5jT8~(Bl zgXY0$N*4MAY)kZXny8X`dcX9_J2kJ3TUur;k>s1^FLc8UDKzV67M2)FXNuD^xfqm7 zhG;Xv>LsQ=jo2=*bGkOw_BNVk?Ue!FrD|u%y89HBS4caex7ctG5>2<)?k8p*#3at# zi(-#HVGme+!tUb(QDjohn(bfP$BJJzqUy1aBLnh^3K2Vb0;Et}NBZ4*ijpR05=G$k zsxVP_y~-c9{(;O-`J-yN`0j31chSVxS}IZ_t^M5wXl;3D6EuEVQ#$)v4qV)Cij$h# zgI+-Ow$^u`7bxur>uu_Wg1tWkwf%i}Yk*s{NVLK?FCT^2%p1ii3MU~&E?>NUf@YRU zk^~D?*4DqmoZsbv8g99mbM9V%Foiv1&8r)i)vio8qHmUNMkn!872>a+>45=cu;VDZ zLIero{hx4am!4Q2BeuQ>>FT=~dh64-=my&7A+oN3O_|vG4tJRGKGsiD(fR{xqzL+e zHvZ8e)cnTpakMvmjQ)TAGZgi_->iwA(a5Ypym^f;ZMy|&)$%{?d3pd8QFI{O=Jo+g zo4G43L~s`G?QVoEUet|8FvmAReJ3QNsT@f*y=c)F@m)H=7Uk~fq`C8{Baqj53+XwV zCva+&`^w72%j`XPS(NyDi*1)&?RMD)2;YMkMB!g!7&rWelKC2ZKnIc9 zn*Q+He{43FfY(Pq9W638wH^#I_+AQx4?i!F|gboi{Gnu0sT#A;m=oKvebDK zpRV19_T)NJZC4$@*0_1pp6G#fVHEQ|N2WuL^T%`?WjlL08oSd8zIyCSRJr(;J_E5E zEUula3Kbt;u39A4rE{DbRINU^q^`)hiagJ~R;3d=YN}efHNtnPiV`RPt8#KaNQX*G zd5U~D>jV+&j_G(ZfR1`-5Dwm!FtqIANR-^M#@4vdkV35gV%dmQ_rK7j6JNBoHuLvy zrIU6aqp8-jAb`Wu$ zqb1hSZWFW@G`Tn0zIqNORF6e`t{Seeu^}RAnZ2$E{(7aKC|S>a?|%s+;(y2Je=*@A zJq>DOzqlFAZMcCFb9D=lk>hM9+bXifHv%Qu?yMEAd|V#Ir&aF&$w^cvI7 zqg-D*r6!NG zx-c11i>TAcU=(*lk>Km~Z2dG_zA6h7eA56Lz%n!D{`nO)hM&DgQ&0mwK0D~zruN`Q zf)*h2=?87$fjsZRk{PI6L$cyX*1E6F`!Og#IZ3;(a))O z#PCt}9@y?Gt8bl$jof=aCc4|xXzNzXAjMwWXzwM$We+#>WxH2+iBZ*DZj&8elXZkk zWL#F7Egi)7AJVU=?tlD8sBbvfP!Ze6T30-Oz6z!IGlJXT7tD;WF7S%JPUF)y*Qy4I zKc~`zBjEK#@8(N`+>^`2pnFxF`SHP40ramg1|WDfLGbR$q9z{sTAP4qsS<+Y6E8-! zunwy=_d~?(Bn*oF9niXsd!eK)sTi==Ne6($X=AUB5P3r|#o=lCi_8*AtE_O-ythjZH->IAu8>7_es>9)KhN5Wp|z+etZgJ_r0fi9`#nj%m%H&qCiAc_S#ES zu3H%(JU7t7t{p+44*r@dL&f(IJstL-z!KER3}fq}oH?_34Z`D^wW(BL|3ELrx5B?m zuYm)Jyg@+VkGtsK;nB9?&B`!1TT8B2zPPA|BULkVracHNI7FBqindOGt(}+{jN-f( ziM6sR9!)u_i!IsRF;1hMt1A%L#WSgqeHPK7-exM8dk!A!&Uz|v;9b;q&29vHsRPSG zZPrT<@Qpvd#3DKM4S}%Br)?ue+BH7CAB}OLvaES=$Y8xDSP7P<_C621zd&b5soY$m zMiF~wV>i|ri$GoKf~Iu|XG~~thSm^t1#~t>8M_zVE96_618LDhq|W7go1WnO?FM3n zT&<8n#Rc~0uuv_wtydLuH>sa{h@vGZ{`6H`gm7@6C|GIt7njD<1y&EhmPmgdMSJTx zQV%K%xb%#jUt^Iojx3IDvd4&o&F~;Mw{WMI>f3sXxTBn{a2O9w zwPIAk|6?z$#<7?Fqi~-+v_+(*WymklsRlTa8*WdUoMc-xD>Z5T2`*rB5psf-mwmz> z8YrKcWU!=KCNU-U0=oX%g{l@J{BqSh;?-ZPI?23}-m4~KaG)i!s-uK161}3|igs-l zjsAL|u;@m7>dJ7fvBX#|CC-sx?a?qmHKUvtZ|3lBuA5nCF3>r=Nc}JyO^SOfop`#9 z)h14KpwIA5vl=yC0R2uHMLE_%4>M{NB|b{Dor^EmSoB&1QSHA-hRme9xdwMre6`q$ z*d;yWBOh97jUZmRahWwu%A-oBt07d<8I0; zFU-|$qT4o_VV6Br;mbX=K#rvmPqEhbfQ!|=6aU9SN3D>4Z*8&-MvFN1)0&F**+Si6Uev6Bx<@(W z^cn2@MMJS*mma|qp7u8m&oj~RSWq7Ag?lBs^t~tTvx7V(!=)opsVt|YFmIX&*@fmg zZsp_Z9GY4Wcdm48w>`ku8$(>mj6;q3i^%;LHIw(-J=FNA=-TuxEoyhPPjLmoborR0 z`a|8mlEt5zY#5Ignj!SmP?Uno^PexZ#)pSFdpKQA`IL%cjC2zb&`qyd7l!(l8}p24 zLx^;z;EB?Y;LdJ-V(lcRe`_rkxo52}i#h*T zI=oJm`EogBVWL$Co#=bvs4|r@M9t7I#?tMMX#is|w1afx@=$)NRZ^CXDm$-7sj2+} zd{%_$mcvsGGuXz84zF2<$biI8sfhKqr(uW9Gi_n@>eWU8%(70cv^**iG6by?yAct( zy$Q)%@V0FzVY1TmwgexUR#j#+mWxZfAopgx$UCpK1pFRY0;2FkqFRYgK{?DV6n%tp zrmbQ9+^3&tbd#!`4uB@W!sssa1MNEhfIb!Z5LhZLA$_;rk|XmMWs;xw8=9?C!yRdo zgQ(|SlA|)V;&c&x`}FDd1UJIJGP+Mh-&=&wAS|+ZhJAw8s?^i$SZ2?ZLD*@v3N%(F z9SFK2PL}`Si7kz_diZLNpp=Xyzg1Pz&VL`jBuZ>ZLP1siT@@rw{$2H?sP9Sdxx|mY z_bp$-Ig3K5?1WGxuHGBa$`$drQc@AOE-Y;=b){Zw(n?5KX_-F1oVs_@sVjnVl5p^9 zEg4_7SE`|pP6-M9y5jqpa2IFV|1S};oo zERFP4+H1_bPUIZH5&Yl?_RWK=ya~tXyN+E$vEKZLE`IXA#Q!q?vo`XGk#w;n$pZa! z%_`cr(-r5;QoDv{>fix=?}2hslNd>R-Z_@QEH;SL);3noZp_8824u|Z1JG%VS z18gn)B-!f@rG;jFc{1rvs`cEv1nFN~X6q=~mf2$M6SjPJN9S7khW^_^Jaz9@uBqE0 zEr^|nYw3HKTHO!YdWrb2Y@KN8u6(}!;+s>1dgon-be{7kRx9K~Gx354PESY}4JkYn zDZ8(;j}mtp+8Z{0I7^_!)Y_qhx)?Q=GLSFrTCTl|_+vWfc&P%uck_Ju^8xb^(Qh`O zTP|#}hc%*$a`1wZlare((AVJ&h|HJBd`1#2U^r!u+eU=%z!U4T&z>xf9>87ugk(Ms z8T}Kjk3z6j%JcxK2WvUgZWpS`yrop}U!1L}YAKTbf*XTo7)%m{%$`)jSA{GI7pIya zRRPVg?=E$>wsm*pFj5#*^wt0Z1CukXlSSQuSfHew+JwhoYmPXViluQ}a>FBrve|VL z-O$oW)`qa|y*~Oh%2$_|=(JsW=AdTho2*uGXrXnlyQAOZq}FFAs{O_N^{_>!chhvX zeMI*gCzg$0Qojx&FPfc%Qmp*J`i!vrik*DwDuOx@4Jxv{ZAoZvo&CI{q?wbbi|3}ZaE9;v;1fX?%}4_@OFo4JXiEw&DBgGHOy3E7^1 z6UqJI9a}?pN9+TugPf~m;q^Iu#r<#4^x3CvUECcG@yzeG@r1*$MH;O-$Jr)%VBLKm zfnJ3@2ot}^#1?GZ2yrHwlA3|nH32qQ64x7Z^CgVJSmQa4wI_vkg= zcomCXHBqfEVZi3EgGnZxda$_r4hCuV`}VF8h-i6E`Rvvvvq6m$mrIX9d~pyeZvA0y zF6|@k>)2Ox_d~wnzVg3?3w-@zRXmSRrONhRt70MmOwkfLNc7FdrCUHTXr* zyl3d8suneqX*SEdQh_VQ*4XI!L<~vDnPxPW>F|VS7&Wt0s)3w2Bx0Xf1p8`VO#9in z()xsZ>%n4uAA5b_zRsHLrV|qz9gp*q`8Do6RW;}NhIP7IOWEPp6C-v~y~_6yxa1Ge zu@m;t9^N}hGQp8hR1SJ<(}XL(p!0!)(pP zfe0)KmrW5TL>t?5aj286VWKmJr>Y1o#ULfcP+nS=tdsq%yc@#^TVHoa8ySsgBQmDq zz5i%JbC%Ds<%pnpuw6Me+elvzX!^+x_sPVKSD?mmG&*TizqHl7G_5b{y-IU^F`kvw2zg~k)Iq(On zednLFqSK-1!sAi2P;$9Q28c#yz8z!lsqtquu~?Ds#@chm#!L>uXwB9#r?0$A!`V5S z$neRjqy~1?GP^3Xmj;R#X3>(=1bS(!`kL|zjGEoCbP;0r7Rjn2a~Z*r2VNI(JU=mi zJ^O}i!gOu8i)0Ee&{(`Hld$J}WY%ovzC(s=&o5*A*L!aS`Ox z&icJ-qF7N=l^{Ac;fA!J#{H`9??%^UE-z`;4-3L$IU8b)avLiqhGJ9S3bn?C#Jg)RXx)OS@Q`MFy$I(2&*m9T#(UvDV&tIOxdm$!% zGWj~fADL_!jAff&4??zOefoi|jksiJqAfWnP^J&*%ggfgrr9NVdhu6N4kR(Qp{V?K zsjql@x^1Yyn~N8p6riWo?AUeV5m$PR1ky}gS*+n$j+ry)G1^sNBfnCGt34wZ8gA_> zTH(j5v2b1#wifP=fif*8L9AJWk#co2z1Wm@33~6_k2~I8=5pU4#lNf+-$}I}rTnyc${z3Ke6d+8NJ@ZaPtmllek1w^ zhl51&4fZhqVk2%>o~iZBQgT>lyhA%0z7OZ@Z3k*s5(8Mt<^pm3D1zMj2)cJ?DP;7i zW8}ZS`#Fsu=nI4!r5xauTR25#zwQ4D_HEZ!_8>U9A0$z{={t^iO0x5gD^*Rzy%OHm zf_qhMM9=$>Y2?>IY&e699)jN_9OvzF&P&SmP@TMI%7IQwtp$3$%$Er zb(4`+vuOP~PkYfglr>#>H<^1W>=UeY>%>EH>SuGepHD)PF%49XD=-|J9B)JFI$U6E zbjjJstl!Zh>s*z$_$Qyf0!urQpO&IC7OfUoCy8&Wtj*jV@v@7E5P@&neEk$x=3$z~ zt6?P>vQwBs z31_Us#i1YJkI!G=^!2aOhJvp{BiQd+M{8suHcQ;9i*T!f z&keyiTTAXQg_RHGd7O?zq~J++mCN)a4RJ6Z3A7(0eu5ULrMfs2HUqxUi2@TiACs(V|x~%#j(H_Ld1T zPX7<97yI|&NFK7RWIp8I&7Xl){pw76XX0Zj5A`d_Yh7AG zloA7kfi%xZvw}pof+ex;N=q^9G6P{ucd7{PHWPtCbj1HKo!GN#V zR{FRr4aEH^)iLp|mZ^lO8B3Dr$SbHQnI`E2w?1O}{i@chKU@+a#;9;Q%~6vBu!HrSWrA=+JoNVpX}@^^yZu? zV)Z|?MAdd4JPOm|`$;x~&@X9`hnhl=cx1VDc%xllj08&VgpI>GWiss1{DON-T4wS57G#4n4Hl)!3x z17GQ+D((|zVIf^&u;AMZd;C*~Rx)s;8yYNQ04W5~IaqUL zIlSi9Mmo_w(LUJ4QsQy{?dNe$XQ{zTGdr*5p;JtK?@~S zi^DDX!uqBd^p%y-42PFAawou;a|r=zf0=q$UWHxgagXl%NbMgs&-?2z-vY0@kIsEulq) zxvqslZbF!xB-V{h@t1XN!}`(<@S+kpg^)$Huu3v5At z`3#4VXLAgdArgYbPtvE}nQe<;a0q4%sRz&4{6cs-P|ap0>?c0Nc)eKh`Rrw};=(dp zM1YTr352;}?38oNN{D!R9R_Hd7tpq9^4UKxqH>>oom}x`jg+KKZsagjs}CLbc&(9J@9DBGPK&ZKO=R9T3c5fU)&(j?`%I3^~s50s{-Ro*%Q* z873Xl813~y+DVBBRA0-#!)XQZ56o^jj~-h!WgjwD$x*~JrOVTD(Ae~pufZrvciQI( zYy?j)=!nAn+2WW3zBTcXz48BX&=^8hnkU{nOmZeU5aHslPiTidPtXk}VGxLgC+(eS z9&*f%bYZ{zxvHm!e^!NARR3KSCxTNrjuf1xqLI6GxPNYWX^ugTPLL{huqUxEdZR#% z%nb>%=A!S_QL^LPVz`hP)kOT*gP!wXHx%N=ev(NT1XXY{%i1M8)D?huIN)v1vo@+7 z^F{`_k0@J+u_z4&InuGAc=4s>{&f_`pjuYnUtC*(qSSA+t`uwKkl5t?sJ<41Fy&lK zZDSF9&f3{u@-5!28MtYr?maIs?7~YMP2%vxnawdPNooRFuoryis4G->;VafYG3N5t z4-p6sALmG3bWE~1SO@o}b2z48od|5y068$>NK^FQBXNa*5b2TXO~xsbn3mE#Q1oxpY28{h`2b$)t&i*t{2ku9W^HxdyL0=^MbDb5 zk)oX!LGTbiG@ff{HEO0!?SSe?u_BE4>Y}EEI#jxzF(n9DTWfpq&oESKgK-#^PJ1vy z44t&XPu!YH!^f2(+?=>HKwKP8-Bd>B+b4M`x2*`B`h2mK>x=wqI*{dSIeW|3$;Ews z2S&v4cdVPm+aD6RIdRcy7gMef?L1pUHFw?Aw05R+5Q4XqwK{~#BqURar+nO`c8k)47NYVyAS^x zKiKaz(pnv_qhmU6wl#p(Qn><;oi?-PG56e!79l@7R1B0!`|v&yB;4_a1LfOPy#|?? zAObV(KHlCLC1n-n6me*_y}vdXuAvxjv71G`N_(m3ol6}*s zk5{!C@@DE<`xB!13-%CEZxwkhFP71R{Zqz+KfWDRux!7*oya)ibRls(Il9O!S61uCqg?}d$>D#iXZ+XUGu5V*0E9bT#7pjPeu-An^9;`%`S1O zH$jnc17K)&WLmpP@&qpBBK_s$@z&#VG*_V5(0PS-h!UtV;@#A)%Gkpp+UHxRubxVW zi0+6HgQrvDiRJW^@l(0^D-|dTHKe0TQpHT^J+~5Fo`%NRF&~S*^V8N!;wo*|@r`zC zsY9D})^vBr|H%OC{tZd2*EU$aS4C=CM;kfirA5j_a+Ga=FM$Rpt#W%isRRr6aBX4{ z>gZ?Zu&(F#S^a2LkgQRn&G;ogBIRSU4EC>ILL%fb_|~7!AmEJVZxNw{N=+r>Fb{H7 z9pc<`=n7S5l9$+ox{MJM8{;Z;bHhQ{;b-gYNpKI<*E^i!nuJQ-9A<0j?&v6Of-q4s zhD)y1;Uw4Bp6(BgZC=s!`>A7IB-4$KgddPrrbd3$w6JXzpLc+&Qir9U$iU;dl}Yot zG6A*tSi04}C0K{`%(l6bkBSz*%*30Cei}Qnr$#-OKZn25QsqfS=JOb;HP72D!fyi) z^wXDYlVmMZFVaX2Z%Cu_19pe*v2~USH3Uu@i@0E`x34zG0;)-TeSm7HsfxWX+KNP- zTWm59K$7UP${OwD-1f@^^K3cpd2#~nFfQ8O!oz`?D1L3sfv!9)%`gpAM+EBCV7=`5 zmJC7lsN=iT}=gXUY^>ft)Nsd7OFGWJ)}L6b-W4*;bMA&uPDE zRt)n;AVgo;`;xxhS{d?CV&aw?RVy)c)ugV-J5_1UP?&c^QvK>2ewFH zJZkxF0#VbKo6r_6_oqvC4eY5acD0bLhlJnVyx2)HiuuG4$lJlg$PSx090h!1xV5Wn zx}8MuCfJ_)41nY<|6 z%lW9Eo@GnJ#GVH5p|r0EInvi#+$7n%P86|=8@~A4eR?5ns-J#qxNVG^bFjWwn`P}V zKRRkAeY*miF4|GgWfJ7*TqDJ&8Rg^_!Ze$KbnfGL7^k-ISb{cTP_{T>OLB9jTZMiH z@0#~7p8POR;-2ry;e=Zo^IZG(m0DX4BK&V8=_wOt+Y_}hH4Vj$IgIQGM(mQ&#*cWL?KS;`o`@G4|EXFhd~R1g?G`U5qzDtg->#Z2w%@C2C(=H~ zE0&X(tlDbzlUh}coJb13?|=1VhgGaHv^JFy=6X#Y*#nBaF$VBk(uTxvYY>t z?RUkC*;p){ zCqvN3=OWfEHOi>Gm@iJAOQ0ZNiA+;iftSB$Ig?Ga)v_&ats>Zl`9>nwtF}(=jwnfr z*7s0{G5oog)^h1EgsJLS$;l_&9nKuWp+{^J1Imo$YP%?vAvp1gq(xQhb#^Sew_YYD z?7RCASXGmb7)s2l&nSC1G0W=V-^7TfbI_lgp0yWhDc(cucK_PxRO*RS%k2SCAp;q8 zpoXzhQnFsEqOqeH<|-PLT6_5ixMZWEyim)DR}GS9W>_QT z7~8D5kPv(466s2Oig}C9u12TTyo^fy{dGcS!{4E`Og=*MICcaXK77(TQ|dl%5%sNg zjL7}Y`h@Vmh~j*?5`C8Sr!~cGjM#n&hhqI58p;qan4V;B2*WjX>9oHMp)c(aX)6;$ zbqqqE+Fr0)nVRaa7d0Yl9N#6hGF!ZHW54c zpIjuwV-~qCXC#NDdUP_i(nmF{rDO!YXe-dHW7Rotu-n!TQ{?`a%OZmsIQ$#v45da= z*=CVuCYF6-8{=;%B;3cqcQwb+?GT+x&LJ4iv4>?EVhha!QG-@aZ5w#X)(u+mkr^-o zWO8d4@k0<1Rq0%<4o3x7%F&XDXo@zX`&5QKI5;r7G;bOaf3>!<;eI_5!Bk)LrxWbK zb;^l~FUzqrI&vf9&5r2N+5~6AnG{4zE{-X(n;x3fB33kCY!B51s{u=6X@0HAszhq} zEzUSh^>F9~R|a!flrM9KROA%tdhil_Wv1;EUc+RW8XL1uv){vG^G!1UN~TUJ-8Bm| zN#@-pl~fe<6kmMA`EH)Xvq(H?kMeRG?{J@(BIaDJDsy)vYSUx|`&lj8lr;}}_hSta zcTAM7Y9g3-Sx(+G&cC`n0+U9|+w1W6;P{J*>se}4_$~W$Ojs8D% z%DO@vKFy!$XRKv7UTrop4b$^KLf+N<3T3BuUnIswi*i4td=kb5Cs79|w5@0B=+TU9 zGVxXS1L;`?I@QQ2sTF!4MCk_fV@qYYHfOdSF2 zwu?yCu3eA<(eFXuCuu?05eu-|jqgJ|7(c+iE#G775J0w@Ocpfg)UlR7?L*moBpb!K zgOpM}vbB4V>V1leSx?*AiPse|E>$%XXMU|pXXNPCot1DGg zMNAC?&ELOU6)!41G2rgXM6C;Q8lK7TtZXjkHnMhbccf~R+?gKMDPm_DkGeb^v#v!p z)RC$;jz6)YiAdj#_Y|Bj`J%R30!XgO8e2cgC3!PZ4{BymX{SA_y>B|`%( zJf$Yf7PFtjJ?-}#WNgJcYn5b3)npR?jR@YCuMlGT=}noq-%;DW;Y%y&U0+_nV)`Bcw*XXY( zaepgjz;}C)=tdg%IsQZLS#7Q4Y4;bsKc^OV7eq~A%Cm(+iU zJyD&Ygrw6}U)x(oMvN?joZ|&*uZAp`{8B0Tzg|UN-Txvt3n?8hwg+LZe$@y={y-T` z;#|#gU-9EP{?uuQPTbJfn(pI>chbfi7eE(0naLDudBRPO&f2@AI!HK1qH$_zOn)c$ zS*m7BcbbItfG^ZuMZh1U#gazbrlt8^(;L6&0cifK-)9V^gywGG-J z_a!XgPMZnTtbWrvh|vfEyRETIB^2VoG-z?y+Rv@UY772O!!NOq+y9EErz#;eYFP?P z;3plVPa|#ZwfzTU2?i}lur;a|k?kC{_s9SxQP!61;srOC#EQ8c_+~w#m355yIb!-0 zTfW$lgR5>Y#1#2*E(33M^Kshg@f!!ZB037}qryxQu3&9r5%U&v|1|i3Kc0JuhB_R! zCbhQ3sM-K~T`}R8WeviWpplRf%!xwCM_*BBP*ZchY>D}<4hK=$wIjiZj+$T9B#iv3 z8%?3QNY!x0ocz1lgM?+E-6VPqwjvdz5VIR z-5Sf@+@X-E$)foe?S7K@0tD=`! zZ>1Bkti;G}{(`m7!x?zqbYD|8(N0HfCJ|uR7FagMD&&dpcVZh;J!kTu8le6DU2BOL z`vH#Q@(<~RLiQ6Je&QsFF77|k3XlAP4gJbxJjPQuxUM=LO->gW7L;i;OIPZFvC&$N z7HT4{-@!URQ`gqjz0n9UY0Q#HOnMT74MsEU89d~dnRLId9JYGuuyHv;@qrnmPUI0# z0Ee7cL_>PdY)eEts);w*(8ono`(rP>Ip3N4|c;DtazV+y-wTqz_%C_j_(L1 zymH3Y>7hLC4{i`oSnq>uHVlF9dL@MRpn6~3BM~Wx<}`665&p@TXb%<(V>ifPzn^f} z>>eUz3FB5&o7pwl7GZw@MZts&e&X+4_6Q$Ipkb*NiDCO_rTW=$+w%`lwN)qZ-Tn(* z+K3;AQ8tc=R*J?&EAz%iD-PfbK4)7uK3eI<`U%#9*_X-sJC0R^o5wC@;k_@X(tUtR zP9>L0^{=92t5XuC8Ie{4;eYKXWR*63wU67R%OFu>Prq&2>0h|!`zIS_ zlwjYJoTybK!;t&fGUuzIU9R<9ymQ<~TO(WjZJJ*^@zZZwWnIaemHO)F=`q&bNez0| zcz$|#%)HLOTE;ejxrUrI_z5l<*@nl6_=xXXD)`H4El2-n|aw$Rb4 z(--qa=Gs=5WRj8e24il;l$;_nLsx^t@7`B@fO7Z#wySsUt8+-`RpwbQIaue{c#Yc9 zzk*vFpiVqGO6CdpaKOW8HTLbr{{;_;=)dFgWsI}*W#;nKBAJIVyRT~!AQ$_? zgn2wg>A{&u^fDRshz4gc7qm-BaWWKzCVgRPg6lq%Ptm+FXZNZmp+~>*qQ>zlSH6-b!}*h!Gi? z{j>EWGKQoN9XZ17u?0W0B&WR8KqB<)T=cN>#mM~qJZMdk@RL2!A}go8T21_oC32LF zJ|E9Pk4)+1Rb5y1pzJcErO7CzF@Qx@$F)3oA58PfmH9akb&+>2m(jT&bz4~QZ*H># zZ{K}?Q>5iLrv~A*6+mm0mOH09(wj<{8x9*#s;h_poAvp`-nF4%$eh8CMLV_j_r5@5+ZEk8-^$<|bD%wDFRu zOp40vyyn^0=f|DtP|wod11xFOTcy!tl`;%NE6hXlhs$@x z&r&?H$ZP_20wby4=_1XKE%A>WttjZEGW4h^hbaw>Q)U;T=cPGhLY=D*a6nE`e&3=L znF&2y)wi!~TD|(VpTBMURF7`uqe`l^yd>_?IfSFmV~c3>E4n&4w}|@WN=Z~x|6LMM z48zaFy*ae!N7_tQ&TOejb;D8B@|7j4-H%=l0x=~UW|kI^#igrwFc5IA>x85mn{#H( zYvjC5`Y5?1DksuYEUi9^*Y7=L9Tcx!J;m(kieL-B*~a3TF&x!Kt>@^mE+VKlfNo=ohLV-$)@ znZE^9!b>%mB1L{y-#*rFcg6hOATICEeqUG?%Nep{kEPxefBLF@aE4(>p{Y2>oL3-& zAg<5ky05Cr%(I8m;-&er+Vk7nr?($AyuZ1@|HeHXRip%?1%VrI2M?=LS?&>X;FFVc z3&N_se*C7-Q|{Y75;szp=`2yr-fUPsIpz9^q>;~cuzWe!^|+fkuibBW>X3AOcE-4L zefsd>Lx%?j`3JbyQQW+|Jv{yD`uLi7tq`^5(o#aW7S!6VeGovG9_%q^jp4-x*i!J}G5xleDb z%Tf6*bwcfO>%$5S(OZ95Kk=*Ad%igQfBzdX`KjnxV!YTI;G9{o2fX_g5Sgz1^(sPfX1 zMJq#(etE9Rpb4h?XAj&>)-pKGg_rbtsi`DM8EC(cYd3x zdw9t)>wJXUrk#;uTf{b>1T0bJ)F6ccn@$eZf5h%5q|)mb459~}7tJ5JQ_V``2w7C8 zKGMTUl2%sRw^Ts8xb9xAiKnWDk!xRX3KFTH5Ac0#8B$SXE-WiD>iQOxBHR{}tDBZK zyj;fbY2^Rn{flP@Uw`3ze$=sG&7?&=JB8@pV+)Uzux^pQth{grbC% zIrT>OF1xy}`S;?EqwAb1zSvx$S7$jeKDK1l21C=B*UD&!8nZ_f6bp~Dp%;ej>)Yq> zpV?YF&oH>UYof*4v(WxN=^z^x^_k=O7shFpR)UEzK|Cc6n z-kR9=hl|E3ODZo%P1Z*(`!qECi^NN9o^jgSymFm%*$tx2&)j>hOKZwuj#F}*YYiyX z8xcVlk#zYU89Rs1rB_3WG%w4;NFUlyr%s<(l%G^qSY{kqHl>^?Lu#!CXI0e+j10O` z=52m-aS53bw$5hoS$YXcaOT02Biu{c#5 z#brfFd*TsGul6og=Qh`+K2^6F_4%k7YPqlAUgi`%2mY(l&QT;i5aQXN;TDEhY5X%Ey+M^kc^6+!;LoM99^a!z~|s*L{pmsd(@} zv{sH3lok=o(v!l@@J7USR!-UR8v&` z8be;K$srGvs6i$s{&n9Hcl*BOHst`n>>&Yu@LbO2*qRZ`xF6hh-8iW*goWXZY0 z(r4uvjkF#4U7XqD@_T&e^)nrwF0C`*w|eFm&VByUb6I1g$Df6c;D&}vF?RWu&UHsc zU#8{MxSDgiWW)OMBFsir8yIfvpO^hYyVZ`M-i0#Bhxw?UDl|D;lhM$Oq55d^S+gG^M}+P#dwundb8nUM2IW$z{#BGK^*-IN zcQl$}dh*bgMcHriTea#^=~_DtuOwQa+EQh!)Lc8wFr#Z=Ru<-Gfo-VBGwZh~kNz8z z)UT*wR;i^ViFx*tvIC$gBFc8T&usJ6TdX8 zEe)J&*8|qLu|h-E@C;oG-GC7zvRX5{ae&`bPZxZ1`MCSDFTdF_=x9WBf~rZ9EUHDX znv$BouBD^PTjIQx52Ln)Iole|i5t_Un$hpMjQW!eK)!aVrq>Af{bX`tq%G?;hnv(I|v)a}GCs_9azfBvVp6j+NkkW0&AeY8vE z_W>W(#j~6@UaM|g6?Uy}KeqJEDKAG|r!lyoFTZqU9$A8cp%QlkxU{i6^5`c?lXjnc z^Y#DSZaGd=EdMs+g`Y#8nYGLEO=K(M*&^M#Qw5t|Dkxw3TDJww?iaRgkScViY13yt zzOTvEg-+Rdx!bK?w{t(;+4#?Ew=TSxcI+*sWZ!&`Ne}uEjg7wKu zPa6s!TM`~yTx!e7d+K$vQNy=lW$5GtL$2r7Sxo}p*j?>~Uc_2cv z6rz~aq#hSbivh9p3Xk3Wu_fzv)PUA2*Y5kQ^u&9P!#aQ0UBo(1r~mrxPJcGHm%KK# z-t+UkwgvnCakWjmVn>sV*VoMIaeC+7ktK!LHG?s_<@{I~%)>p)<#QP2%rjxiBmYF{ zWqXL_kH;40Peb6InV5E_w4~Q#%fqI>EFY~oci_yC-uZ@chi+az+WVW}puhnCx_-Vs z-d>&_b==+h_KjBDCPgc^CPph(%5Q^Xpbh){Cq-M7okIwofHZcr18F0om7lYt6$|Ss zFqM4^KrVrnaZ{p|>8w|?{S^3xAWS=sktd4=FAj=UI&<;^T;9JI;gRr=pbrumkJ`jjE%SUZCl-Tx3YnBmF?@`76|l;QT||m2agyfAM^pO*cSmtQ}*Ndy?nj} z)Ma}o7wIC)AeirG#d7?r7$pHLO^8wYCxXT?iXqz)ql|1FqnsTXqx=vbqlmZ|C4;pO z`@Tz#QChGa2L`T=QQCtkJz|u9yT>RES>I=UPQ)mmfLDjaC=QVMT#S+g)=i61PJpXm z`tvbLQ&2KJMzMpzYxyqQ=jX;Ke_Qyof*nRMYCb=y$`|7J@B}9b=HSNQAGWuE|8cCs zh2P_X8-bqkxdAasA{D*4GDg`7?sbh(7RJRWZ&RKQ-lOc`?&G-gOKg{Sj8P7Q%Cs2e zd)Aim+|_Gr%wnSz<=v}dlz_g}7(}j#QFd{m^vPTdTw;3#_@F38`44pDm=9ThKxJil zJs10ei#!K5a=w4T$bK8 z`v~X_zORb>wC%pf{PiSV~w<9r%8|z`cW0hW@`Dq>}$Oay%{5&lCbboLcfAWez zZ}x?QrarMsIxtWk2xcV2Dh)U;kn(xH;I2Yo{g4}n*YBF$hMSO)|+z!Uj_WAi}Ok1@)NoNy22RM3YfVCG3h zaK3wNcjK;mgCSr9=W_=+oMQ-2?tKdzuY;OveE2CX0F;BR9B_0#kDm3$Ua`tNQ2qlI z0DgSFp6$7yfbHd=Jr^CwdAfkLS5Qhk$;vxOIcqz3_5eB}I9Blm0tEZVDrdrY0tX{v zm4oc~J&LjG>%It`EZdxG*ZxI( z?^AFa{KjXmgH@(jC9vWFzI<%^joNL?gM%La!Z5S8|7qvi_1Qtbcnd_a|0A#pe7hi4 z@$imQ{`QJf{^K`{1-QPBpBc8rDwm%^9;`g-wH!ma`=VGS<%L+K9jN0Ir_8YM#d4zB1R8P7O^!MBU93`h zn%BU-=Ir~MeLu2q0sHJvvgTqdz$MCsyJMB<@5d^+{PwXWgPH|!@LzoRC1wAQVwGke z(+aloBgx=pa11INkx?eLYq= z4!+|Wdq6Sg`}2CR(1nAWfS>t72p4Ptir5|i)>DZ+-~i=qpj~IAy;Gc`unq*l zRO}Y}CsJMori1$IYXKHf)`7SAd<|$tc@5XN*M;|gnhJF0#L=hX6rbRDB?1hiYy#<& zM}yvH;uIU$3}&;v7+8N}8@x^VAo%zSa>3^vDfb8Yd^WzK%f#XMLFN3ClT5h{#FMHA z#()XHAPKs0#`01^w0V-5Du7{4CqdAc4>L&*BhZjTQ4QtGgLJ7wj^H$f$>1b z9|w^OB!7sCL`Zeck!fs8_p%JAKk&nvOl#9*)-s=M08wS><&MQv3}c^64UsNg2H{Z2 z`bmCx1Qi^|=kPN|%R~;)gDK!iAfs1uz;7<|*d^nRhq6xwiDeY4z-%tdE-f}f=Nlv; zBQrO~0?BB~S(7ALlaZg(@7QO9dk*7?!sn>`Gmfb_gWqiS;&aIYWfm3p>q|xZmzG$J zl5>?=KnvxU2^|ecPfe5Yd->bHGDcX)mnD^&0Md%`3T5zB5-rj@9t{dWAz;AU3`ras znRZH-)KgbpT53i-6&+{{WST({DB}kEFh7nY8l&Xagqt+g zXFCbW$s~#+X{fqj4j9aDD}oQyeJW;D%e*HH^amm4z+ zXBA00i>IzM1Ty%aO^DBIflvxz$8?~&)`U))O)JTi+?o9Kzj^G>9GX5xCM1n2Ei{be z7dDbj1;s-Nx|%8sr97-r$gO1tQzgo9wv2zLrwtuKGNLj7i~~}FQ^&OHIGx;X$+;%7 zod@JNd5bQ`q~nGmPz)p_8q43Q7q57y#4ESE#w(un68Z zb?`K06UgfvuPg&Qz;3ozfqy8+b%|GwQT_lJDR%jK@vnI0-2Hgv1h9Di%}L!7ln*@_h7VZhkn?4E30sjQ$9k9L^7PU-J zqLUJo;T<@(XM%DzH9@h4Bv_R09FPPYx&+0&NrG~9Y=ZLMgal;^=rx{`fE3UX)OkKZ zIk-7N*#*u}{ucypNl@;vov}7SX$U%jgcDTae1cL8u2c5!2|`aMD6K9eC=)@} z1xteR%de;w@Y~G<<+Xnjl;^<@e{dca--5pabjr~{opKJuMd_5fKm_TO#=$y8Vc!LgIRU<-d<`^_$5{B25u#J3fegxR z!8*#@K?&tyAdoK&lotrqDIu(9vQL&h6Lre6hC1ab@J<7r@@KkEDITPuw7*X2(NCv* z#Cl$qPKg+)q2Vx{VgXCR+p_G-pAO*uIBGRX!xQ6miV@g>+XS6*C|9SL3>rN0bjm_7 z16-`oDe*IO%4{c!Sq}iC!01If#rqk~!P)_gAfD~!;CsrwS(_H=EK0w(bV}7$o$>_h zBjBZvb;>74G#sVeld=x%Ii^#BzSL0iIolxU3!O3)G^e};TsWaq>Yvn*^tDd;n{5N@ z-lupK-)opl`92taTBkgJ+M-h?vauap2N9RK11G+`#0fzSXwSZwn>yt+kOC%xR>0>k zowDE`4K4rHDZ!v0xag6ntno}#;y@t?0Iq#;6{u&NaHq=d2BEYbKMCDYV zhPjmEC?8`zJ2X*g7p~!D$}_?el|NZ;j7n4*#As*}ov7r40ibzoqH;b?LpJ3ml>f(i zUlR=$SHZQuouJcm9rq{AuMv1Gdn-JUmi29-vdOaCtB1U z6qNrTCnPFwIFZ2mSzrclgCy|O#6;y>j)r5C z6P4G&Eq$VLa8jbunDq~AUj-96<~C~^`#Z7!Yu06acLDoz!DvtnW&!`gM8(o`TB0Ix zhmG;zG>D#>s06W3qA%r-!EP{+&#r(XkN`^9C%|__RH9VFwcarOW-c$-#`n{3DjSJtpc8;yaW8fF|r)XK3V>i^{6Kk zl?-r?vfsi)Wgg`caE|g-u$1x>;1=Zs)}E|oS?>2-$on7pRHD-AX+8u~DbE1el+(Zt z%3@KXVtj@RfsK^6FHTgJFQXzL>sjOjY@oah^tW=ipdEN}O`gqtFU#cq!jj+hlbVsj`5mC284!28E-$49la|#Jy(5_*N%!+ge%ei* z^0IkZFca8U2aBchGE4cImzH0~Pe4|uh&J*jHmf($pOU;ypW)^{>U6N8Oy1W(`CN|5 zXVvmBBO9ki@koZH@krXp%5c}Z)$(e~)-n?)Qx+ztRyR;@#8-MljP+!K@NM#`9`8dv zm&!T~46AM;mWEYFixyFAR>=o5z2&lS@nIM<;a^{~B*xQBqGXZSEHAxOeVX!nHL`}r zNvlG|naJuuF|YNq7*92WN^Fz&Rwi$y>?#vy)tH%OGQK`1%aR`q3tjFyqw6*DTSM|_ z?PTGctVV8blXrCPJaOTQ_TOw+>rB(lDz z7)wc$k`u+7WQG5eTU-h$2zNKR>vtnhgv--}4_8ml6KZhY(CbdGSPv_iNCgvw9F&0iK;D^`MbrxwkGRm%= zzrcX77Ud`Nq@Ay*ZF-5tpytmzYuwJcZZ9YBk&k|eI>~lvF;4(d;_J?A2$mBqoSaBZ*MlO>6$fhz{+L=<*OWVx{<)mFA6X`>; z`^#MNLB`qYFgEG%>kKBzda#`9n?9WOk~(~Zs1a@Jc(2sFJYyL->glP2_KE9=&K{hiN9^P1Tkyx&3 zuiP@#CskDxTwq8kQ&;oTdaik!k!JM{T|He{!E8N4tp!rX_o9X5W$`P2un;)n+4G zJ_AwAIpjvkff;4$eL!={zLL3V)X|sh*ODU9=g!n7QZmi5<)-n~!KEgdgC|vVn@Z>R zc}?o)rt&f0Kr;-zofSH$8-+&mg}5`$R3G*K>b$ykwjMQt@f-{7fNf!7Mr5>sug>c8Z}C(QG3*^qNtt!3*XR0-<2Y?ZcYY-{zjKV&>94f>an{Zq>(#gXp^m>k zM0`)(U*E;Z{|1D${_FdXdPH~TAHed8@ZXv?9r?$pSy7cTTt71M{+yj%4EZ-@XO|)? zW95Y^^1f9?&Pcq-Z)6ch_kjB)exLsvzxjMnMNLutUKP#xql#wySw$I$e^f=eo>k$O z_^SFNZ&fv;cSRNE+Bo#Qihg*_|1}_^-m7ZJ%{=gm-+ZDOJq}mtV$(=^Z#>RZRW@8K z{ACqArJL(!zfqv7DiyA(;>ajiRnJyc)q{;ybqzgMSJec(qTj>!YpUwA>s94{uc~Td z{++72@w-t~%b!-&9F%xcRmsn*sw0}h=|xq2TgXPyAKJ(t-_wsHjUEA;!Z!M`71_q( zF@0)l8>OJ*1RE`|+C_GrXroieGs#A)nH$qjV2Lq}FKC!)qia)aG;XSmw%{>+Gi%pT zjN^w`Tg#ds^B!^@oLTD)J1(?=3p?R+++%)87MyIO#bh-yo3%3LO!~~{aTeIz~-Dv{en#^u2XXcxIzzfAZ3kvDUR=WY;H# zjgCII(X>~*TrX^NiJnHz!!|g)}I~p+sAUwd&zZf8hk0s z$#3h)jl8+`zs+y%HT!w%b>DT~`yB7Zag$+wG4JFVi{97|JLJc~Y+f=fL>D;7R$u1( z+kR_*N-lqg@yWJ2nrf@vSWAydv(?yiTMfZ<`ld#=lE^zZ3kkgM5Ond2jH9<#9)&rr98t!&_p zA}tJCwV;g0b!@?pScvE7JIYpvk%9TRg@DnvDgg()W= z;X-67@~*juV<*s@c|82+yU1MTI=PEnhpuR|+EzcD=GDNCt$Y^N+p5euTWwv-J{&mB z`)?jh*v|XUfm8HfG3F>Yb%nR&CMToFRo*7%ll1-gnf~4#-q+u`34B98i=Onh2*1mR z4b$nPkb2Knjj@a6+qMe(o%i31;a7$`_>}$$3bOe_^r5%M6S@lzP=j6ti|B{$ z^Iku+)p5L{4=4S}Z^`ZWfu8xmR!fT7>6>D9YJmPIj?K7+arS&EQru4dBGt4i4nS0Srrs6n* z(wFSi9R;juc26X>sHW{Ouo&&}L)*VCrJHV`kBhw))Uek#)$R2h51F4aN7b}feKNDA zVXt$w?A4)}y_z+**8%)VuhoJz@X2A`Ss`eK&7w$8Tan^5f4V2-_t)7#=Wb1~*K>{(&(C5xfOGJBO@X)pKX z_F9RNtL!yzg}tV*=0Fx@&c%A@YJ0vF%U-7s+v^Tl_mI6NlD4+H2N% zdkwk7gI?qYQSpMkE-*)4wpUqlHEA@yYOnPByetpxwG;u5?e*g$UZOwjwH^ViwPZg3 zz+R`=x0K^mnd6?=E9rd)tSeb2%Qze2a4mB{}F4b8GVJ77j{p$vLeZRHu!DdUbNpa&l=82aW0J zpgz4E)VX&)2ledjpsX@YGP)Mdy!P?L@&yOX;CHYyv$Gd(%3RtZqm8k%dv^9{{-5t0 z?A(%_y`0>IL8G#>e)^$I;FJF4h3N4ZaT)S^sBb)Ct6)?Usq z9MysHIfk;~@FYjA=7f1mRXqrMchW z!j0xSDiFmNS}w3+j-!?@aFo|K+{8RbP32hXQl8y1o)I~k4EmmDvCmP_WOH(Qd8fbp zR>n!4$~tMp$4;6_?kVS_$xcp6a(2>YoT3N2IB5ft2RX^`O3($h(c!<^KgJV6#=J%aU$NlvPZ%Lz^@*}_SK+d63*bJg}v%1Ct5&UQ|!Kfy_> zGM&_7s-^qPa8k-FCzYG&q*2IZ-Z9Imv|ML9=~ouMCi#EdeBVh6{wPZ3xy~8sSx((D z3gtFh-QzZXw-`aMK)*xAKj!jJEe_Ln-~zTi;rYIDQnOsne|bc2|Jq6YFdM%zS0wjT zbyjIxi(B;3HqMI0&QNDPwJI6rY-o2Fea26kEXL7?-~w*oN0qaz8#> z^%ldrux);W`$12fH&&2HxMgS-kyon?QB8>9Coci=3>9d=f2JUL=A5{&7Nr^`h@OaRA4z@Jw=y{LxuC4q5w4 za`iimE9Rn}#a°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

^LL+(H^Ofc|^iw4SY=)P*8IG}C9Kv@gD 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

kfdJnFC*`06gDbh>d9tnO>O%DOe}Fy-sz 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%0Da9%G)t6a9-0CKV> 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

X^hRp=m2yQLE@G9w6d|~J>$DudZ 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®bE*6)>cz>lBoZymm?2+(95`C*l^xh!hD5k8LO;3 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θ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

gQog8c+9~__dcV5 zC`9(gF(0K`eQdnPA;(=X`u*eBaZT)T@yU2hBxmYnh#liuAnzoogWyi>mM-h$xn5R< z55}`lYyRB=6G!fA8|9$`g78rsP25B=ej+;=I`7MJ0!NVap(i@8$V`_iH-IiuCn2HZ z1hHij3$^nIS8KU`q_{JQ`2|mjpy?1tZQ#%1ez-h_<7BATK{}_Cs+P1tua!BUuahC_ zOlD2$%xsEYt}JOebxAL(6a16hFm-gyCT$CQQTLY_-kqZE*MWs+1@VhXCw~en*7R*B#_QNi z<(EI)M0N&N+iX1>;I^vve=O0Wc7}MZXa2ROhpHJAppck)@SZV);~(#*9{G;aogo<_ zCWHC9HifX-w?^-SW~$>4g)W1QRc1BI5DzlgUc1i0YMWk96$1F=T z;#X0BD%R_{wKBx;sfZI+Ixb#Kh2Q#f&5Xht(-^Z>dW?1#O)^;nWoC^GF(H!`DObL8 z7wxiGq%t)y179&=kB&&wHk(aXR>SNd5hcp9nIoSZSYB)l z6!}d@wg~|+_US0lb698OU#_lV@pN`y@$fg2_rWwxy6Opu* z`(oLH6Y#R4dKsZ!4y&MEMyr=e3{CLEOqRy4*{Y0U)jN2k1*6_9Rx^lOfe}=rHt7lS zT5UuBoX6l1E!_AJ4!E5Ge_?=fxvVgI7Mp3UDI6#&eadzz8^bfikxyBC_(bpWl^lg@ zqwj?Wk+AOn1QRkY`qADQqUCIsuIz(RB6SP#bT)I0oaI$s#Z+9EQ}G5WA|Dx*bn$}0 z=CGSet|ve)9JElFaNHbF#(EejjxaM&I*XmTtV5p$AE~1>VmCc!Z+JHaqm=ffFDjep zPDH;)blQ@-n&suNKTCAllG>Q*GOV)`bm6%sxufFNw-QctC)dw(cT-Jp9p=~A97AmO zQCloP=2xEeJ7TPZ-aP}a<~3f7!UZ<88K@-YXmtXR2V!V!7~bKT?1$a)i4#}zL@(+0 zh>lk$ZdU0?R<(oZoyT~{0pd90sdaE3dKq`95r(xOW2cMBq&afJF4q-d+dLK(?2AX8 zODaiPjrW;Y!B7kpi1i1Gfk)LK{vwafs<%A?>bscLuB1yWB_mzbr6h_t*l75Y(^3R8 zG~Db)6H5qQgoTME7-Gbco6h>t>bkOIJ54MuVBuLNmkjY_F1xFFT}ND;$9{J`?_6#j zkvA}oIcJE|`7Bsjr-gTs&+04wg&rboK3lF7U@V@S&$c^GU}{dWRFQX`3-do`6|8OU zkA>lX^#y#2FNL^D{}YAq{1X3}5PiR7%`~ePi?6?A6O?&Qa6TqA@)va%u%513Crq>M zxHql7y;7deEr!JM1uU3*O)?ph+*8gP3B&kp0rTdsCYED#Cq|WpV6-qZq(=}yjOGhj zjcQ+ku^TTh#fIdD;n4^zMH3dXcGk*m2b?Jon5OS1h)aTfu1QP~BNxGs>0ia7nkBJf z^&*zu=iWF|zNE@vfF5b_P0e(fZ4uGQ;y0M-vI0L4oh*KKd3pipBK<4YrD~WP48v90 zOkMj7@zYn#uj)Hj(8wvoi8#>y`HE$GY=HrhvB(82!cah$Saj0t(6*UeYfH13;aWSn zH}l`Zuhx)paIngp9q?Pu>DalLRkzk`^%vetun;Y~v2ZCH?&?{& zoX;zRhK`jpMAlOHyc%0IkF_uhx$s;yJh^VU@W4nLR6-bTDFTF1?ipgqx2f~Qsbwt0 z&blIv?k9%%twiZEcEYA;Fl_1Ma+u*qxuqiX_at}WP{90^(G@a8-2yg9b9s(fSb(75 zj5(#^Sx@dRDy+Z?6N#(k>k*3SwSv{v@FgO51#6`&&nXp=8$c~t!5S+aarNXkC~WZ! zu3pS86~7Vhi*Hzzrv6fK`WvK30X6#?WP(;Az)(-gDBQF$)yCRpR2#hU|NBj;i5llN zV%;i)0$r@sg0E>-XjsMGXfki5sP^HcI=P;G;pE;Rqsxo>!OX%(vaAeN#5$_78V@w3 zqNg|wcl&^~PGvPRvjT~AnpnmN;-P+~RMO_QfR!mjh?mScNncukAw!7W&2*VfCedlS zo@Az1r#yxcos74IneIdME<`8e9cZS@&}Bo=>2+l(9dbmEK|b{aU&ma+j@ZIzUm#tX z^U1e*nt*9`lDoIH#JVb3n^cx4TgC>8!gY+-8RQI0HiiG342g7!S8A_T}Ot6 z4JrKRCY;u@iXqqE=;Z_`_j4r}4-^CJD#*rv1gp&X7=ERV)2(nX(QiF_tYq_wqVon; zqP!?{Tet}xR>DTswb$*x^%g-8IWb-aNyY=4;RXi{J2f_ruL$57i6399Sr=gWQlFbJ z#1@)O9|ge^2W7AH;`K(Bp}fI>nY0PczAzScpqr=*7-0xC>k*SNLxQrwa%PTUkfV=X1moBK-Q7UYsU^+Z^Gt4TL@* zwAlv2vK*05gqzRxID-d5V2-fc4#F@H8f^z*{cJIl2#@~Mi|s^+m@VEBVFC!Xcfh+& znk6RhVDnt2{He!^N(TritRfrcOAKkx@30T({!A}AeaDU~xli>%`#syBDXl9Geb0Wi zt65hKhHaI>Fn=*;W4ygxt;cHZ3q!=Eoh&u;f_#A?cJ5HD2GaM(y&pV-uF~;-BUd^V z1;jlBBZ5I%cczhGMU7uuw4Z!Hg{&AXz~L~4o?2N)U^NX{|5~k zOz()5la3a|Qum*&|ImxQKd_9tFDqbhVE-wlsNoEEh=Sp=@u5sj!$mTkh*>KLUyWNi z%vEIWViiNjLWFi_X@;p7W3&yq`zZ~U0ic&TC*#+=Ac(EIa1W)WO+}Hvn>}~82G8PC z1+lq^$>Mp72YRt&4{M~HEYXWgdst`X(sU0Iw3ihqtKR6vk9*l3yD|6ma-x41P?*1u z4YkG>u|34!`&p=e(OtdOZaO0!NBxMwjRM8O&KiM)H?kz((~EWo*fve-EAjUMR=eW4 zJ9?{<4dQ9VWSw#f!(`1t7SHEHiMpLpim^5Qko1q8VkE+*BMn!npsv zz)Dsn9x@0LbsxdR-Q>|yXHkI-Y0Z)Pce~^XV&qZwR;h?_H2fIr8hN_7d;t&RnjCVx z5ArBxmq` zUpF%vT4zg^bhb0W67x^6A(|7u;?)Ukm4CjbcE%ug(b6&5wU;sPy4Pupqd=;|j9@*z zhUv`9(z1s>cr+P_R9=OLHD!EWZ8gIN2+;kWnJr|GjS6(5vz4jW^y2H2tX>_T5}2<7 zR+)1kRFrH(a~YG<&dE?_0RJ|Kc=sUEygkXLco;Cfz#n9cGdCxMYR?Q zRMoy*)IG~yX~aJT#8zwU&Q%ekoEYVapc5mq*(SdJF0kG(2LXy%-7||Myg3I zLJ@XLKjl~$>}K%=7VNUvk|$$$pAhdV@lqRDq?0pnd*ZqO0$!+PI_Wms5-*8(uhA5; z<0wDrm7J;#p7@0Yx?Hy8Ne^Tm@lbkymjjkO>E-kyUgcj|ooe&I+f6j`^xZ%%jQy2W z)hO-G>P7M;7F{Wz8piH(Ycc;Kix*BulWhv0U19~+l|voXbt=f>e%HP$%s#XBj}{$M zC|_McuV2YNnuh9FY(g=^_e0~GDXg>PnlP#AhKFPtb1}8FFBWJ7F5`C|xfy~%3Y zEbLHPCbI8iz&*K%^+$I^FKXRlS<0lw9%B71MA;I5(TnQ0S(|EsM@(x2mCGA~<8HHX z&6)P%o7=3H&4l())c+3d!@AsI&1_C5nDj>6Wn4_V!4#wNe%u

-_0=VrQ0GMeag>f+k(pj`7~6f;f=;60dlO( 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

0XA(`79kQo6nm;_v3%Lj(0OVgf7C;< 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

Fno4W^ra_B9^3Qt>O#nBtv>Ae9w>@7_eZnlE$ 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 z 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

;9;x*aIVYmClrWG!J`p`Qo%P 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

KnlLV(XJ=z^aPjnfJ|r8mwa~!V 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 z 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℘Y*fp5MO0;_Z#m^Wewx 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ÿZNy~yQ_97ebP|?HlWNC{S@o{u^UfJGZI|Gm$ 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%0Dg@H%X>QZL$Z>noBtlQ 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

<+$qoyB~3U2_Okf^UDvBKW0CS(di) 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%0A3vD-%=WpyOA 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

47GX?R{6OyV@( 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�Dj?U0(n>@w3R$0{G`1KKS`G#)&H$1NU@|Qp%=(w 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

!ci?c`n(eyHQ?IL!a0>XLqB!{^n0^w5?!Ew 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

teW}s!5vjUQEJ?z-+erS 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⁣dclY>VgP`E3aHwTv}Q* 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 delta 5335447 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

W{RF|$}j&lsItn5v(%gzNm06wUTc=Hit7EUe5g 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⑍?9J2c!WvacG7*w!g>01j{4944s`$6et35Rqz6 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%0AZy||C9!4+oOUURc~sp7bB&Vt*p?Ve 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¬ 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 z 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

>-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

q5cmVJl62K(@=2B_e7ul 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%0Aqe(cI3G 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 z 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%0DPhOX}QH3lBbqX2yi^6d`w~AWq6_(G;3`f{M^S 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μn# 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 z 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%0D-zF zs}?U?yz_W-k#2t;u*Lh2r}Muy@LL*;T0Cy?X^UrD$Ntlf7u!HR{@qVN7A?MMaeH*& zO1R{IjLwp?-hcvsf(PW+ezROZCjWbQLax`($RC93qnrXE0xNRupd^1SuJ1g-9PuA9 z0EhfST;CVpo&QgKi;T>t1|Nfu$WM4HDnWkF*UC0a$mj5x;nnfs-Fvn=j17T zL9X{%lIwj|~reRA@j;`-IjW&d67Z0Vrf1)A;W!L28mBfd;W+~RJF`{Z{&2fzP2qQDX7 zNJ24r4?ZP79G;Qi2)-bH8GIE{;7Mo79B;@!f(G`J%}RV6-Xs4ryicz8AHuii|G%Qa zsHMS#+&Wh(G$q##vKC*M9$DI;Fauk+o??#phxqnem)u1{J#yVO9=Y^et-s*`1J&u5 zTyK<+Uv{2UVn%-J_lW1@w}G!}uh+kBzhe+6sljdGou`_W=))cI+rj(fw}<^2b$jG0D>lfrzqO$)B3Y?Dy8}bjs?WdWQxDehW{{-A4{~3Jv zG&=uZiol2(d<)xhLawDw$*=bBGWT=xK764rNU;exJg8e<>YjO+s={#d^ z0QLNr$f&m;s60Ri1M>15>0m^j!YAZ0rZOSF&0F#Qe@=k{nHJ<3+yP2gsKKddFeld^!@j_XVE{7b0BbM`Ay&42k73Ajd}`uTsY z1bOmJxjtk^B@*%!o{?v@*XwUd0S66M z_1}>-VFf>tpXCaufpwvHOdkKIcuH>nSv)5%t|q?Nx$Hj|fnpbEQYx+?4Xm*_vfyS< zY~l{Njq5$~!j}64*X(E*UVhhhMym;*>KfKEh#PhxJmKz zhup*B>XE+O68{Hi4JVfoBdb(SQ_MefjWUxFP0H3$=?Pq z$Y1bDnSxD=+s`ux_SuVZ{&y&#H|n>z-{LWO`ZO6>%8oUcKabA;;Yb=3)WEueOo8=$ za|Bws4!I7%X>ng&o`2PwP}nx12I~4(|CT37LSu6MT%d$pf3R@Y;yHPw4OSGmJHE^= z$Zv?ha=9k|%C}^#l;jt~H{@r3saY$L)q8_|c@av!gj8+N=}c4=+-SCRYl_r0F~@X8Vx?guJ&4iO)d+jufg z+3}(^C)el1io9N1&HCF=Kug_?&8f-$gb|R3e~$+gxsONnm|P!p)0ocxnrTW6KJ|T> z%Z&V+@D;f}^Ed2c8G!Xd9T@iCUoMp=S9cqzH=kvxyDdIw@u0=W>=8OnH~^ouc;4cx z7Vo@BM=S%=N=G&YK37PoyW|(c9r8=yJ@Rk?%aa$!&}{H9fNO&&o4-W(KVC^3p+0o?>bW@=~Yl<>rX>=;n|Y&5KjD z{(2Pn5?1e!Jo%XCw~R5Uyu*sOY#rER}(t<+!=v_8r%=QCO;NllD`#+ZpaVC^_^E>%H;W1{bf=# z=xU&O{#8GKfCdiv2XTFmd2P5)d!b9>e;XVmDzM77# zi~<=>y-RZaDtJYH`OC@YdzIuT|4A09^-6Ph=*RGM8?WlG+wWX7=uv}D!29HSBcEJf z6-VTH{dC{!`L}N+`*OY?sNBaRb49Kvq7AwI7kNN+UuBLsfIH-q>QA*d>#u)+K)wD( z7v%a{P>_Etvd(BaDk-2}mUm7wE1~YRxKCc( zPewc>Kj(7NZ#1I7)&5bo)08}asoZEzZo_kOYa-XL$Q}4be0Tm|zFZn~|IHk+hYtGW zC45L8qJuGciu=cgSMy)$h>d_{{qROoiH!X2Hx@6*o!7|#*5vMM#7pw*wUsyf|JCM* z%Q{f~bIC2-$R{t*@sPa4^#S=3_m3-Y*1tXhvoodR2{j0>B#R{>e5-Lm=A)nhHelIr)p=Ir*vZ1^JoqC3$+KNJh4zz`1Bpkbe-qX2+Va5_2jK!Y?j$ z$**^`eC6auErCIc2Q5Bs@ubCP@a_3uGs>yK%Q{k_HM#q}Q<^C%$&>Dr8{d#y*ATZ) zH!2ia*GC7A8L&=(yX2anN8bP0hnkKDcC^ zz=B){u&TXY|GNErjG&+fI)XL1cCaDW0XSzErM9klWtmEM&zt?HH}duZbuBehpL~Qw zhvb@QK(6->$*V+V|4%5Oi*8DuVgz&Yhrt)*+VP59`&*wu=l>WZE2)8wY(uUcbY5eY zdOHQ=m%F~~`+>TQ-?H9;5ezlZtYvGv3r6HRf-(6N1Bl6W02A^^M=+&;j$lFVIuR^@L|%)B?U7)cm6*Ife|&(?G(58 zw8aSjX?ctIkL?*>@UT>pPH4kUn1TicW@t@JgmK5e_aZ=XyA}% z=-4Aqas7Zi#PvRThUg{|ZjMvz^QSiw}}Tk?#V{ z{!?GIc-i8eH<(kS_i_HlBk8#RHvz0t@<-lYeAMD`i%(lTizsj*I#`f@yLzvt{#TGc z@&=O7hWz7r6}8`JRzjzs2j8CmKYMj~fcVrvUz~>Q=gDdh$nB~4nEan{|B305^;QI? zX28-6XXN&!a?a1l`}qGkx!!+4{>7%>YW-~}pbrZBO=jt?W=n+}a_zt+*8zC!7{H+R zdj0G6(-HX8KsyM?WdxQrAs-^qDY@Qfw&%_M(@f`kfqJnGk!en@i7v>sgB7_ZYMo_P z^qn@&|275mMh>|q>XLg%v`?;ydgOY4|13KHYo=prP@<$0a=p=%Toavgd*qs^ORgPwKz2HPI<~ibPX#O>{=C_n$Xj)nB)tW?E2#uc4$Rx!%Zni&<(-)Fz)J(eA$2 z^RJmY`+>c=cgZ!;0lB_~6SVl4y#5NQS$_!y!b{~DJ|i!FDV~upe<406cW?5PdJS7S zx&G$#>MeBs*H5u2seyXut!Am!ofh}WGbB3PI`*I5DBK2`#J7KfVbbC$d4>_s$@Ak- z3GysLgB1l*G$_dRMr(3Sq$DqK{|&iwxFl5l{HW^vU2-4yamiy0 ztS`Ph|7!!E8U$!CB-a}SjpsF@muXsDAVkBZ$dERANGI<30&_hU=%~ z`O#HH>-CpXpr`}YzZrRaC-IED#PxG>7uVHyI?@B*9YV&=6*z;9~a5ULJDXiV{+XE zF?p(Mf;@mHRC#dbR#K@7S)!=Eiy>r^Wj%?z2Bb z*4BtTeCN}ee!|-8^{=Hq_I9T=feAHGPsxvSr4sWNUy`S9#5UgZX8*+>lR&u_s541U z72lBir-@tdG%Kg?ly=F#_jhtAb;+yiW&aN-P@FCu1mv+Jr5lm|>h`BKm5a%*cL(t) z`F-HoJ0o)hTIvNgP%m11)8h8o2flw#UB+Misx{``(?Bzxoex_)Z1G8pr{s}#Jg2}I zC0djFUy-TlyvrP!H5a$Z9ZR;iM{a$oxjwQ66tKT2H}c8#MkDg=+>_tXJFThVlw6-5 zS>sjxb^B>x(bAwGzvAJt{Wj$GUr~v7n-$8ic)R;v&;Rld(!kvhRIU#SpFF-=oprn{mSh`fDs27Nk+OPcExsbpuPjrrVLwvbI>)TUIyzJqQI`X7 zx5Wo79*}=}fPs;_M@d3aMu7nPdr7W~t0ebsixHFm!#$;A`&@Ix>OJw@`CkKGOM_vH zhb=y7@zn5Y{ zeoWpuR_>FKU+cc&v%m330{Pzr#8)j|ws_~?%}Qv;4!QGjsZc+nK=26(c;xG{K5Oy3#aFf0>tDB@W?Hs1=$vnqZu^bP9(i*0u-QEx zdC?Ug?0K{Qme-YlzZa$3lI3Y_>Qd9bWnylnAK zW>!e=Pj9*!Qs5a+lCRlD`z1`-fvdIg}da-C&~4G<5m52`{fUjz>pd|?x|9VkX*moosjDr z8gp|0wQ~Q}zSr}w9dGsnm6vBogYE~+k(Cp1haKCsPwqr=y+>}pAe7ht0R?p5`{dVs zfUMq_+(kkuxd+e5bx{`|p!0wH3dz*^pgH2;RTwdO`cUy6`IDX|Q|6KD0K% zjgoCZ_Fw)w@r-==4)G4-c=OxI`lqR<@R7`1IRupc#C81G{5*XcMpCjg1>;o1hTh z&<#|3uYbp@>pKtORSVRFcTaR5-+_ybb@G()0b-M?uGC1W(U(Yc_`eiai_7 zj`#wuXUuis#s1gvQz3Z2*P=jPJK_zv9#&iM_8r_(b`QKfe|lQ&9TbZ5r?<-yT*qt% zZ%1x|B|JOD`4&Dr<%#b6*Dmz$SP!Kk{ISn;d!+&2{Dr;W!?jo1@W|I>K~u1(s9PyfSx{0N@t zT+UDk?SdsdvY=bIPEGJZ{|0{h`t}9R%lG{6e_VbcXdUtH5$_-I;Srydp7&qJPf4>Q z7c7tX2Cm~;`H`s=(l4-2`E`);$e;X1Az`1pD5<74_+&inA;i=XJ;|5Fsg zhd!w|{=opQx8oVSeWsgW36JjO#@WK#4{=`0@cbX9ZlGr7w{G=PcR>d}ewN)CylNAV z;0>F2wsSjwt9!Z$mb*gPfS_%Gw(!L>-NdyI`#~E|aN{)L!{@q>kKl3gd{^kOaIW1M zJhM9(!KdfAkDtL~n|KM|m?v8lGAq*L#_$u&r|@f-FFnuKzi}hCW-G6dKYqX7-SHM4e$qD0NBs_6`4;v{ z2iLzZXv5=w%f~NvaSPXG4Ca0( z^ghGK|Hcv}s-Td)#9a`=7q4?(hyU}7&nY8E@DpC^zLgWh z?e!!7`F|AtU(LOZ4&iz{pB(Y*h%b-$ru4l3I)0j<@=3o%^6-c^k9hlt_YS>Se@&1c z7IN1o45K4Hh3oT(IlTQow`41Lv6SWhTce=&g4#d%ooL%8YQn>F+yotXJa^uQ>ji4` zPk8pl=|~j`#wu&aIDl@G0Gxoj+Yr+ZEjTlQ)id>xg&ZTADt*k$l6oXo!N2 z*$7_z&ZgqO=@Fm9pYU*d20Y@)7KP8+1=UZhMXnR_`Vo(gcn7YR-huP|^MCXm*NF)( z2+Zg3&86<+*YMPQ17F)uR8{`@@W%4>S0VHYdv6}`9=u^eWB9_n53hIfr78B`5QX6n ztP}9+Uq8ECiz!?mKZkGr%6C| zE$o7DUnuW%c$w=&9UhxE;Hh~Nt|y-k{PP|A`JWgC{Y=;Zeub0WaT>$#W#wFO^Y?aAeMsrl~tzk4lL7~q12`4Fxj$DP16 zaR&dK1zq}{1h+oT-Py)31k-cRDU)vDmzW2i@jLWW^AO&+sk^Z{d~xH#^ZnOAVR#dF zK@*OJh+YXE^I#VH{sLUKiQrC2nDsM1=sJ0?!tq6 zSWDrJ8$GiO9>ddLb>9Chp8rD|D8&VvySoVnaQ!2d89aS}`}ie1xS#tSQd_yZ|NMKv zC%FrPe|?wN>h67=*Wkeo-5oUHjmJNwyuJgEAMU&lPpS`g6O2#@U-|TMpcy=}JImnu z_&Gea|6jnv`<3%1!4ieo6@nE!Fki!?j=QrB-9Em0vER|@UH`niu}0~6|Fx?#yR+tz z3nKW|CTzj&&Vn|)Yk@k4Uar3tx`%~4W8(~WXFYgiA0N|guMFUNzaPS*{Nu~{Cn)H_ zVG7qkGq{3e@P-AQ!&CFc#d!YT{GQv4OI#2=({*A6Z`(k@zxivtvZV~+o0Hu*(a!Ds zEo>9Dc7<|}1b<|&bX|D(AQ!X`Uzn%x;RD^r58&;j?FvH_^p%SV{5QJpr8k40WxhP( z8+iX5_i1@jxx{as3L*UJC%X%pN4y7by!{zv3uAcnaO;Hg{quj-UZEzqVD%7p!4&?6 zKXifSM|=g>?-kp6p0B?O)urDF{R)*j{N;~!OAx_Nx`}~yjJhA1e| z1Rg)o?cOQxSdVBfGgk%o_^E)Hk>s)w*TM2HGc4Uw=}!w|3})ybt`C3eB8VV z*FY_}f_C6d3)=NP|M$O^u;&*7P0)uc=oo&-*SnTZ;Tk7{yP*00TcFUhq)WJhuHc$r z16R=67yMK3HVaxWyx9M0wFYY90=2XSuUODFTtPc6wFXH)sWJx1jpq94anxF$$ z&=h{c8(c?+a(Dm1ZnuwBaIb%Xl1|}M3p#@&OpySf>{_FU)E$IXosHIc5Cdl9lx`sdYjc)C? zhhD6|2C977Z?%%v;42Fn!WFa**Z56%5wzTYT@)^{q%m9rrEmou!nYQ51Xs}Um+}0s z38uI}EuF*l$hA7+)vx#+)kA4*=XU-yP-9nc=TF``;@uIeB^xp{I5jQBNxn%`09vnk9hUp4?B^szb3AGg}p~d zymQ3kBR;r1FZSQ~@(Q`nj`-q;ua9`})x$g9-&ig8a{ucUP@QPtf~!v4D_0AyPg1+^ z_Qg*wk53;Sf7N-qcX$4}|LzKdeW4tn`f2AwxV}=F!Mlm}g~qL&M|AtFwhJGx?9SkUjWd9&)8phwVRpn9@XgoU#7nro^0|WRE1zrg-SdC- z>u#V8E?C(F)vx=l3tH~u8}OkNtKkqz+PwnFeaE&vBCxHz#LE$I1W;3{2I)`h?mhi}y zYz4O^OM*2DnqUjxt=WJ0OZMo$bDOIH*EkVeLEEM0{nzp9SkewI(B|sGH9-tl&;k6L zS9D(=93OhI{(3W*9~N@|iQU-}e(GD@9k1cKvn@Qf8w=Kc=ZYIE_g@7CO;CgPY~l$1 zIrBDL<8b7`I7tr$1&QGsy%52xdLe@E zUWnjT`>CeTxV|9~d{gJ& zZT6sj7xyk#$qU7QdS%qZWEHN5$r?PiaYA@x9_`(oKRsHt_JuOQ?1}CrvkSlUe7E)k zxE`&B@W{TmG@?iL{69tEAvQq<|3~u$Tme_`h3&01JhuPeBq(Tt;J^JP*xJN3`08$M z$r|wSgPphG)tB10<;?fb|EIVMhPYs(*1>fwr$>B##8U)Xu|fBa6o;1At# zs>Ah%MIyNVu1E)d?UxrnNty4z7=_GQI)F!KxDHL=p&h>|d}Tpb@XS6w_*Q;n#s1eZ zYujh9m7;Lq@fY14SK;#u+$pHRzhEB1gB!SC(NaI~^8Bssg2q9i2=G($COox35&RnO zae-R!+nBfE_j->#|94P0*)Hh9pJ?8L>(6qG;E`?W8GLM;digCp{|A5I)_8>rqEnr3 z;qe2WTr?`EecNBMjlJ}S@RvT$EoD>gUjOnD9_=P*t56P`e_n8kd%y3%_3<%0vm5Bc zHBJgolw^QH^>i0#2;V%``3RnxkKt4E34Gx^3Fas?PIh;^h6m;wxITUhpW6Qi8-HoW z7N}Bs-hUmxl@+SEU}#>0YoHLG*~i!6`dP8)(2MoI<;~o?T<5TmyZ%;74F5^bZKA;u zpTYH2?+jkNgqQnoc{zn*|80(V!KpzLcm5pD6-`hNiP&m&DZMX)C;lcmd*N)%{l)^R6(E0xPUx{Y8 zU}}Npa1FGCt8;63&4O+`&(~i`w_YI#G(qLNeybI<0axcDxW?(i8%3aE|MgH%pct-! zQn&(5;Me_#+jKLy##!cG?ti@kwyZ@fT%bT}xCYw76{z|>zjG(szXhxB-JL%bqJ5z} zUV35a!GG88tPfY90bF}x1n>S&;&$&C1>Nxkt_fyv-SHZ(Pi%tk`<*z?ZlIc=pb0{_ z?w~=pC2PWU0}))~x6OCY|GI-dF8Jk-x=l2IYoHNaK_~E`1)chy?2g~eFYJ!r9Il`% zxc18Sh*y8$FToef8_V}!h=Mj_3;qiqbDikG)rlTlo#?|e>qJ_3vHx}av}OZbpb18B zbs~d5-hwXR8fSIj<@r<6%|W3!f8n>>>Da;*G`P%fsV1nx6|@Qemyg-=e+vZ-)PXB# z4?eM$#&8Ag!!`ckGCcn)=@b|I&P8tRGq?s?z!h`_Us}+$+`azo--I?Ql&^pLH=$tb zw^~8#@Yh+;CR{;V@I*;FC~Pcg7p|7};F_QhSI{y1gnuYIngml6G*AXt&;`6=n{)|R z&=p+cZ%WVmuj8krl^^=8*5i2-zPY>mhXfsX@LBf^*oBAZJMSHOvHq*ixI%hZ$o&={ zcbjeq*By-E>d+M4v<}VSMTg4$m!Y5u7I1ZF4cF827XE#^f!dG!j-G8^{}G=5HE|Oc zXu=k}ZFkm&YwbI5jo;h3oj={#a942W??;w&4A($YxRxM;_blifK1l4jeSv}|Siu#v z@?*cHkD0r@QiE%pI$S}MCJLz~jo@l&3$6(|a0MN}+h2E|-VdGcpa1o?JHZ9=?1(Sn zdJfne@ybsQJD0D&CJ4R4-kV3feZ>3l;1h0X2Jo_T#r_+iptYI6N47LmxRz!H*V4@4 zTAEGn<^I03Mc}@4p5L54VAu@P-W(!B4l3Z^55r-iE)(yi<6w|8@M{YK1N?n3?zB zA2g5Qw}{_| zcmF}~YgVYJP`>^J!ClR(@RQ7I@JE}6@MoCU;mNbD&_H2e-h{u>Jc7U0yaj)=c^m!# z=Sk2(;bOa>3;%|B5B?ML7=BIrl4~D+J@d5my#G3WH@3n67u?Z&2)~p02!0RqG5jIs zlS41o|1>L14-2`UZa#xwV4F09Kg<4u7`!0v_crXyyJ}qA;)vR`A!Fui@vLZ{Tfv z#oWU6h*k~Gcl%#Uph7)3zuf=y=!kcYcznbMJ9qQ%zS%t972Nq#pxF^$9P#xL4}JkR zrl0?>v0y*{-#Fr}Bi=pY{Ue?Xj}#_HJUimcBfdG}l`E8;*gyZP)uAiwj-|YL#M?)_ zcf?cA^YzyRBd@Uc=@FkF@zoLEUY-~GuX;sn3S0a75s!{|=ZMEge2{y&|8>lM@G1AU zIK>6}F4zp7J><{IW0JwEk@FQ?Uk%^x-JQROeA-Q1`9;4IYYS9^7s-qN>hQUJ;?aPQ z?Bkp8^`{ayaSMf?+QePB{%Lmqh!2nW1b*5-yLlH03TpKdK7F#a6uz(}*uwu^9sMQ0 zqb-}bX1;s=SHe0jSgED(nN8S)Yl0U1bep*AdlIbd4*Gr}*xbc^c`b#jbwhaPSMA{w z{+A2a>I{C}()0bdK;bX!f)!jrHt_1V?W^Q)btt%!zXTe;T6nSlb^Kmo6E|_erRFWT z2I{~Svhm%87r025R8~osJGXvY=hKg7)AVzb|+99|TG|R-x#B{$KbR*U~9m z17&apUBEjQbO}$CbcKQ@*uWLER`EOcd<$BKYn&$Bg64n!7lqi8w&4oefop;uTtSEM z|FWRt()0f7_-UXiE>KG|_`rhB;R?EdYy8!r7wfO2l@t7yKJc?{?Q3uiREH~Q6TYyZ z5xfXm?!OianxF$$&=h{Y1s%dQ&KRzs(-ZLgKenVZT%eX_a80m)E9e$}{eN{Gtz1Q& zw)3ZfYP&*t`T`}b!)F$>LD#z?T;sRkuSo2*Jx1YKmNbQHpdnmA$MCfUoxs)6WQu|& z$lz+}8vZp4x`k_;$}g+cen)H0_s{>q#=VV(xIjtka81yJD`*$qy4bCK?0LTaZ?{6~ z6@uN`58*WnI)W?c7_RZB@QaFhi~YAm;U@p)lCI$zXbaccSFY-}x?w@9a0RX9UhaRr z0&0RfE+~`cK|63g&&Tk$*bSs`jX&JGJAb-^@xD;*mcHG=1g<-n!Zkq#*A1-U*Sy4@ z|FO4^0@FR|SV*FY&;L5J|JHm~{a`Cm!LxIhz3 z;R-s3H~z$ZxqWrSx4!3p|Hm$Ld z09Plb@Hbn~46bn&g%|r@$4^ODxL{&ywuUR{2CfN$Yxo^i(At5Q=TEI}92AQ4CvP3` z?hzlrum3r>WFvSU)XqN&>ckA5Stl~MIx&Z<6HB-{5mfQ~pIXvt)o+~!3gHUcfG;g* z6Rx0<+};2FO{lFx`T7?GO4^72hXozL@BevgHC#a_@ML32rzj}t46X_0@JHFi8~FRo zgKPR7wQ-W5ih`1c@XDp``JfJ0&<0#VBe;UbrRV+E@e8i)zThy#1;HuqOD`k3ef${S zvHzdI7bm-MriWgv|HcZl!$R&;^9-K;&ccaM1gSMdC=Uottw1@Z}8K{I%qx(+Sj`kK;e=XU<|HQ?>8;Le{Ws9x*xJ5)d7 z5&YsWxntRZKP8#EfBP{&Veu+=2NSsdEyo-lywm-=z6Csdxf^Fqw?AT)Y)}YZ?Jn5D z^-nN@Yx|whKf$QLLmQ_G-`I`SobR9i^<#DoTp(}3pY~fZy|0_WM5I&-_#O8PcrqV*l&-=}l;X3*>9KUKxX$*V5pj|L*og z4X!|q124~?3ax`easJ-^E&J#9N4yW8zRh)L2oHbkd%4gZ3*x(mOjO&r4&FqOOe&!6>dR}WMu zU;py&4cq?@;hJC!e~e8$gX{N(FW`v^YZUaS7J?i2E!96tZNP(#>s*_Dsq+{PtJ)TeDkxejzeW&IhM#Q{kKo_Tz1)8j6g1EbuAp=H z%7QNF7IX>M`0Eq#{I8_d8~RId(l_0jg>VhjfGcPOuYc#=<+*C@+|Hj`+TIo1`O^el zxPlJg@3o*KxW<{l7m2lKhQiibn!y!x4%Y-rxPk`1>UT8!Z`aYJih>3T;c96EUbU7s z;R+hTHGbRq{`p@?`?%nRmUIBuKqI(?1}*kqh(c^h>u?2az%@YxSI{2(q5tF7zMp%!|Md!}fd;rhEgiu-7IX|(&=dTtS=g4_VOGftTk`19c7x#radx9=!Hl_cj{C6|@i6_yc$z)Sdq+3b)v} zmS%7bw16w<3LaR{HC#bAH%>0UrNK>nS4->gmsrpyTtQoK1?|Y){RctIl6F-nU;p-R zPCd9L=))Cs4F8@5ox&3hl%b%c3wXnVF5znF3a;@ta0{9QwVV2_KJ`+!_I0=hYQhz? z1s___He5kFrRV+E@zVr7T%eW?;UBS}W4Okd!WA?-^kV(HmUMnt$X!Vna80m+D`@3r zen)Th9oNwsycnn4e{~d;vv(sw_4-W;0juYXNe_kprE8pxF%@96*PvQ_FcF3DO}?u zLll&B3}0H%30y&^a7~cG6?E-<|NMWECEelz4OF>>-)aS|!8aB(gez#>^L+g^LDMS) zy9bjVTtD@a!teS$*Xki$U9eyBDs3hHwQP!z)fzXs2Py7M2QaD%ODX&bJAx^M-J;ZqCRhbw4$YdrsJf*~$YODFK~n)XF$cxpa_ zH_S7+yZ`)Iuj&Sxt5ClF4%A z_ERr0eDgi`)$jpa-}{-sSKlr_KL7onC^YQbY-{*5bb%_j_3xl@J?C|JTQ>#|Z2WHN zdH;3%Zu3L8>0(@<_kt9zO*e$EY}1YC_NCtOp%?3~38sgI-1TO&gul&#uHo9eTeyN& ze$DS({rm5B&;L~vbUbQsO;CsHbhP2u{gJ&g!Zl9(Yk2-w(i9hL^~wlW&>>tCjNuA8 z-?^Q?#F8#|1$X{5&>F6wTX>YWwEXYa{Z=bz1^)BI9uR6MC}{*=ThKOKLA!7Tjo}>& zn)Fdn(iE-)z$0u9uLD`*!UThJa{L1TD1ezE^j6qIxXKld#6?f5DDem`@qUc&Va%@sVnk$c5l z=U(oAy#luFJDowpZ{5d!>L#ed8#ZwWSHK2*U>$1i-JQS85=Q$%d5Sba8-9{a+=Ht_ zDLi|s>)Z%_&!5}R|70krb#r(-a;;my$M)v5hJVU}ZsEW2bJx*I@*94um9PdMTkAsj z#0IXzH9-@8KbyE`zI*=PeO8ML-eeaH;nxVxEthBv*9}bJGrNJA?@6FL$oxW}2^R2M z+QeJ<3(PCG^E;|>YH$}c-+y%!7M8RDSI{P06SUw88pFSBLDRyE{jcMvfrhw1Egi$x z7IXqv&?#KwX9r%MKP6os6pF>|{DNEKEnEXtZtu5RL2K~f2ku=lgy%us`LCm(37T*P z?ZQ87L1VbaN#P1Qygi=(YnF6`3)IpvToX*;3c7^f`UB51MynkZmdl z_j51zzg_{Abc_ocS9UF(!ZlC^SI`B#Z9$iNcjr$@SNlSF{xrb`uAsHw@mu{G3tES3 zoF;tKu=oEK3QbGehAU_Xt_gZ@1s%e#QgIy}Cn#v3DO@eh;5`dEhb!m;uJKpqyXSu; zt=!RX=~FFf4X%Oea0P9`Lkk-DzJLC2`Gr6ebl?g)fKPAiJ~f-r&ndsq7|h|_@<+Y% z{kKLTxQQF6^1FT~^o7YfJhNX^)Pgr`oE}_XfQ$<-_P>r_^=5A30WL`GC!dG#u1zq3 z?|xDmexr{2EO>R`<@wX+e(QrmasIOVxIn?3{7$UwH=kGF!~43A58(^@_&PlL{7c;V z@1oFcyMcP}ss&2n;VaW3Z!m!Cj1TzW6*MS2WMu<4P*~VNP58`WGZ^AWBbQe7T5AA|3F3?MF3fDi`9>cq~_7k{1e!6oze?5cQuHepJ z*8*km%zO?H%@=U}lkFuvu?toxeD1350ikkNe=YTe$tpZ}jN4o_c-vk{8}NtN_(_Dq zhpfB=>Uv>lIJ~ z&2WKQI)~3K=mM^wOSr~g@7{)H+M!PU|^ToWwe3R=0l-%cZSM}-&rU&rqz*S2$s3pCIS zuAp;x$AT{43c5V-^89In^+BPyRVA(7({J@lENBSVI1RXhM(}9+?sER1g@Tf{;hLZe zSI_}`Ye7eFjWfBYoqsKXlFo2J-CCN#6?6{Q1WUMr2KTa#y891;$6m*+eN}~WtL@)} zLb!r9;IRd5!WA@vCra8zK}q}YPg~FdT;q)33Oa!gT+saQf1#kHGq@(0!xeM`|DEf) zjt2MkH?PL2mY(;YYail*v9+`gSI`Dr6GU(Y?Hzit{%^3P{lh};8fXAlOGogT1s%f` zbOJBNFZbUJ1tnd!s(hXcegZuccR?sSZVL@y6!Slb8hPXfzG~f!_f`9Xa?kgQJ z{ONWB>CWx^>1}klE4cHgI~c>)b_Wx8HNh0FpiB6hE$G_w zeEl`h)+^-ie)^Q`zJ9A~7PJai&>CFh*WqQ*V*f=bX!mxG_yDdi-woj!Cxb8SE2691 z%l)rc!0Nf~k!ye~d!cl1|_XI)!V346dMSc;^PLquYc9`^=_tKfl##X${`8pdnmA>u?2a zn(v3*9N#T9-D!ggq)Zl|J58e3>QMk8VP=`O*yaE3s z^CtWy<`Mi==B@kV`TuXM(8dM&lWHBf{-jzL{(2jy2cMY7a(DmvuUfJ~Uxo7ZF9`G} z)l$0s4X6P;|C4Ivl|%T<#vj3xPgr4$g8ro11paUK@l*JJn$O_+i)tC%{-Rp`^ZzLP zzy?~tukb5w_b%ZT^A-H+=4*Ipz9~KLzmDJSt+2%fcQ+3n;Gcp=npfbDF|WcOZ(cj} zV*UG82oDRnC+2ndndS}nYt5VR3(O<<$8#_DUkimV*#&L*cg#ERt$7!I1^d!V4}PL~ z`~W=v|Ed-GxZq~yDg3w02k^U^58?MVAMM=EpZ=uUcvo=e?@@Na1pXNFDSTwFfHU~x z?c+0el2~Dm!pqGU@QF>Zgm<3oe%sXse#NIaul&Bhc~3P@nkeXDGJ@+@vUT8#kGe0% zb>aGbp*^^MUuf)n|NOtPf%>>0Gf&}PvpX2UzkXBqIx&HN(|qQ6zW(2`!pbY;zy12l z?kk*Yc=aFL9dF?2)9eeA5A<7ohK*l?f2Qza|J6~@9W~)Yd)ABKa|_afmlNdUci@*< zpg8w(|LYY{Egj^KvTE^&Ecoq+}*&EZhwk( z3%|^6pzM3GwDMrT)e2gJ zXL_A@FrNRFw2lijK@+Z^UHE@m&={_9Qn|bT{C7RtIUTA{zW(Ju1ELoYxPp%1nqUf7 z&^bIg>6UKoHz;g=)-NM$;V0Y2S03WG`cKSj@aLG<;V*Zd1Z@=b8_qj$J%GeVd~n3a zaQ)WYMd^9}b^PM@y7%uTF1SP8eKC0he`~{auJ%yB6MAk4;o}=Vwd`p9(2MmC?SUdX zEaZM$o1hJUnRyqkfHAyhd#Dc&^8YXQUy6bz7{cFW6K8NeGtTKJx;tLL^=!C&D4zfI zaJa$+fwgW8U)Th}!~7)(f5RENJj>zttM33Rln&KC+;7=lkb>C2imW zO%TBqvNWgAyMZnIWet1&ubh1Ot**hVKelhD!PV+ITsP2!>jt_B3OD;r*XkIq zfl|0yJ%raS=m@T$WAokfzb2UC0wrC-&$6IvxW?JS6|{1S*XbmPENRs*1WHtbBYw-R{Sp^wpfy}UxA544 z2B&(h-gUHc;N|(#1hs=gasHGvf`80{w&5D53s=w>KKQZy{7)YRwKRomf+1W%XYkwp zw(IB|u5p&9;`v`m*SKJ8E#1HsbPLx6l}GqXpr8%8z5WGXu%wX+9_jtENBC+ zaiY@m{_FTDX&V>Jtfd{ef_CAWAciaG=+KMxzgE+=baGh8T?5VF3Oa`eKXGqP3%b3# zF5$)a<^EfvprqB){FeTO1r6Z}+JGx)1g}}p)@gYDS4-QtKofM~3Oay)&4P~L8fUU| zJAX<#+ZEjTYgp0@uApNZcn3!~a!q zK7(IkcQ%J>;w4-+wuUe5#x@BGy0a}@6I34Kw_11BfZz2_ZV4i|#%Y`Hp8u7!iwiPK z+Jh@-4A%rHTtO$kC&AxZ(wSe_z5C7K3c7@cb_!N-1zp2k(0u=GQBczGv3{$sac9@k z23&U>!4HMHjoWG4FUBDG| z3D*Q`xPn&y!0+f+?rdNG4^hxS4Y-0v@QST{3$CDTxW@1PLE-ddqfEq5)1a)}T?zjzqf_WFNapFTS)?Z1}!$R&OOFE!i&>>tCjNuA8hyQCHwA_D7 z6g1EpuAp0Z?dR?RBzT%*Z8%^;rU-lBV6#icXMmshHIcMTtQ>_)H>SVxt%{H zO?QRj@CAV;7{V2F1}|D#{5OYdoF#ma*jlbpNG<6GuAp1ECaCoMB~Z`?T$?nBP|!ea zxLVqU$3Jsx--9b?4A=On^ZoO`l1^~J>uv34a1AtvE9es5vQ4`3JYRn$U3-Q7+Hc_s z8b01{wbs4?SI`Jv1}*kq8-=>Hv;$YrE?g7Da0MN}Z+v&RNhi6N`(LksCs<*I3pBwT zu7Q{E$ZlW-*A1-q?#`bk*zODEG147`f8@9NmKL-D*EkVed!h~R|2%QKw}XO`cHx>J zhAZd@u46WVYn)kvf|AbR9c$?VuAob}CRoE2wED-cqr2yS?cUG|+7lY60awrn9@sH! z!43{7w3O3tEM1 zoUrg>|EtwX+Q0=fTl*$lK_j>(Xu}n>f8gc$)7lRX3dQ-;KqI( zRDmmK6|M%t72I|2Tv=8svaZ2F|I)H2Z(HTdc|EIX%QTK8!UBI_$ zHCz*H;2JlG)oD9_RkeCoaOY2VP=#xP5WZ_Q{PA`J9r$+>`|P!c!micug#}IF3Oax* z=m@T$$s7g!toItOpYf_ZQLS?w8rshZR^jcA`#M1luAlu1o$sIj^|N1fToBtp4R~bU zgum!i_odtR5$}1PufHxxy~5r{M|^t3=SO@4f8KraO(ZdDbERyE`_2C+509VivJhPzVy}R?Lq?3K2oKO?Y;0n5epVV?e zH*k#;JlXH`;B_wX6Q6|@C^p#|;06|@I; zLG%6BM`3A6Q@C0>fNO#gTtTOBz22+}FZREVUwh_$0C|lI^b^aqKl59vFWrXlTi?$u zSp@&+?>TQDczOPG2i=20vHdl03~$=$=)={a6t3}y@VrCr{LfJMO}m3RTm!A)Z40!4 zE6^6MaVmd~=YOqPxg&Z z-80<-NDr_X}|B5Acbq3WQc;2j^T3)I-%RzPvM#%gDdFL`TqG|=X-+-%ZWh_1az`{~nIrSqH8OdT`y@5dMe>@uh^O%A zcigx2$MDq)+j~>;FVo zNc}=kz0mm>9-L)&0AIY=`5fLJIA6hoGH9{?p5@=!!deuJ@xwfdV|-u3qZK4-dRNf9X41p?**(&R^p}?wB>< zw=-|S?_l16-_5)S|Gfv<^M4@F$y3;Afi8;D2pCPf&QH6_)UKn6KfV zG~dF%W?o7Cz4blwn!N0P-s+!Pp{_#F|NOtJo@7e^KheAe|8?^Y{I2Fbc+#>$AB9uR z2k{?Sd2@*>M`f8@F^5OyK!nyC|1*b?C+V>rEnfj-NEPFRfPKZ+fuX6AidN zUueQt?{&vJf-mwHsB-^xP`HIn(1V|C-iIsT03O+Mzz|-u{~tXE&;OcWf(zbe6EEPu z{1DfP6TeyM-&nuT;|NO5Bs;;m*mP*=$-{YZf?OSk- z(}62!&+~l!$Cfnq3c+se`*2M#fGg-29=y{XzX`njLPW9urYPtO5i@vb17+}yy?rm? ze`g(9!*v7O+{^v1S3tF>@_Zc+cM4|Kp(Ml? zJzxuWkzx{72dZyuEBN3Azb4( z;K}t*afv!8Jk7iZ*Fb%^f)3zA3p#{b(ER&5{1;n2 z|4##jW#NB&^N4rhpE=caG=|^l5zf;?FVDXnzu{pa4>YmXjo@12FZ{l$3xSJDUH_XP;QApNf&T+Vg+AXC)RLvVgtWZVrvte<+oIwsKb9~L7VVLoaSzz1y|4xd}BeA zE(%K8gKL65{0y6T4F81r6s~bH=lkb>C0*cx$`#!M$P%ugE4U`uz!kLilEY5t>wnuv zxz^RaLJ(-6CR{;V@X&&`;R@P;m*W@vuZMz?rtsT8)_n(b0-xFq%;36#Ib1ie%)Q+I zdIfCS9jtJH?qChq1Y5XnAUyl9)j@FWuIqGT@9z9*plDwx&!3XE;cW}rfh%YiuJL2| z8K>#_9|iq$xeTtadavO6B6jeX{vGRI(N*A|vlp~5IZ|jI@%9n#!QcHD*Xki$Un3fs z@1FmIZ@SM?$GBi)Up$(@Bb#6jKhJy#SHQLJNzk*k-1vo{Z~woAYl6zqZ}o*XaRYvx z$GT2La5qlA|Jo=hX&0Va&>mbtW4MB*a0Q(fUhIDzKYbl=jtgF7cd&$Of;C(>u!Tpz z=w3;Km+m`PokcCLe_PNtT;p`%c~E!$V-)(oWS?}>Z7-y7O)!Kj z=nVeAKX7|u{!)D1UIQ(0fm*tT*R7=+xH`IpYy8SNwgm3}gFs0eDwMB(`9rBCjo=!n z4Oh@Ed|*L)@I*;t6f{8!SI`OkI;Xpq&fpqn4!595utcF_NmpKPzYDh2E1xPn{Wk9 zA`~=18?Ki2;cDpsu5m_i1)VtGKmV^S=@b_z=?tz3=5Phwz+Yz_4PJ5B>3sb)P}M8! z*FJ;?cAV;P1#Q4JegrRr7W=P01)abZbdjK-N2nEC18v|68jSo_*Q}!zxPn&AchCQtAjAbq+JdX49k|Bn!4%{y>S*n>B(bP9Jt^Zl2hprmW~8!YG+t~;*0-fy*n z*5IiH4GS;!zmA`h)^UL*Xu=h=3;%_uyNrf2e+70#THvT~F?mq}FvP5GQ%F`MI|F>(ui1>&vj`;eB2XF9iIMD<(6yy>7hJWEU zR~tSs@50r&7`}C#OM*TN*18m~35M|VY~mUG7oXvR&fywoS$f`o9X};q`y2v^V+{CA(_ zI@*D2oSyUj^S_ezd4VNO;R-r{Yl0D6K{LoBdWRXdV6^i6w2Kpn+O&1?|8W7PJdj&>mdl_Y)M9 zbPPW!b;oH6*FYIuK^Jrjx-{QE|J&Q{3KwXC4O~HMZ}D6G0Sj7(Yn-OTm^Z!W$MeI`H!RDQWAVP@F$a(19yx3jdh}9l|xv7@h}p=YNVq%aYFE z3Yx(+!2+(JTlnLj<4#lMt$6;|K()8}OQ4q4;av;bfGcPduJK!PcmMe}q3z8kR-x#B z{@=e^(iEA> z@A3S9r5CshrnsPIp1~D#0naSx60V@Do!j}-1e;x<3?4k)Ca%2QUz*>1q5F1S1HOL6 z%gPHQ`0u~cc^ke=taV)!!V}!PUk|Q3h~b(bg+JCN9>KNek_ieoAGxG+_=jwuC0rA) z;hJy@@7aw7)3T!n&;L3WuCP0nnxF>Pokj3l+YPkg8mH@dzWz!YdxaoKEomRFB}n0# zUE9e?tv7j5cf^Oj&zw!<||0`)DFBJdjmGKAG(g?1B+HeK! z!l&BQdw1tgN#lK?44?^8xPngLk9d{ayfe7QnZrkKxA*@g3QKzdS-}-_4c7!)xPpf7 z^gH?y3))Cf&_EGfEp5Y_*3u4KLA!8`ADi!<|CMxv3+k_SEuFwM&H&8-i9Yi)I~u-V))kXxDVGIr*Mrwgxd`#!3>30S<*RN11;g& zv}<_vD((qt16R;(>3RQo{3;jtOQ5A`z<;h*!xgj(uUnwrp%?3~MDbxEcMX)n6=($i z)){9Pr#6_uPk4>nD|2`;e!2gaC}`j{JW@;Hx`8cRH&A)ck&eCx&;QS{JBVJpD`<7*x3uz= zVVSrAf12Gu1lRaU8wCyAg?H3y_^#D(O_0KM10(1A=l^r;Q>qLX{LJoP0e|Fc-L782 zwFDdZ%x+-odA|O-gW$b>OEp0i{wFqZ6aEqN7F^?W;APNa|MgH9ThbV=pnbR|7{C>D z2G{o+v)s%5uUEj~lie2<=D0vVBf5a=XGE9qsg1LOr{?RuyYqLKN4PJsRNv<>!HxgM zt#JrH)4T!K+DGuUb+ko)o4xpoC#b(X9)@mOPay8_H(!< zSi%)Fc)#D#KenJ%^WF2m1`2V3k~ZMMFT1zbCR{-yxW;e$o&-wT_Y1)fE$INRfktoz zoxp1rbP9Jt^ZhqNK@-g33c7(m=5=oEgA4suYn&=vLBqm}{jcNKu%vZdpq4h^njnHJ zXb=8L3)(;M^89I_!9k&TH&N0Nyk$Yha0Q*fHU12q2X*Ivfx;(VLLBG{%X$?NKpdnmA>u?)C37RM3;7f*4IddUif zvHjie;KOQ>>x6zIN(J7vXSxs`-0+#@g%Moe9qT&ZKmP|!_s?chToBlIyT%t7687Lt zd*zDZTf3t^yqq8(e*phS3pCEX-2Zw79R98A#1t32(tH80o3G%ScmppcEdTrHuG8-P zP3_Jq`$G9~y0a==6NGTxSquJZ3)+GI{hJbZ$2}C3v=1Ly&=jtq1Gs{Y;0l^0C|qIU z0xjSgXa!f$4Lr4=TeyM-A9G8vd;Zr1RV!#uC}|V^M;5dN*Ek)xg7$pRfB%nmwOs}BlARNdJCt_enP-Psg=mAAN{3;65bY|sBI z6g0sGu7QJp@LM{!8>ql_168=j5C0+Y2htt1aKVXo2OYQu>cJJX4_~R%a`*ao&}tQm z{^$Q`f)QLnGx&4WYPiPPz?16L+~e>T1+^~txZfcSRD~;09j;B?g1_7aO@a;znxF^Q zz$y!|4>*&NUR`jM&yE|9O`Uq91* zognyx-#Ptyy&7EOG%BOa%E<1YXce#$%%y-ZK8mNv7l(Y#SSkMTrpe?w@@A#es zN}BqG;PsYt2-iSkxPngMV+%TiyP*00%TUk+3%G)=;X&-ac@=!xZ}n^J+*jcG_-5h7 z{@3x-_vIp7F#eP~9UXXT-i7NA4UOPK`}o;`yYpwS)!9Lz*ey>u%e~7j;U_-d`3C;Z z^KEnev)>859)$4f&--rvIto*Jp@`rwvI*Momzj6r3K+v@wkP`kjOYKrJ}|`vnqUZj zzfC-WzvSJn6EpbB%$IU^|3UD7tgu$0Jgq^XiMR0GgbTmb3%j!_TsKyOCz_y+g6^yh zf0YI8!Zl6|*Ak@gwF{aA0~C~W2-gH-xPs2$T7o5fs!o@l_g}|P6Krw8Zs33MTV1=l z`^>2d*A3L*8oz$%#ro?G+J}YQZ*+m%L|wQBis9N5DLk;C1A4xv%KbM)K@*JO3Oa|M zWkHv4jkAR}EKu+nJpZe8mCyLC)<8A50yW@T`v|TVsP4|~{JqBRAl?<+`P0NHToVrA zExWT3TsJm`zbvsAkSPkfvlU$L5y5Bu4(V^j)!?=FxII*d>&B8M3fk>0c-QW%4cDD@ z;F_QZ*NqLG@1Or)U`fZgKm$$T3Yx+D7IY3*(1qvu`fGxfSJ)rREnJ(Z@~{39oG^2( zuEBrBybk|zod399vHw~q)a_@vI&cN;!4V&z1;tN1svf5t=SwNecgS_ zW({wf2N(MtI?*~&-Mc$~y0dU!D9@kPxB;Kooi*XQvk0#7+wk|Fudn~3pcjxnT<_ll z_+@ry6ZnhFXK)3YCn)sn|CjL0?sx^)9k1bN#Tz58s>sZd<7r(dYM85y#D7?|0 z+n4aKlo#Y*7l41YILG;al}r5H{y6*i8eBI}FTB|QYPFI#alz8oK7y-5Ex0D=z}2Dj zz{~UZ|19b7pitbA1{%ZlOgE)l&>37oGk89}JO2w5lynXM!}k?ymVd<*t~IVK{Uy*+ z*5GH@I8FYY->r3`g$vY)4qO3y@QQ8f7_LtAJXa=9!--cbn7v>xI z3+;}B&-oqNJ^zO&H0=)RaNR)zt`0?TEoBe>8W$-4{XZyZpaEQuTqF3R>Rvy_a0Q*f zHU6yhy#G3WO1i)WdcR-6Z}xt-88`5TdGL9^)!(q!iSW>i_5WqNpmA8pT}dOj0=D68 zTe1#Zo#?`g@yq=eqo7WV;SJkd8N6*ihpQ87`0d~CI=B5ip8s{nl`r_M)4(-&&+a&c z>yGPijo;k4oj=`icUN%d?*W!HhHIb{t_PMOJhh-Bc#zoV^b?lI zfnRJl5PZ?^sK!sKDCiDC_*Ab4aJ9Mt*8~w)`?&vjO}b7rIR}f@|Ul z+$IcWp6BZy+Y3nM74r4BrJ2Ju!4j@J3%=yH`o0#l3NObg_FssCmY@NzTF@q3K_j?= zw&4oe%e~zHdIi)oU>_IU`~%i%_jXN!HI{6O8=60Ql> zaNSw(Wq%2DV^#QNGkg9IQFw*jaRaVrzzD7flQvurCSAB5Owt5}x=lQU>yF3p!2W*< zkF29JxH_7d@1FlP!2%bkrCa!`ENJB`eycT39X_(xkB0C0`r9#U`i0%QUkk24G5l>7 zD1|G~7``n7*$^X_mTuDp>k`vRETx@tIV-B6(k5yURws=6qRYr_x5&HF#}2uvK%3m0 zzq8?b{+SvC8-Zm3cE9$*<^NM5xj9ixK9xQmlbZr1U2;=Ek9;nJu1lUv!3RDCOa=k@4U%z8ZoZJ1knjFww9u5? zoPP#i@Bd8==9EC)7oYD7a#Mo^xyhjM>uML63OE%n`+q1Ubt{4L?blLckK7d0CvQqY zd*r5|0l7Z^a{Pr9FeM$4fBIZ}?Vi;5w8rxqUzD!LzgYoI2G(z?O=rAKe!s7vk2~bM ziTB7IX`x{4n17~;`s;w6f96C(@_i+PnA{X}O8y-=enx&nbAWrda|)O~UXXXB25Mey zAya_{`3+5+ze)c1ucGDL0R=uN0gv3A$R{@i4aj{dXrJ5^G!$R$|4jxFB`_tOkni|4 z)L=?(&NCx71)W#Dy#FU9Evf-!O1dC788m)d?E+I!hy2Y_P?sF%DaW5j0aH?+Jd%R; z$W1{5a#PTd+!S=Q^yThFA<#1c-67?>p*!$^JdsDX`s63e z%PPm@vHVf0gnaPGlTgx}0`cLC67_O2F9+lzz5&n|v(pl3yp@A-`SRBfr;o@)x-S}48|C{Y|LJ6W5VoXffkASD-SKWvTP;|>K(4Z7sJ{Qw2+lV2j|8Is>sjvtYm{03tRq*Akl+|+DB zZZepX?xhbeaZqDykyzGBd(q1K?)NQ7z z$&b1TT`(j!1s#zWQqY)O7j!xP#uP9aOvq1>j5G4!IhX}=a$jbRDyoBex0_J`t8_j7 z&1ip{1Z+xRYUYsJ+vB5Io7{APOK#5ZtsV343dy*?4(Mrkmzgv*xjE5@+!S<7-jISO zRe!BEX(}bP$jymta#K);+>?T~$;*Ob{<{<~8F=KTpndW^Z$Xm|$<292 zn}bCJQ6+!fErGr9WB z$jy0ja$C+b*Iu^2nSQC9NZnqY1-4v98|3DAn_XI>MQ+aHZ2GeQQ4*!vn}O0T$=D@# zqy`=GTq@v^7vf!Vt2~b$e?A4w<})Ba`p1}NA^C~o5&28SWAZ>ext;d^uaQ7T2@07u zIl0->738Ku>TlJq%w^UzRxb0;OdD$z!2B~A*yLu<*d{kE*CC%v#k%CT4kXa0z!~C0 za#NrYxhcq)+}Z(Kw1nJLcrc-W$zV!uYFv=tCIwZ0uQs(gk40`ic-Zju{(oUsG)iDf z>X4fZTyj&;9=ZQN7`*+8m;G-}G^_;HOYex>l_rhJO+m-x=KK?KUC`zD%PH{RQqqFl zoJcLIO>M3b7I{kw+9WpxwM*CI->iTp1BVirChd~9e}X3Mk(=}M$xT6rYsdWSN=c)2 zK+iu@(h<4IU`%cbIwOzeK0!|Yte*~0gMtEP9$WvYHuZ0%#x}XRygKA2LzjFg748fu zU~24UAN^BQY(#F(GZtU%|4rXaC_yGAP039`r{pGs8M!HFQT2gpr%kf%qKS)1mvb>Bl5kaVqwKmq6FI8mS6k`smG z?y)$2M6P`Jgxp62`Q4Bv^Sn~`TP#fb`XR|>iy|FxXQ`oC%ynDe)^m+fz+-vKRr z;^|TX_he-3lV{RpJ#t&Vf(glAb^$6j+Vo}rn?SM|*zhU&xj(;fIW$yG{^|r3Sda%l zgIoWqw#4#FDn0&M6nM~uD5*>SbMb&YxfCrFk=rBqh};|>|BLqjT{&<}35ttwqJ-Rf z7komV%ke3>InQ+EX8y^EvQUM+6EO~?f<8ez>W*bHZAh4-;IL0HQpr;{|75$Q1$Zr|KA}HRRb#d z1$;!FiO1xH_?SEvPssh>FVA0&zX=6$Ns!j~lsuB-GjdabS&ipQUygs%)F#245_pn9 zL7s{)$o=1-<YCI*s%VBTV=gG;V-{SbiT?W-AiexaVyH-7!BSC{akP}(t zW}3Cg|J%$Oh$<@5g(8104(Jn|R62QASf{~z&?e7F<(epKU$_Og;@`k4e% zN{~E2T8R8*w_e-M)LZC0sdAbJLfNZ0(B-?9IT2x5&SAnJm3E-X*{KB`8p^ z1=pQC+(KYEC}MK^a%4OqH!YXd_`Jqd<1-j!rVH+n44RE<)4eK2#!iiQYTPF`gR#GI zAD3|@#u{x?nCtpwH{)cCN*;~Jlk>yPEj@t0A+jM6#zo%uPsN!2~8HFjl5 zZjv8%8y2V*`ENdm7II71E8josxOdgLgYmxy4%)1*i^2d)+ z<9Us%dskax*RHe#`4w^=M|`#a-|8dCz^4R`l(a`~jt|MrwO~a4&8<+Nr0V7S|KvJ7 ztp-+}*Z88wt?jBUVb0&$qL<^(-D05pUZBQ<8XwkpT;r3aFUP-`ex{^ZO@euitNU!Z z#?2acHeAm?lW}Jwu$+I!{TlC+o2T9*^3(qdV{82Hj`^SddqB_sS&bJp-mt1IVKTOB zylv6`-z4yA67*_3tnpEeC&p2KrA)?C6VUZvdtT#<8n^Dd<(6oX5AJ^z`o^Vz@otR= zH9oBIc*|b?{a*^0L6_C|yvCc`S8E)cfhD$G<6Z4#`9SC_;g(VhZIP6#old9o|Fle|EA=D z96u+wpMfrD+^<>zU(RFQkM{rnxI=C@Py%xks!eV_FL>m>eB$Ym=Vzh<;mT$H<*!3v zxC-css(W_O1#yjMA&rs7>xk1}?cJ z-XTxEkMs1%LpeSuU5|gW0-BQcDM2a;Lh?ikIwbey_=r4{<40@9{7a>zlXXBhnYqiA z)%d)|)dM#BSgDVzi}d*{@(Vs8`~TLz1>~w&<6Uy|c_FCrVU5Rwn!tp-_!vfYN}hil zJ|(xsGx9{vGZSC!{}1^jYFto)g*2UNR-4ou->h+`#yeFXD03pe8c?Q5`{c0{G^+8G zJo$L2`+iFPfKM$eT#mndi-GbbljNS<(NH^8Tf(~@UCKW48QAP{v${oo!lz{#*Le4VwEs5=0!m;8-idLju5@{^Cmi5k09Tf(?aZcT7}n|yh^9)I2z0?W4R)p%IrqZ&_Ye7Xzm z|IL$13rgT0fIe&PTCK4o-X^!jyX49KIFG+_nSb-`&;|WfU|Ik2ry1f=jgMOI5 zmRq7#<1Tsj0-5&}FZK6xbGBj0Ox zOxF>)^Kld?9#9~DKLTTNGe{G1Q_u-{D(6YbBk`&DYX5Kk(&2&9QfYIX)uq$bXL>I;b|0 zsaZ@3e5u)(+|(=~FKf1JKs6yZ6`L7H{mU<*-hl)Q6VS=aXG6r*?$v^t;~V6uq_@b; z7;2IaJgJ#YfyDGNd2}oa>X4hk=#e|0#PI>Sf|u|AqJT*dlDFl*hvcSa5xFH58^?FZ(|cPG9`Mz-%-+rYCR}zSa!+Q#h};~X>_Pi~B@51k67}#GmCO9=N*Cm-0OnsNJ|{OX+Inkz(rUri`+t+MO9_4?f7zf*{vde* zGN|!kjmH%)``?^sQVEp53-|*1GOO`9xh#3xTB>n4>8lv-xUc)lpxz09+U5LEeblR@r?XrIexz3`pjbqsE1dZ$Rucz|5T25 zYP>`KmqRboHTKD`NZy8;^(k=gry@Z_UMA2d8k2hu!Ff{h?2Dm3eo7whh~u+|)BfMu z34s|UFc}o&j%2VP_wI-Ds7F*=G-<*c#^o?&GO$fRm%IEwUqB67RO9ovEWDh_FKD*SQM{c?%B!9DX<%nF4AE<-^u_Tz1n+z7@=?*Ap^O4o2_O3w7 z+2q;2IKHjD{NHB!1>ZoRO9|}z!u#aG_VAE==j$*nM>U>o`tlS1EF)?U3rYTV4KS{~$`dEX>|)R!?PoEq<}9T}Pg{yLxwu$_k{ z?US41qZ%LAc=~TH&;QK+Er1#nHQv~_+Cr;6Bl*9iCE7La4Qc{C^7Ih2R7jre0w0ol zpF-D++2!~|e6{}%B*BCdJpC(ZiLA!wHLmunwvahbv+4t70!}rcBFWe%&*kFLBe%bS z8VBT_ypAI#kM(Z5Y`rlDzKIh}$$e?Mj6D8t9AA*TvYlU$$5K%Bn6ibIy=SJGDXFsz zY|brsyMGPmvG=F_|05;fQG!?oU6=iCs6e0G zy&5eVlB+MnhsKe-d zoG2sD#Aobso}69!eop=}v~*dE1FC&v_UBFV-XbsLgNj3LR??34@|>&b zCtcuCf@m7*uIQ2%Ux)kTrprQdbuEq`Zu+uLp$v*>Gf=uOJ|YjqV{-Q(w9te+`!q66 z$(^!5I>nR%wv;p@H#IBBGYc6n$XAbUw5wfgyw#@tzX`aM-~nI9eC?8_uf_d>)F?vh9HVYE-~%7@nxc`WA{#1t6F-vgP{ct(EIHE8O2jjIEz6*I>-;p_ds2{<(g zIyLUsc)!M@ikGc#G9Fg~Yfo!@R^vsDHxAlDODuce-cq3SHu*ksN7SqFUX6$3<{On! z>3Z~;6)<=-24g}A%ug^TueQ0W&5FSwLL!!=#{Ha$9c22IRhtmhM-5pv)(gQ8l2HWE_(p zZ|?b!r*eEj9?HsS9a0?=g}!fC7RsSO{t>)AeoCW9Wia|4bKYkWlB zx#3(4ii85DC8jl=*Z88wEw|bdW{=r&2i1UUnurp-Mrzinalgj<-^6feo>69tCFXx$(4+05f6tLw)GxB}KbMmK%&&iJvFUWoP zKrJY6nj}z9sCLa+;tle*i(BOH6K|4#R@~NJw!fKvUzI?M65J^6kpEh|O@6P#&;>5} zlf^rmzU=>FB;aiZN`JL@mpl~r$=@p8BM+sE1M&;X>GxDRw zbMlvp&&gjcUXTw45?D~+23aVqCst>H*`Bw^%_i2Z@otR|f||gv#^V~F)Oc3obNG7y z{}-vTdQ!E<#+x+^=}q|0Y4d5?Fgw_FlZ=-ASwPXI7z+xTH^Ut{Tlxj;DZ;?Mw zGH`1=Ab-yb2l&x>p924L9zNAZuQ>`Him&$n*3k$IDS>Iy33)0Rr{tz43|jjhg>TcTCtF1Z<`-5L)zT+hFU_!sHv z*53#$Ve3OY3_K^e$`6I&YZCNpJgV_=ji;Nw?0=K-Y%{RoMU6L}zU7v%YrMS$*W=IILSQ-mdNm%__^8H{ z8lOI$_W!0O@|pyT8n>RY<(6pGxVv(he6Ki zR^vsDH=b2(2~%OabUpsf3TOiDngl&^_XD_78j$DjhxggPBb(2)WBy$&T`*b)ma|V8 zPilNhZu)pZu0D#4l~-+v{k|*D|1>G^pzmQ2IW^v?algj1W)j z@lK8VHQxVs$NZ1}J+RDQjcYt5f06X@tj3EPZ##YbJtC@EQs-Tje9lTtMSk{ z>c7rlWCF`v%YP>0q{gQ;p4a$-d|)!Lp10*1w`$z2@otR=TlVt(zZAGg`Z6Z}sl54Q zQsY^T&ud&ge_7$O{mt|<88mfZ?K_zL0r|E+z{1rb|BJX^%Q~Wf_aOW>J0}0ZZ}1|~F}eGDeSVdY zr>{lJO~{kMaXLX-x^6480*3E=bRx{HphV`z|GhL&rPyPrn|EcR%C5;ZB1e6FW6u*tu1SB!}k zxwRuQcF5z)(f4ig?7ffE=XVDbaPD}r4s^)XwaCCDclJjMb;*ki74XT`QK#wi_rzEG z|LnxAbReJv#rf!>KDl=s24hHWz34UiJVSC{-WL>CeW08JFz?6Jfbw7L>k}p9ZUY&l z8Rw-(RUS&dIGSx7I!<4?+yC1-WxM#)>+&I!M)7=$gjT zmyK(tU$!US*K1LN=xWT4CV68!WMGpQccPD5{`<$dbCm$piV-U?LV2^N>E6Cru1CC#iClB2ZMLw=N+B12z zbA#N*WBUVTQNX($)2T_Gsi)`+Z1$Vbmo0MjalEU&Y=1NT@~57v6Lctn zdNS5(a+!bG+c1xnUmd+pf_dB^&$q@{vB<4AV!AfT z{V!u>w8^u9ypOL%f#`Rru|w|cbE58oHhKIoOxF&1@xH_L@g8}2G|n^dDUir!vPT~N z9DN*+7dPW#(`P>hO&gMX$&tE1L->0CAKi}2ZbS*EEzt9y0_pQ)qe1S@ zFt`fx?6v4)>-g&6jUSJ7qDh|ajBAHoy6z;i0!EL=1Hvsz5I-LaRGZvA5E;1S$pYu; zkOyzV<=9(021$@&Vd<^|y6J-*P-CCGI0Gl@k>`h^sRQ!ty_kM|a_13)vJc9CAqB!0 z;UY97x3&-U@ez4^3Mw!nx9)qKK0YQdhO+4$P#}6Z0tvZyAFSaMa&RYv6U@qVCU3aGzgr5lqwyTB9j@FlV`lG_(x1x(4q-(uEGwU_O0reC1{ zAb9!KTT0+wc95(5jj^)qe``NnE}NTy(tUXwj!hna z1p9*)xjR7@IOKu6rlUO3@``f5-m)v>^?kD=>fxN1% zcM|RY{lB6H0VODIm6eX%+#3$blTXSDNFLpBnyy&1a+!bjAGE8{DuDlve}qkAOzz(c zT{b3n&Xg69Jh>PxG$D5e=VRqcDG)wWRzPy^IcTAb-1#kXdSmcG=MQg&>`~Uns*qO8_fw~Cu*dY%ei;Ga3 z+_JFXxa7`r(bAoYm;LWP2MdT-36!4;UWn1#B@g5ik5BIZ0!wd?yf^~$J|IsHD_dwe z{`wp^4_y$FXD{}37Yy02#Wf-#w|BsKM&!l4P~o_AJ^sxKm^==BnNWi8NDR6Oc|O5< zkdmv}3A&(D@>JfKoUL8wuZs6#u*}v0eFFO}$T%kt&%iXBlgEF+Mx!9NPC$(pZr~R$MkEE2j+7>x%*dH!pWTzFz9UdE3nUK4LI;BWbBapk3iqI*`IriZYh`i z7Z1XAyF(uR6We@Ge7*nQQ|@L_g5+0dA)ozg$RHpOPDE4p$>R{`5364GzYMxzHK2kc z&=L{3lCR}P$L%1Z)17JU;JnWy_WMClqkx@;V{6&c$>}$yjh9phwKvATp}FCD{)Hn~4{v+2wJ&(1>Ad7FV{8)Vp{b;-TE zp+G*lFMl1QM;`qU3sFFxj^zFSeF|hTY8H}P*Q2S2GCMjk&4({HwNnSb7QF{<-bK#xIX-G-~#ocy&z%fntB$6%$iC{W1vflc!CpV)HQ07+fj2CtuA>$>Zg#pY;5vK=fwW zAdnZgVsPc;p^`yL9{m&3vLG*H_q-@wkAJfQI#(X3Yu0#Kb(H2m#I&@?eOb6{a{KPD z)#quEhw>$~vv!@ovYv#RwbucCg7mMr%DLq3A-Fho$n95SVe!~^MvHdY!vU5?p90py zeO-Va`vB#tC`y z`zPy)O~hCG|41IQODRG8cdQ2)xqVk`xn|_q?{Iuh?*2tSvQ>Sc!kuuUq8d>C3oz&w zJ8EE)`|_BsL+;66IBK*14Cisl z-EA@GJ4;{wPc!|J{m~L0C9vhrXP5m#T#kM6{9VWCKJJlc=VNCTY`89p`HHo_5zuGY z4NGQ7o_`umIwa2&W>ZA&z5we%Oz!{brD%$T0?CJPb()Z855TBS$(1~AGbMLNC}>6= z{~hbc?B%ro_jkdjF{cF9<;xF?3v3WN6tKUA`Rb8}ayjmj2PdLy zeDY))oTo?b{OE*b1qLdhfPWYg^vS(%o~&yelJ6(?e1_z~Az1Sx@=Tr?iM5yQZ>FF3 zFD$WRO5pBwsLnVckL2n%A&(z{E=$Qh53^vp>C67N<;$gPGf;YTE?Qzn?%ofBD<{vM zi%smD+r-L^jR>*99Gu#}B|@Ovtkj;rPLX z0@mNK0hyA=w+~CJ&y0 zf)2^uFJh2J|vy3@DI(0~s`4RUOs-F4!Ad3~BCvU_6zX_F^sV@KqYhY!Ud?U4ItVV~huy?p=Y z`;l?C8c@~{34C%_?wIt*ix^wCfINE#re&YJ_xq)n<8MfT}H1gJ?v44|%0h zOrCrPvuRB3ZP(E)oh*Gh{>}6=&ty(0L3+n4b%K;U+8489N}hf+)W>J!>K(^vpKZ9F zf8KjAU-ON?^2q2i^zocLyc0Dm$o=j2(-|ztlgqFIs-QZki+$gq^H&WD#9u^7E%M^; z7}ZU3=Rj;IZ1&@yr3=&|kH3rxI05bd)myQEv^l|X=zEtuy)UL^huoKY#vZx-bxiNB zanxU_XD=THE&ur@p#Q791^l|L_5bRTheu#k2jtc_kwKsR7>t#We2`p&&Eb#&`E)Ct zaYUZUz1}go`I0Ij&*kp{PROl;^|~@pDFuo+)EQ67ot>}{W#rL)u@#$EEy=?#0^!qx#Iw>eYB44L1$WwVRL7h?^)i00Gl@0RvyO?FoO<(rE^&}*)Hv^^n z@;6#r_I9=#T`z$H&k*dN#b4h6zH(bQdXUp9?Cd42~jDn0g3peqA% zM;<=!pF;cp_@RDT?{Z0|1o8jFN3)1Lc_l8>Bl7rxXzG}JEBUNAUb)P_KHOtA>1F;az$?ffsaY0_lpI}~) z+gF^XYdBEG?^4%p*GpwY3#moMW?v5tyRRZPx|BFzwfZX2;*N8rOcnCi6gyiRr{}Bgd9>?VQF&GnLcDWUskf*Oh#U|v*u^4k{>3aN|70@{r38s|bypyot zWaL?2mR|DWlk(Y*Je8;EinU|@+46k;Vja+ZYY$N%b!v5xM*oK$QG>j=Kjytf9=r@I zV3R!k!2k(t3IxFcx&STm1b3~J!!A$1w#g&;THhu2`zTOnK!Nb!lXS)&`_5>IE_wbO z%o?BEx&pi59=U(jllA!n@zws{`N0V~(5D3U!*Cf5$=$DFWgL=6d*Ip;k*D&hc~tds z|Nl@-v$z^i$r$%=#^l-VxPg$6hu2~(O~})?%4jDq_FY~r%QRC8q@O`cWaNH;B{L^i zW|vGJw6IPr$nDQ>qg%T1>T*yo%WS4!^kZDVtz}@ty*~Q5$^I(b0kO%`pJN4Vljl1g zqtEMZxNfu8Y=@@nYy_4^dVj_|_Q;DAUDGA^zW*wnfluyy8tX)lJl$HJ{|_kO%0;42 zUhIwB69a;bn)obwEvI0=$n`lIA`JVnvg5Gm6EdGsvAO0$*rGa z)?~)f@a0dfuS65gOaSSXEk7j4$z6FmZcgsK!q+Jaa;v}z7vzH{?1;6!aawiIWpW~m z{FQgZ@lEpVDokUWJpBopx#G#dxt##F~*8V zUfhB%?rJaF-%P*s`S^(BQ-b&g)VN3P$}Tn_Pw$Nk`sCibFowcSU-p0ghW&L7hMR#> z?2AyKh}@Sg+K4jk-UJ*L@$Joy8ze(E)5u*>|*3XIamDxiBr zpZzcR#1oQx&%)(+2w(62oyTL)MU)`3I=ZPx zWm567|KlHHuQ#a#%KQI6z#vM=)tNHd$>X=9sWbAP+^n9F zTL+abq31sZ)IG4}nv;9y;s(WnT>TBRL%r6FY7AaWp7U>z+jkzN53owtj0|oFx0F=?q4Mv6Y}gS^4X6( zpUBcqZl66sANME_pLU`yKtOIEiwyeY*$pS_<3sY~!Dyi&dG=nkP&A-GBpZsD+?C(; zjmf>c;p&%=o1fWC*rkh8@zwr6?Ba9(loNcgr)!q6-y2;wBah{If}A`$LTY7a{fjajf?HPIabF7Rxc_6#zIk|fYK9(28QUCHH zB+q^=Oh9K>x;){mURNFMmNaRD{YzMIEOK8iyG`vk5@V%J?tC9( z#btjmR?-f+yWM`vDwd!BDG;S->MnWu4=hAJd3KF#&&e%$@F*Zpk42aDwU_O0rl0$N zxE2g4f%)tgkw@~R^oZP+uiayEU)}{V-t=Yv+b83bO|ls%J(q8_Cgeqd>6enb&e_W* zRa5p`vFpvq?cd4${}~1Tv=y2(CpWj%=j`TZcjUgjqGds@9)t?0*VF$0AIBi$#_Ox2 zJx%b*#v+g84TnwgLLOGP$?gBbwWGCinSa(+GTK)G-I6MmpUJk#S2v%@V|n?EN1hyw z54BzLa3CvMz=3nH2kesvasx6X_ae-iA-Q@7#zaIO-zU^H9E>QC$b$nhdH4`LU)7jA zx&%#_kb4#?Fd>g_#3!v3zTW@)PsHVQN(mhK_??l*BP^vea`W=4oII92;Jo5x;hlS; zZ;DEwd?(ELvfU;xOq+CNKUVqnA9C zFBTngwLSX2P3}GgE1+At?mV*sD)S~2N?_gz<&nGBV!C$8gI!SppWOZyt{uI#%i#G3 z21T$A=+PNH8lUC*jEd_<_)P6^7Mn~n(2T7k&UG>Be#EnozILs-5NI>a&p(gf;K0QWc?__SNnfwSKL-# zP=Y@;QDb#Rb+mg=!xpMRuAV916OxA^23@o2<@^7nM0Pcxtb1U$>X7H}#k_Bm2l5^v zm;EhU>8|OJJG(Ep=jHhGDB#-|y=c7s08>)jem*)T) z|M8m+))_P@fpraPY?DW_ZEumQGx6EaA44Zd4@Bk1pa++5t_1p4L7Ya^61HE>KS=_ zCAQ)DrZ4+HkS7}Fn}O2(XUWEd+>r+e7v#CTu1lR+odwQkadB#pyYXvq{kJF(-HA^^ zO>$el>9on!&bW58$Q}7*ltUgp3@y|?llK3Sd3OsX$ah5_cgVeMaFz4O(><{=cFDc> zgnC~2E0_6ab~wFNKp&@qzr9lbkAOYKbnTO8zeAUWNP*8{5mRB&fD_-`0C>II-Tkz@6v7&jE1m#_^ zk066Cc_Cl1`sBgqaar$?$Nwz5OwWG`q+4Oh+vu zV$3C_>+x?^!1O3|!GscceH17qHxH{%$@8CKJ;=zPzAeVYZ0$OKHIT1H=j(v3Y5JfO z_5Ux({ax{4bU_~9h-s<9>IxWNg3kpFa{D{-{J%wk;yh&BBo9x1+g+ZJ)^thuh@E-Enbp$<^8Df)2So!tow? z_^Z=({;Ep>U%vhJ$vt^@OOHI4$MyqqM{dRT$-}Q;P={yH0usIPxMjuFkP^gyK16#& zo?VL1gd=kI)s&uCTJ^* zJUbUn+9VGT#H_K&-EZSLfR^_1oM!sP^8Btt334mc1!|Kk+4;ES-VZVFJLLI?FebcB zU)IU{#IZU9e=|@@BH#V=$g|VsqZzrm2izx*o`*3Jk}r?fZ91fYvn#gM5xITJvvfg6 zSMQdOX5{YV1fB70 zun)G!0@9#>+0!-2i@W2K zkWC)SQ*ABs?9VvfA&=xafI*uA&hxMbbjkBW&;=dx^b}maJ#zCHUza>-;e&?{U+@33 z2Vz6fqXh2zWweufkH9+7C-*N2b>D^L=5f7Y#moNpe}(IDR0$|moP*2ph~2`16O%{s z@q0|}CYas{dAxij!*cvhC=eWqE=bAkpJ7@~$-{&2vS!0=XR|54*TWu{C}GQp==yna&tewL;h|3V^XEMhDB#Nv z1l60Xqc@yma5c#N3sHd{R+8GyOh8?2Q}`Hr}745kKB>h z^K{AWuY_f8<$|~2dj3UE!pG*`MnE5U0|sM2Zpq^_A-Q)1uIoec%)$~Lkw@p8iupgH zKrUYx#O#-0^p44k=VQf8$fIrKOK9>`?zX3Irv1NnIqua=DM2iMP9q}^8?t+5m+y#k za$CL^m>Wm^%X`4T!5*zJ0o_yOyCG)ingzS;|J7TngVg>52B}3JK2%mx@`3*VEWI`b zLirnxE%NA(7!wY8crCn5?%#fZu8K=;0KYI6Z9!T_5-YFA-Vg0EI32*{B_tLMC5_|P07)wFZ)0GD3;iG zGf=uEe{yw9?#b=>ggiY4eLo>LFSk$0lTXU?{}~0mL-2iIPM*k zwaKGDV?)s)FRnu0d*pVEF7A>?gS`*aIr$Xu%fHRG{MREl@9_=D6Il=X#uUfox1#J`oH4?F+2L?O1|R>$-}2&D>fvLUWj!i zBKM*Jnr=jaaDkSH$%7X9d`#|L?CJt1$($em~4>KZJ4IsVP`dx<Sw?~2(B z9`F^I9&HoQhn4q$<);=dd3FRY(;aeOo`(0x(44@Z=l90CGc5Ql3=}mIug4~ja(PreHyq+`Pblv|S#vqz+2Ffg>t+4?q$ldL6 z=W{`x9goq}cw2Sw`Y*+OK#M#oH#j;)lLFQ=vE{PKJ$Y`wMV>wcE#Z)R^2l|Y+};Tb zk^45@|I6q84kgHBkb2~P_jKJgUG}?SO!(x*%W?JVtsE^@zHAPkQiD}MpI0T99;^RH zpIm(&9+D?*)NDvzoP^D1MD7kw#3&t6Abb!;X-uyEA8I@%&*dTWguM7D7PKjO@^Or< zK}G>3f1_!}E`ORKC--A~oG#cMTvHb0O0J6P?Rt=|_y4JU+tol|H7(UY@r8j!UVIU= zrb+I+7%QVq9)1MJw<=!tfAR`6sZ$A*AHN@ozHE~hFZcDBaLKK2;D$qoJey$s@W}0_ zls6!ktxbNM@g>Dn>>0{M<-x(?_jcK(7-!5RCFSkY$W`7f{#<>bkAN9yy< z*&jHN(My3?-e9WEtuCeEk51DkYLKVf$*z~&x;HLnP4e^-j5&Ki0ayP1SBpHl2`v(@Hpy~sa zAAr%=uLe|f7Ped=`OfmD#38x=TXaE0?uf_ax&FmeIsV2JaDI$=oRF*QL*4fi_Mc(2 zr{wt=n3hxW@FzHbw)ExrH`CAi4o2yW68KNTXwS)$m-xCsb8_=Rr67;)g4^?p4cGIp zcniM6Rp(VlyX#{iYLG`C#s1$S_vEJ>O>*Z3S(3@a&-F0>TO5$LSUTk9>$f(!|1Df> zTyj_5fYu>T|KFjy<-GG~|8MPu>C~kJj;vfhxqA|77LeQW(aWGjjW4 z6f`G)_Fb_~%*nIo=|Nro{+|NDJJ1pfa!-B}qRy`lQs+NT)h*N@x6VezEb{0mtfWot zW&4}y7s{)YZAuV)5To5;e+%|>E_ou4=XA(38KmB(FZ(~g=`>w~?q;BrNS=i9$piTd zh&^)WahTr$xw-}C?~^+(IUCpikOKCJ7?wlw|8SmkkBEe=4q)HhFeEKJm23Q+Z4Nz@b3# zVNAa^c`PrPamlTH(3c%@`w(2TJo2E0%XAmM-v1ZJU|#x^AbJA4M{di{=>ziMVk}U7 za_el2p|Ij*|3~ujnPDYR-jaC|R=|io!Jr$FCr4m*#N_d@sKA&!waTmOa{MI}C?0{) zJ0VYxfT!elmA7C`$(_%lpc%RO>pHX2_4qd{pd)`IGN%Mygg%?I%Nq_0^5`+x`7Fr& zpJ7Q>?^w+O%)cT#M9;UzI-vjC{-?|W@<={JHp%__bdZkRx(84lIP#XRnaF`9~yw-B^+WRD z77X4YdHjA{Eu(kR{@;9b8c_oK1;^-&WAa#jlsYCif66%_&;N+QJ28&>mlvTI`#OWv z1oVHEgHyiQn3BKZJ{Y7Kd2k{=vgPES+@7D453*BnqJjds{8`-vd3pgZD(Zsjs8&sk zl?J=~QCf>U$KMMcs3rxhAEWPWa{H1{w@HgU+!rgI!!EDqY?FJp9-z&$d{W^J^o?}-fdWQBh^fFPGGX)luyqg9Huo=ykYbVv%PD zVmI6*w{Aw?+vLgMy$G~8@M_#zb;#qVVnfj;x8I11lS}U1aG-9Y4tXN4ZX9?NaH6er zf-ZUfVQis%_K$`7_#V0W#1oMF-$2Fs@b&)R{L(3;1lfOKtsatF^36uX{vli=M&$YD zP_ek;W&aoQ*6O4ZC|}F>9&7v%PysPTf_lUujyqUxZIUXN=;qjWv~%?g;xQ)(6^u>XjKs7ap7-;A}%V|fU* zMPA&3rQKOO=3gXlENQO;dQjQ&J06!j_-jwcJLK+{@d?RezXD5gm)tY&|M4l{?}lx1 zk34)h#za7#$**VoVk&kjy%LZ98kdi1~Q1qE%Qzn^5ic#J|=f>#)f4~9?PF} zO~hCG|44qPH=zWTbB6e{O;`+205( z&s@k~Fbl}@ZSf39pIttJh2-`-aTOhsJEtEm^Pd9hW{m0)x!pxm$K;OusBBE0eiuK} zOUUhaV+EYNi}wHVn^B;Y5`^30$0$>F52HF`|0()-M(%$d>p^ZD*(vo2d8(~20o}9Z z|2bOLcJfT_=c|jWqgrkEY@M>fE^kn5k`F?8Nt{gq^;9%1w#ZSvxs znBE=oF zCb{!MT;*(X^+J5^Z;_jCRGgK|{4)=mwpRgNK=l~;?AIZ;zKj}pNUK}fEig7XZ?)02E%lZZS%72Em2hy(JBc0wMQ{Q-F{-*%07XMYmgW6DkqCPH-9f!e6{~i*yU9L)+5CAuz=iuC@xNY^5P4)-xrc+`gI@W_#0Bd zx(OJ9zEGySpw?gLIZ!4FTsU?eZL#V4UDx%)pD zq#5}?Zv=FX@=K>VxqTt-auwvkCqkWU!7e}XP?uH*Z*cQznEwq5 zq#r_)TIAN*a(j*3pJR5|yzAX1w||WFqeEUi<5b-e zUGn4-Y*>8bsDJrov;0z_X97BT`G4dakAOUrw_Enf?Q<~whUDSZm<18}ppZWnH=;mr zD@qWv%gZLl;mykPCT%0E4IbPjZ{{3GH_|HWRrsUb4xRaTYryn~=mvlxRor1p4 z$zAyY;#_;#{$~1la$PSdL9`qCQoW}-dPBK5HOTYVW6ih7J$XvLx#`RP_omo@*qedU zUHOwKE%J1KJbdDiTOsCsoBi3i8}5=PpE?8A{|*JR1~Tx-;~~1HOYUEd8y7x#@gx+e zM;^&r@`Lx#{@*HJ(umwV13n_puEm&$$?Z$9u8dbM^DmbbEm;LH`tyrj z{XZt;>U7jBCAUsKO&>ockIy(*dq(aJ-h-RQGYZ&u$J(B=zYCY$Ik}R*lvR=% zTs;KWnt^(6byUX}VA?du3k!ETEOP49_@jyoUL8v-;o#;`8uF8jL*kBp0ocDEmV;EkHY*`msJO~ z_k0wzLGEmC-v3Df`p@~1^)D|r z|3F}30%&=qN$BTZ^2Li**K*F7Au$e7kv+-z45;4D9!G~dSH>q@^-8y zxpQ|E$R4=*O67fapOLkC0+;*W@AW4p^7ol% zW~V*#%(JsAtwpVb+k#(U&1^)F`6Z+&*a;8a%%AHcJW+)OI|)~2;;QH(Jl+YrEa)Zz z^IJGQJcRpuU;#eDqoXiP=O;Ygu}rH#fN(QEX%#}A_y6UyCTR*yL?O=abcP8xAHp3> zgmBL}ShFbMj<<1^#R@p|ziT&oIPn4jaP0v>cs(cK(Ks$b3gM~eu`63C=Pj2Y+~bCp zQ^#MD2y&s9G~vpZIGqeP7YnqJcK*= zk!v5}neX`XzkVW!K90NK0O6h!aL|Pa_w%DxO@t>#;_L_$o_mln5+s5!{~qrs;mVEJ z5;4O4{0XQy;hE9g8zx*{T%@&-!g-tjZ#xqs6s<(TvmXskg7ENR9CS&-Kit4gHR18T z82L;Wa(Mpta(o?5rchw;bizdPr&24xO}Ha> zB$IIEA#^l+gv)l!$FJks{EHvns1*><2~;54vFVx!S2EZ_VZx*Hu!SOo`-^b(ixQrC z>@1xBF)DE2;EEF-y&P+x5dJ-X5pgTwQSJvM2+wrHa+9|N3kQ+maUAU_qTrZ=(CjxUZdczLF~OSkKL2u$R6E-Q*oU6S(bBmH&+swfrksBvv4?QaA#4dh;i+I0`z$~N ziNE6X3lW}s2TT*;27bRkOnBxr99t2>Q!{av1!GhYHELClQ~m<(3tA}Wr{opFWeIJ5 zE8(G=u_Y47^ZtLF-|0*d1v3x3r3uf)0W*ZV`1goq36Jyd4>#PdAB@od@rAf*nF<8( zy3t0#^MI%ne){|2Yd7>VkvLLlj)R3w(sfhvAs;6K+0$JEQ>Nu19gYh4P%wzg0L3 zn(_jziBtTo7-7QwpVesc2<801a+L7YjUg?4jBxq#AkObN5h(m6GYaABxgXF8FkO(}v?}8*edIk5A3D10mu3MIHa~xy6h6DQ14uhS4%Z7>bHvix7 zBd$(nqTnBgU1K5KFbH=@GT|A1iq=ZF;UKoOt&qd{-<9aC+6x5+$NN*XK64PBxgNJ* zZo(bwu&F(SCm!S8FyWz$nmvp^KM^>NIJJTUgn!1ry)Hz!<0fpmCc^hA=n;hpkFUTM zji_85|GDX>yoS>$N)*ieYFmj`fG8ejudP*p(At z{SD?4bgkTkJ9^-q4G-Zi{+PXwa5H}qfuHc8;}diy14IzbeZL>!Vg9C+Cc+)R;VcLf z9_LTh#wf=xp${73MBrj*xmpM}@b~yCglG1kA!;RDZin%M1mW?Ea5+wD9NIrO{aj_( z$0@4tJFbdp!o&Pw)ePae@LiU0j_~>j?LJ#Z5Bd zxh@W-i9k6OyC6e&&SS|E?l_FgvEfeLs8*}QUs!G;JkC$Wnvv)If13j>orNlViCtkM zJntzU!^1+oQ zT>xaK$t0~MT!hD6Sb&@G+%w)D!b3JR)jrPK{C^h@t@??Ajr;!r!ZYJ>c?}Wn>4-6+ zCc>5dc%hL(4(EUQ14Pk6fx+WO7b-@$|1umCal*g25~p7a;fmjL?OfPkjRuL zurIBI%Y3`;AUrh&O|?_UwfW~cx>l=!OD9mlXD8tNb`u`v-(=(=+%^r@4jF|;{T3$D2NjUIk8bw zXdyiHG1gciJj|c>YbD&w*P29*qy2;T{P5@UlR1G_9NdC=5mTfnUxR}#O}LG}v@S!q zKZ2f8mhhnY2flvaQ#eZFYm2l?FcBW=j_ECgNBN%6O1S?GbUf^FBnl;Z&?y6XD?s z4I2=A#fE8ZjT&|5hSU zxci(S+~D(QVn@^@>We1RO?cu3bkRJ7XL{fU#!t9|-=qrUIiG*O z;=B*#1=uaZtDU z|F$1P+7-FEAU7uDzTGt*r+h^>je8y_oE@1V_h~#pc!2Y8A&2k(DM5u;p}=6^3JT%A zp_o2NxO*7#4B;uB-t=JMg(kH0F#cpBa1O_e?1bA#Aa@ZS=iEoQ!t)6cZW@L8L{zSh z|6EgBMxr226s%U{t%Qep`V`?=UO<-cD9^|IP`)L!`4{2}R-HiYME__k*g<%jb2s6h zF__*@c#`ub!d+wU!}%X2g7i4dsD<#%1mp?AQ#Ryj!u>oS!^8O+s}*Y+kLfKB6aPQJ z3$PIdA1}a3xPhnl5U!MB0Rh6ZW08k*9P1CE&=XM*%L&xWgr5}W3gP~Vm_A8(>m=kE z!c)_bn;t1_iJ&|M1u_x1ct&=@V|GmMB0R$L@e%Ih1&0XtoTTLwG(?D?Wil2JCp?J? zhE~GUyd_eEJ9s`>!UIz=e{+l4643s+>DN?-0;?v-^Tc%I4#EvQBRAo0p59NmjkjEr zo~!+D<^@Of0^k{5Knvl{8F)bn!WGWbgxhCgdc&iIeQ$N#hwHzE2;yA9MtBqy)E_6| zfmz5sgl9Mp5N?};>BEl_|G#B63SvaTGZ(o+c#`uZ;jVd@K0|n#7i@Yg*AjgGwQ>cy zO`uiO;FymY*$KCujNCP7A+Jh2IR6Y{+O@8*IiQE+ZXg%-kH zTaYIRPo9oEO}Jw#a>En)3Pb<5@{BA60`UL0p@NO@7M_ul@Kg<^_Ym&mJV1D$0n)4E zFH8g(RRBLR!p-%_6~YZXeUfmw4%24{Z{qowo+SQ%ge%A(P=9ikF}njZvJ)QS+(o#5 zC#Lri?%9Prl;=4A(p({u7ibrd;R!kf-Q?kC*9(>Dc)z;_NRLPh*AK z{D1j;EZD*YxxQ~b7rBk_*ly%b!aX769>QDBLmnvPL4$(}!i55ZjTaCj+{G_QAw0n-v-HqH$cq`|AJy-kRaStjq=>@=BIFAw@ zI*9382>0KMJVAIejyz3x8q(wVd%m#79^Jj)BV5$?MW3vd#ixF5NPa5v|H=ZXKH z;u(dBg69FuC`NdabA@o%gP1-^c#@ByOdIF(FMbOunEq1O5&_=FGU1jxF}90}xB z!qc2P2+#6-+=PdI!F>G4^ZtL93z~>R@;6k767KpPc?;p`Uy&yW_wanu1swX{&lL=< zg*9&F1y~5T8Sd9ChK+F9h}=oI<0xK`hwzx1k2?MWM9{(&!h{Ekuz(ohj&{fu!n2$w z3Ac2_^cmpV_|I9uhzSLzzZSMcvJ-Nda05?oC)~l)y9jr6#(aEvj`Ppe9R;DhKx^Vw z&Lf0-x?%b_;YrS036FKf^eMt^<{%2PM9|U$x%qE}E#c^b+)B8O7vLbgmDku!cniW%5soVWS^ww@?3yjWP{I4{^jxT7zow-N5^ zhulechNt%w@}R-i9~AfN<-$`*Hqfh@gopm|iI?*fIt) zk_k7BMQ$fN#JP)b_Yh3)dxiM_*7 zPR`?mn|T+s5-wwn4JkcW`#ddV9(xDVD}+1#fjmig3+EZ+dH>(W zGcvtd*b;{KF(a99`Ca68!UH_Li|`0f?`xbd7NCYk4qrmibVM|zlL@pB^`T@C} z@N5>ji*VD=$bFo*`Tv$*Q4k^u4xUkjaQ{!3K2CV_7v!ykhj_uMLLM|^xgc98Fa-XM z8JUxXEn)i&xs~wjQREK7?HwM_2CtiNS4Wk@`12D%t0sWek8pQq%qU8DhVvG}t$i_l zf^b7W!SvQI zi2rZ676lHXkm1}-cz|<1;lArIpC-anoJVsU>u)f)uSbQJoIo41@DK5`%7VV*ujc=R8bK0Df}1FqKSS;(yoK{7!fk0xA0<4- zd5fN_{U84v6%u*@@aUJw(}cGiL2me()c9NE7Q$nk+X$DxdjQveClN$Ip#FFWcYlvO zKzN4pFyX!*Fnx@0>%WmJUlae|{v!&KL?Ox*GK5>QnBMeFVM~NLmkE#a{OxU=&p-c9 zn31bZpf!NO^fPiF;UUgLgl9RA5bpaG^NACl3UWa!5u{IeP`iQ@N1J}lX&H@JdqQFHI44nH2&u|_hJk<~L zi4gANJf7z`{~Q7;wB`lc=r>EqQ-n8ho+Ug`jOoqa7Pdr&b1UJ7;vgzGh`=`hxtnnJ zK;(YHQ#^eW;dU9*M+r~xd|HA;;2eYs3Bnc5(}c%)0fz4iYaAVn`B(_Ia&F_i&HoRV zpn{VqSUC3(9vXt_1BCmBA`cU8;^||B9Q=PSPznWxG|wnWxMvs^kRd$Dx#|1Dmhcb9 z^fKXTjl=k}6M<(0D!2%DS&{n)Z{<8hc#`K6A>1(%^NFim9sjxMXB&lrR-(|t6;gz| z#$fs^;f}G$%|8^jL~I;#tBz~)ua#%y&-f`3aXxv4AGRGn_{WPud>D z`QJhW{_&Vmg77rwX~I1dFumc&!Wt(zw-D|+5!2g#B>sOZ7dVN6V_lMV z+(mepXXGP1#M6femuF)B5yH(5jl=tYh#LN3os)O;U3Ndgr`rz^kKrYi;%~DBL07JF$xr- zkX(v9Nw|me4B_b|nBMerVM};8m)kg>f39VyU~d!P{ByaGy9iHn?jzi`0@H^G&u|_g zJQZAt3UMMxtU}&OxR0k#5$@*cvxGa{n2-6F!j?#K9<&mHYc(o32yf-wO}JwXruP%x z!g&+nwzZf(iahWC$GD({D45ryLW1zfI^=1>WzG%17S_0l=VK}0YX5J*jBEu0xc$bt zlkg1Z9>RU)m`{N46z5^W4Hb}HEk8yC=1R;+Aza>wJV|&=%?N%ngg5bgOurSjgrN%4 z%fPkqpR<4wUVxn_1h|5WaJL6D@)6$ZMIItNwi$UO&vE`aHlZM%7icxIafMdG6WcI- zig0HQ@+{$Qp5FX>VM{2rK~%63fw>yFgYXFFZo->R$Mk-}Wgqe;!WDj@(I627wxB`_ z;Tg^ogxmd?K25l9D{{lp!WtWRJ{Hc~{Qnl-1va9P;u$#!kMNp#2)EZ_!2!a}yoJJr z9Nzy^j|#Cufx*eSLb$sQ(LJQ$mUb6(@ao$2{!hQSjf(-2o`#uF+ z8-ErePHUN& zJf9}ydH>(e6{18T8pDiQ2)A;cAlz~XrcVJn#T=Q>TY<{^zD& zERF&h1nN(Y%l9I;6K=jAxr^{7&V7Wp@O(mfj`PpP3y$Ok+65T+mBtB|dCgi0H$R9M zlp?%|^DN=Ehq(W5?p#>o*h83+m2mlC;`n}S3jb3v4F>!Ya9 zLU^1PkRUwp7^Y7XZs6R|1uNX<|7W&jJVtoyQM+@>H;67F~!d4}*7jjQv&YhmBJcmXou_UADpJK@$t$X$d- zpF{2=+{$@K*b;HB zV5OX=cMxuE#eCd^n_fchCp`2L_y3!SAj=h^g!^B{j9Lh{y^1_Rcq`{=!W{`rZ|F|^ zf5&SmuyikMiB_&)BfN#DcM|S;9rN)JZh8ZGAji@E!D7P&;hX^NpTYhnD#QrSaIO#@ z`8%dh5}thvd4}+y|7{eQdKA{!nnW%WZsQr*2~Y9#F2c?4U_L&=lgQ!uUm|e5iwY6K z(;py@6Q1JfTM751Fnx;fB z>$%$h0bW3pUI0A&F%}Rd-2V~s7Q#(DeS&cJKQMioaPz;o|8MA7SmPK7)E^7s@~6mc zgj+vD?j*d0a}VLRG^P*qB>sPl3&KP}{u~uzgeSg6t`P3~26>Y36z7>X&gY-|Fe;dO z6}E&ggIp#&!_(UdHy^?DF2Xb4BKHw)2y#J)2%30C5yAsJeVlOLcUV9x;VI5jgeyN_ z`e2p_Qa_@=+?%un=T^cK|HkwV!rh#^33p~Oy&rkr|2O}Pf+nJ1_z8KG@Ft$Vg>b_! zm_9*xfajAg;L!g8u3+g?SmXHZ_})&LaOE!KR>Ey}Aomk)_!M~);WIzq%l&^M2%La1 z+sMGe3(9tiYtu4DxY>s9hD;Fd|2?Fox2?nc%-Uc1f5Pi|{GSR86~|Uco^x#OKmXWV zx#HN|c}*MV^N(Lt;JP+J{xacH=B8tF+il0@&I8Bh@|~3P@@;oh0hXUScx>JRO{e~J zfM0x>s`jTLqvQBGTjaJ4`SkeqSk8mxc>%u369qmUZ;wd(H>Bfg;kh4&C!bHp9EAV7 zbv(Dwsp2f>K{b<3D&api-uEi+oP+THw2pVtao5It!CiGcq~rLeP!xJ9^XcKuqWS*! z=>$D=8ToZwKTrcY-cy%8q~pDGyh+DIA5f3>Lvoj~^HGZJ+?rsI;1`!?m%7wdRN#|P-RVRJrxaG*|L)(HmbxW$)O zkaaw)bPMm&quBQIGw zd4)0^kLvhT9XD^!r^m0ILZM5?r|Z&(G!FGwr{4^nz*(2iXr_+4bljoi5gnhU<7pkA zt>el1eExIV+8+{Rbb`4$1w%t#0bj(8LaUC?*QK}V_{lmR({U%~TKO$H!6`Zg!;XBx z3v}GFGtW=e@r;fy)bYr!e0qEdI|`Ele*Q=80{pHs6j&Sc3NBqnAst_$6hxb zN5_}xxUY>v{gXO@a%MiGUc)SSLt|G$K5K=^?!uBR%%PE)+t1F ze2tE$b$qRkTXhC)osK(o9KRCo@xcj_3-=yQ_-Fc4h!AGHsJF99-pWfE~@Q3+=yaK*<9u+J) zj^6}=T-Nbzh_rtLI$opWrVI1=`*U3F|5lw~drkoVPwIG`jyo>OXH>7_Ejr$y<4GOg zq2s2Dx&N;=#ZH|d4g&Q@<@jQL?N38m#{-D8e=V2f)8k$Tg)tpJLzmugXT2em$B09mjn1}XnR>#lN@yO-* z0(R@TkMDTYmOEd^V>*6;j$4CQ<}-e2IZi?pfxl6}o9lu-0?NQyTb&pQq)+rp+ zaRU!Ts7-yZj;D0|J{@=6lE0w)bv%^gYW*M330iUjU=QlJ`PO_!_z8u++w%MoUHYhw zx9E6M#~%fb?GGPXZqH}*xK1H^AkUxF@klJspVINDjz6vA@*Vl~N}dM|PMzSHyuc8? zGp}$+$5T4~td867%BO!$$DKO$qFTU(s>Dj=!qoSshPsj{ScyU+`->1zE>m*KwDQ zzoFy4d-M7HUB_cO{+5m>*K+^ABS1+fNUg<;RK7^Z(>m_c@r;gF>v&ejYjxbPE|)*l z{|cSJ)Fv<(^ajMN;}7f7TXg&}9hY_d2_3iU_?s$c7YrRTIcR>e@#xb};jarmzXHF9 z;P>Mf8;^E+8Gk#!)Ohq9`1QbV(PxcEho&2k_J`lq@VOQKKj`zuqrKqwd-(j`7mY{n z{-N>c!NefqeV3(k^0WR`L{-_3{dF zma!lEW`)?Fo%@wIlpPo^I@!_%(h#BloI0;sn5=2byQ&*}@+ou6WQBcsqhMw8o)W6q znt9>?_C=#uJG}1-f0dScn|IqrZ=GCSv#A!+8oIi6G{~DOs<(QpRMl_Bi^Xi$JaH8J z?F?ZA>m3!A^-+wa2BnAWuc)i{%HF!V+PeBOw(?4G@WB43)au?Bjn4{RbOMm7b*ybrm)Bo4j@9&^%j88@z@=bF1qs zYj=9lbSW}SWFI{x$n0-V z35zZ5PWCp)N~e4y7@)%NANyj16RwncF>|>zgT44bqH9rIJ&XP%6tjmuga+0w zXY9*~9x8tSR&hOJ6Q#cFr+-03-u6pFS<%np@(#s|cfp`)ep(RN7Fis_D$W4a^OguM zCff)0Ei#R~<9)Jd zHBQk!&KxSuHI8N#cNX_&-j~FFZ0MQ71=#*teZsGZ-J8Q=7dCjWa#6kDZ6BnG@(O>>KYiU?DjLEffjCtCiu1m!5LLNndGxyV{ycFMBF0Ok=jQgl_DOpfH=cZWjBn9gm7@*yzEc zhrRNs*hyz(E*uQ@W#yA1w>dX_D)eC0uL=v<+^?ZK^2R8zRM7vq;Y_h3n|iu5wYfW3 zFaOO#2UfaS?!>-dE1kxkI2Ei{*)PH%_V%MTKK*!D@{5O(lWn3vaXhD%@h zwRmEYBD3v(75XyUcBw1-={(79%!65M<+{s8nn0%$`{aE&ljYVK+P2Rjg$*Zih~NtgBdwqT$SSlduZuOG^a_|GX&*R_2S_ z#P`6+EnEgwzBvx_W6d&Q2CH5P&2{nD;%4@b38IVb9W1VgMDaK#TEotKNxk-I?Ch7o z#$9od*nv%7C=FuY4u%3f3ZJ z9^11}64{7hlC7&^m+Pyc@8kxbmyKUIuy0$Yz1mxqqLJfR$H~$}w$LX!*k5iJZAD5c zn>7ta8WbV2wF{+*#+B^I*U(xo_{4$6)%bb*0dX+Pd@XKd2X2DSnDq-Z%AgYQWLB{k ztitMFgvsoU&B7>{MZqhD61HKobTYf-N>~HFUItBm&XvMqRlOIGgRCEG;w+W3QRN=*QM5 zFpRWMeSCuS$ibK3YS{;SrPb`}w_vI*42#>D{V{P6TQy87HLhZVpC}o{>|tTDI@LcL z(3=eki^JGyCyNu<)Jdj||AEcF3SD)>Ra;MAJy|rf+a0jdX>086ebORk{v7N@ z@y)_KTw@w6eS3 z6-$ldm}iw(!mdA29L_#G87A}B!=y=U=>f5iaT5Ee`HjBpuGfUI#z|K@2K8m*mJ4Is z+r~{8XJb7pV2sJvmzdd=`%C(&lV*l`IqjI=C#=JZjZ}jLJCqgd>P+t3Zl|}hwE1s8 z_G4G?lh(24-QW+zf0rfp^rjLMd(I6LKC`1_WKTm+f33fKQ(eV2?^Id+9~VCnODtE|ciBh@8w zF7`t@4DIx(8`{%+hg`x&y#m#amB0*m_g!ezRnTolC#Jlzn<)402_w38o9gLotgUL4 ztLtG|7M(COh76Ym8~d=qhl=~KGtPw0w(Ws+y6dlSX|7jbP~Y1P{#o;jxDt%Zc((sc zSaqK7ruL#;>c?Eok_j6C{_Mr#_X+cJHt1CKx+FI6S};Ufn`kLM@bQt+JW<@HHicDf z*IDeq0Vw&A%OT$%?}Gt6{dBOyYD1k+SF^dzhQi?RK`BuW6#CZd(CXSqy8J9KSvlL- zpLt58_U$Tb>++_zGh2MWP};6~`~*82KT%xYw-Z=&?`Ci&JW3~zTv0FYP(^E&3)9(m zS-6DwFEDqZTe*>Y{bpf^QDhanz*gOOzc8LH+Xah;_G#y1;y7G7!>@>A*yv}#W;vYV zC5$Z>CbFg9h^yEazd*+vEr9_9pH5`o?w0KA#pS|McIPYNM7C~^FjQ3Cj1HyXl~t4~ zn$OX()VtGL(@?6g10HZdyAJ_NGhl_VhPB%xPGO6Nh?ChB6T#>@UWco>v^(VUHz!=k z^gW{3X+U+Qx3;b^FoD^2gY_8lnK02fmd$!yu&`uza2{9f0dwzemPWAhZqjn*90Qi2 z$4)^yVOwn#J90Bvu$#{kR{Wh&bq0G)}q2>n=ip){>X0VDDh z_y?&2Vt27$HTVBq72tgO>uPsaSAj#Sz@%JQA<66|Fp4a+M;NI7Gk~qKOH0_Q&xAE% zZ!ZkXDs@=8PFZyFRJo#Z%XFnZc(OI@HoG*LJ$qtqF*Gx&eHYbN1pj$!b$tUnvR0af zb^}Cx*=2hm7-GPNzrE4FSeuYo`7t%`9Zi+?7}FivFW zMuk4ialX`@t&54hg`S(e4O*h|DsKb$`H;3~40O>*rtA?M?2{ql99DV~*bdtRFn0H> z5Gsq5*=?DWvVT4Ut4!7@dRc8u6q>Js#<{vq8YT#M9rX>cs{m_PyRCd%ZB2DUZ5^|1 zl;##GWojNG`|(#$f3!{l&-E%;FnXO04j`XYi-&?8(i#swmB50QQ!umMhrwSu?*Z6n zeY*;5{AhOMF|jwBa}}(0TzSAsVJs@EpNv!3<$J_&J*vDFRkGS5GOpO=-N9|FKpn}YVE&=vLiX5MFj=)Ov)w039bihR9roc_;^pk4v!M02t%R?2Wd1Z+(H1>ISs48Z!PW`OhBS}nSY1}|gV-C|!Re-8fZQa3nmrJutk zU44~U#q5uZ4aQ1#<3?CLx~(ei!9F=(n#r!;C{?nb9{>Y;YY$j%;FAOYeDD?+W^F64 zYRG%B@0hfLc^;F&%UvaO>C-E>i?6N0O{u!$-2XX@;YTlnH6k=YDq*j@E|^%^gJ2I- z220cs7P>&{hW^N_w}J5Mo}#5>`ws68FZ8&f--?=wja$J3td$$;cGOhD&{jVyMz;EF zXwqk5V1^H!1}(7iS6DCZdR$!FUNOpwm6hKBqoAu*n$cV-4QKCkm(om@2X|uly<08JGM2DV>QkYeJb3U_X4?m*A>L{5Q1-Vw!2N;Dira16v1t>FI$#It zpEh_n8+Qnr;FEKpci*`{vasUQ!RuW59*lWlHWqjfW}k~4sf4xo=(lovmRu#+*wYul zkeT^~AR6beCEnuU?2OZe!R+5x!K$N)yjEC~Z=NF6;KYGq`?5vFgFCYu55va%>a$_3 zTu}+vER@)m<0Z>1Me%b4I{o=KP5sY{rEJuIS<2qN!u$ zj=DNnpIP>F;e7VSrO>+Ii3lulIV`x*p5i>FS`W7MRoIQ)dzEk|TWtoP8itvL$-k>x zH8VtYG`A7hAQpW{?4_-~5JD2v{bNT~vPTiY{Uu%5 zGg+`8*3MGTHkY;wd&(`$hKVMzm(Aen{^L?;UdO(Y!R$7NIu`boSXkGqOFG*Oy>qTZ zMcw8d+n`nJRVTMwj_#yCy^ z_PiNb3w7*ehNv6_`3lU#DPnOav$v+oUkkncSF>V5#_Oq%@kHax3h(uh{~+;MqXXPaPAGL|}^!!IXv#!Aw^CrC{pY)+%Zk z4MJ->ysA~(caAW;zmRL1UDb79l^XqCEdl$;4HiG=$+Tyd)v)u0VZ2Za2($;E41A_V z5SL&tN5C)Xz7;G1T=m@M-v!yY4!sfgF!8ib9p=Lt4yA#;S`P+CW$e~nf|?M<+5(tP zJ_2QEUVVqp`zNqdzwN-k`m%<3+TDEW{G?(LdSgHPglT-rR z$UJzyQX0&zxKQ#jcbRmmaVY8?dP7(M3*n4j&|aVRlvc4%A`nnpx>XoZq|Cr1V@81= z@o@wU@H_8|%h@euQhAXwU6u7=#SaO~R9OWk_(`4EpH@nxY`0mQpNMb zF9si4{#}^EUYrDhJI|Le3#a#zLTtoj*y^3OKy-c@aJ0fpP}sbFTohYg;ucAy^zE`3Mzeg0l4+c?}XLn#VufEhOHJRuptewvh4c+ z_F<2o1J$JAEYF1A(c#j`~T^pEmI~&wl>csB96>6F@czxN=3^IT@-;e6NDkbf~k&L^J<|J z#-jH89opV?DqQc`Pl-#_jg7X@cdMwXDzB}p-dtUy`f|pp(n$8hi?E2pf{V%kDn?|E>cd$KmPW+Fbq~aP4Ld&!Qj?r#6=w^VQ7eDMhxuF&Yuh}-P0d{dv(`- z*s?F#E1t!|--FYAvr^oV{k<0~F2hxQ zfxT7*k)lcXdGYUHnP1*3I-xYs>(9FPmd3JvJETjDBiKjZ{Jl4O<}28!e6SzfjBif` zmv`$n7};ACaI&xV<*WIhm2EmHJ3K_PwE zh@;Rxk*Si0-LY6&%cci~DVja*R=*W?)TPyM^FbXysT~l~KX)6rXg^&7hNbI2#QsH9 zUUcnXM4hD8SX(Lkvs7=XBb)LyWIOdkaafm;5KaWQr4HN__RM!e-%hZ}-3+_s+D+`p zix7fJTqv|>4+i0mMrk>i+=*{N85OI=kntS0{%LTS8dpOMVT21}T2HKoKac(n+ttq= z66P3pvh+i+!2r=pHuD--rPe(y&SBZ95Cc8EmpHaqYN+(fzKWVESlqUFHK(fW9tS(? z8mRGxx8TA{M~HI!;i}bO$~j<8?jHrc|K2sy61K1>)D(guvMJ{vv+4W9?d-~jp^ZEr zf)LE47DeczR=RtaDGk*SUD09~Z18rlrQ0upXufqP42>VFVD#9J3Z?AEr$NAaiPK>$ z=c0*Y*_&?({b+cx4?E*pa8B%Ah!$-=3hSiD3kz*XyHol|FxAwt;1OW+8OMw^xIU^UtH| z4B5aVrs}?}HygHAsBDX7%1Q@$V`GE2o(X%Qpch9#u>Pafu(yBXI#~C9Itpv6JtRPg zSoPYKufde4E@Upa*g??ZM%rG@JWst7Ddz%7Y)K_lH@;i$$>yI1i`%;w!8|zQE?80b z-Uf}T&9W!%hv+D8(4`(>U~%`HPo=t3u!V6(ib z+Pk$1B8Lz`xb`mCi|u(0Oqz9?G^lUSsvUl?73yA5muUa9uq=JD4XXFouVLt}-wRt? zSO`vL(~7|U{(b~zG2A!G-)u9p!yiJV{I{J_IjdGx=D-Hz}?be=SzyK3Fya8@HtUU;Rq%i^x&&hp2q4iE|%Cm4+*_GwpRz?bcHRcfl*^#0#|W?9o&?6o)zY^gS)_}TC8Ay zC$0fy`8na_qDf0xc)ieP-&rue-hNt~0V{maD@m+!8jS06ywW7&cojeeYJ}oGz3ZyB zRj9GWjnKaQJ~cagnlukq)6g`@!nU0T-SNO)FfHD5VF-RW3fRUz;sSPPnq*_k`%2Ds zTHp|z;8kpCUui*Sh#Wvnu0gfyJstrcZt^!U3pHCdc{+^3kIxl6?C6K$3+%ZX!N;Ds zORQ#&CI}y{nJ%5rX03yL)?ZTM7Pjkc;nGJkuZdlZ>|Q$zv=63BSFi`YQ0TC8;Wkt6 z>!nkeZHcst%|1`qZnUxSOQhbc%V@By2bMrDpS}h{;UDjXtz?I#(pl_*^Mqey*>y5q9(%|8Wi69bfv0a3Aw+Hfd#w5!&l|=_K~c>#$Ho_KDtsIG-&&d>Pj^dVwtb? zsv2mihpidh>aVY_*z9GCtYV3&y&4OEyYtLz6-(I#x5K0=Hi{#(*tw|`PX*K))JS^A z(pvRSc|G&)1G9baH^N`p_>bT|)v&w8Q`;NYDn;v=FjG2>U3oq9$l`CsmCUprEKuOE zFsM(j>e|2rd24M&P1_Jtn5&=EpY2{M%@8!Hc0&g)vR2*-TUM|ZYOs3S-D2&&V(D^L z!o*7TpV|A?!!B#ZN3bsLwZd}T;RYDT#k;|&TQ?efyfd0$WA^L05P5mq3LegwT37>= z&EU{Hk%YT1C+`-SGo|V6$Ew%DIv)g=?T2s0 zp8M{A>2>cuVI@1NKnuHS!Hu}?BXKn=IS(AQ@l&9nE7n8dFZY3#*jWpoZkY+;{C8@^ zaedmWS(PhY$3d6v1Yf7Tp<*+0JOk^~?^ZCSSDXg!C@it_*ugGR7tNy+w?h|?wT(M* z(zuDG^>vk{`4F78N==}0b*oywt$wrG&8AfttC5v%xB{qcxrH4uiZchoP^hVajHmE? z)p1Y`K9jd%n>tBXP7%*xH`T&@ns!E*hHp+0R~o@HX#yYMCMFI6zZDkkzHID05S|@& z1I(NL0coXip3Z61T)i9nfxVq!gj?6eEkb3l+=jQkTvi6Q-vD8}bKVDs>izY?Oz_St z?jAIhjcSIq2txE$CN~Ri_H7@SOUhDkxYq81twH!XVL~n*ed!Gl37F)EsF(KXZ!@L2 zT5NC*`U0+IaG_s3Ec7)lz?>b+VD!1bxUN9@8}_dw_`byyh4<`}`^?CcAT3f0>*uum7=aUr%vO;!#aHmb)WZ-Z(v z+CnadZYye_yDEKZ{8Vkt9xH0L)WD3yAPd~YEnzPip~~HtfoUpL@7WG-z7ayPzaIvR zx9S-PJq>q2wCsnE!13A^fL?xoz(92YeZ8`RX z|1j`k*nh%(X4qY*e{R1V79TD01%DQ|tE;PMY`dSR-5Bg@g4?-pOJw^FmbetMgD_BW zyZWuQ4d`#d9Y+{kwc?m|7I2=}N9Vz`fL*eMJsp5WYQ&>3A8kdjKzCRN)A+S}V3+@L zEzHTP?_kbPWx_DFeLMsKtGsseBzYheym^)o0Bi7pEr(8p zn>yue-a#-XbsK~cY{7P+Ten^6o}z6%9=cr^E@^HiPcPT|D|Y3rDZ7lp%mT$?cGGBx zV;n9MH?T4v#2Ur^uzqaXE}Y0V9D@2kJQ7xmx0gY5vfGW)6t?9cgqwfPfNg9(0K@j0 z?XY1v$Y5K0+Emznzc3o+-2T4M7sHRhee3-jU|;h6i{R~b?+4wr?g-4|F|7Ou+?dyV zz#c{5WT@w5bYa_dqu?Y??$lF9)^bQ32cz?Fmw{u8%4BxET6}OS^ah;R5>%2dqVF!`77hSjG&0v3N!KM3iJW{dlQb$rqXi}7m* zAu{#U0l~p88zs(Xj^&b{y{`7@@{1vo5uXYJO}H0!0k3X{8(y%02m|3@!4Yuc=Qm2{ zYQbvoq87C~!&_I|b|ZE$TRcka)=o7Cc*{XM=`g(xZoq2cUp2sb!q)1I?9y4%v#fa^ zv_GIB>;ncC6+)5uSq#Sp*28X23mzQ0SUQ814F+E$H3t~P-}|xO4?rBO>$A}F=kIPIp6+c`KZsG9tqPIwa zXzfU-Ox+j=^8EUpdVkKw9M6Jfjm(B_obfCez!#qf3$iyROo6c|f2{6O&lmTp<83N? z!3~2vXV@f`Iv>XGhp)i+sCoyy{l+3`XtM=|`SnFoCB|doMX=SlzaN;IXZ+CRXFe;A zF?Y|oY322eHI?NGJN&#*&aPPmgYaLw;kp<71=?rg_t3_%d*Pq68>Iz(DpVV)F65n0 zS)4QbY{MmzI0EiS%Xv>g3p6yUOMqFuLkxFg;e2WBj+!bK{EHy5R~uo#ese?^JG190 z{O|yG_*9in%d59}Yj-rLpSvwny}_J`fxj0+Bn38n>b4K$OtgR{9=!r?lew#5%`g2# zlv%&?VXt*}9a!C}@4-W#WRVVJ9s}2-Yk!C)Y+ek97;~&i{j(=?*9&miji>9U z{&{Cx2lZx|2t-W&-2yXv!TAs&3S0s)^wHl!AO2+w42ydrV9Ppghqz_KJA#X?-VWpV zit~kqY+p5O6V~4Wq2cpB7KIa3FKGA+!WeA@82>yh)OW9kF!pqzZaLo=1&7f&xxZ4^}>_9J5HRSYh4bjCqbA+5#|p9 zr?AR9cKkRvECmOcRcFs%SG^N9xusR=_M5#n3LJ%(9v#@Jn|G&rmRKDb-c1$AmAeLZ z?F<3fI&kIN5|5rEb!KCqgI=ooR`9a$?E_8htWUsb?Y#pGP`VNPvYyjmGIzNE%)M|1 zRO07q5qp)5I}Nre%i*Taa(;YxUJV3x;TS}ncQYJ>fISEJDRBIy9JVtRTk(Vg zKjolaXi$x&)NQJ$)FKB{|DQ4|ljmt6feQ6jl6tBDhGwan!z^{~(CdMy=C@aL`*;hRF>u(X90&?tmJ(s8O7{7-fK|EUZzW9Yb3>DWV89l6IH1;@%TORDAX$%-Ep#&jCFsk&S}hT&zu zzXQ>kmp=j5+xaN?!=IOf#|w5`VrRjQEI8qKLsdQHQO*|&G7dCjJL-6fycx7$0oqx9 zvdu90k19c2FaDr&tP=m1OZ~I{4Iaa~{vXTvuSc%h9KmBQpMTaIe^#qwRO%RQuQvUP zva+K2{0G9Tzp;hWc_pcsrZ@JBVUXn=4wqa`jXH{~ya&n}uZa zKXf?OFnIiyKYkJaZ8!hNT3{;%3%s=dxf;i=#W6ZcSAtfHV4*j4Z2S7ZbgZtR|Fm!f z^={k$v7G<9TSn*YY!DsZ+{D{e0bVfNWGJuRwynGpwto#cD_}<0^GbiFLq?7^#E+vM zEGzqCnMD7;Y)XAg9;dWF7B;&EHm%1Sga2KFs*WKXxKVFtt0yVCZmr(rt!%8^s_nPr zcZHI!-R9P+tEG15lU>#yB8(f7K2l@W)&(!~iF8yO+$0%!_ww)x`sw?cj>{0E6$KcZ?F*x*iqh7Zv z7Azd&{|g0jeOg;;bMg;+)1bOp))iG==rC!+{0~aU)Hzm}e}1jOKdf}R#{5rqO+Oj` zyqM#b5`<0ff7fTQX8!N3aokD;kH5$M|E07)t6PwtYETS+HV}{ND=CA@WQg=_t7xe7 zsdtR=q=Xh0!2qA(KWr`8gd(Z;y!-&?{?{0FkRNm0{n41`77(`eMhLH;BuFFsYDQ`q zS+gNdD)rTElX+3vv_EEAc)YH_aOX|ZF_W(%$&cIT$M5pvU(2lHXZ~khoIAIY7zH71 zErwpyAWZ7n0alBeT09;H&ngtjtmhRFF4dNqE9XKWy7vhXk<}IsxNXvdwYw9dv~Wzq z!9d#8q&~s0S$&8Rjv*~o!@QfSwcELU=V%|b=k#I2sVzxmWi04|MakX(0m>C);kZTF zn-K0xtydq^UBJu%xM%8~0|yCazYAv@C*gV8r~0e+E%uAES*Hg@tD3kSON^EJu+t9@ z9LP)$LQFcxPGk=?2pgGvC*17W{Vqg$PkRmmgw1b=cKme01#ssN*kTOk!ZAa5E-(%c zuWV7zIZMs|6xSL3>hWe7J}zfJ#NiMCoXYA8!C)>ooB82#xbIc(udS)~vTIjJv*D~A z*E07Y3D{$CajLPdEdw_8d02RrHz7LvWL&+lRtO+B#^H$Q$1ezQIAI0cae;#2xz;0M zd-m3&LZ7x9z&7^53TZ^|Ia{mYIQ%J9gAKVm)LgI>jzW0rjv-hEH}H=o=%n6q*92_6 z0QVI)32-C(;$H`LVQ;R01K}%Lg-JniDW0ZZ%Imur9zNoosThih5Z}tsCN3djRd;b6 zNz_xl3$PG^wCXXB9d)n_DF%(L0vB<9Fc15v3FpAeENXW6b!oNd-EzZB$9v6#=kpt# zaK3S?x9y60V;hl6=)bJ(tSOO9VXwXc52)v#${VBJ?RT@@8^jgtygBM)QT&0z8_LBF zY{_>pH=f-NrxCh;1V<&G+W>ciV5TinpVTt3trx)b*?TG6m3U|l+-v*Ca}bS(Pp3tG+8(E{xCED`X*f8_P99Zm=a@s?vk`i z)aL9w_GFQG0h6u~7aKR{#ZR9O*6`9+p>e40tP(`5WN0=x!3+<0!hNObih~~#Uvj=E zIcj!juUV z87zakii%>}^|}^{-BnT4wY!e)>WaOrbycvtR_tZf_y3*y-kX^WxbFVH?;E}3z58x2 z=bU@mh3y_mjum!7iNh7OHWQ$t%{tH(7Sj(L6WC@6*%>j}C=O$^BTG;!8nnw@JlJ#i zA|g3-yJE^Ji+u5;fNZuxwoE0eM)ft72>Q{yirHjtH8uG~CkirQhpWQw>o)!d2#rd#DZUv(ZK1>{%>BOtSL zddEOXnyDUp@A)33lHMLhfj*Ji`dMQ;!?ZZI;-k~uLjVzQ$6vF-*Qgb8mlmNDET()S zN9-og{;IH}FR)5`YHDtZS(I4(Xa($VPIuwLW4t<8ke8#*{tDaRGI>T_XfH=$fvcv4 z$lLG2BkcB~s}P2xCGCro}jC-9Js!uUh z%E2oh^{5{ul3ORbN)y9Y6VGtDJ&EC5mH#K~N=`l6Jzb5WZEF8SNTg|9&~j?sMaz#V zaUZ3Ad>8TYz}KB#wfj<+HZQi`MgL2lUV0I+{l?7@ zE4;2#kF`5zE6;3q#t=W&pe-AkTeSo?ToQHF;_=pcTiS3A;*leRI_P(2EeRJ`-#dM? zq}`^cEKUj!gKzhV8LTx)@6{ZCVtil*1Z*)UF;$l({wHxda6LwL`6fJC%R4RrGqw1 zmlOwzTq$`-Yi<2NCK^ger?sogSKb{^+mdqhZ=`gDORW|#(0U}039AJgQ7j(dbq&h> z&)LM!vuQlo@yV_q(o%l`=oRp+%x)h}ttWBA;T0CDO6Zy(n>HRbo)xdk<|s%p+??|^2>E!Igc8CL@XK8h%-3PEF99!rxOcIpAy1vC+q(db&Ugtd zFz6e!F>iXwm0btfp%otm5l5g|rWFY(gsSTy(Qyzm-y*mzvPy;_o_9dM?T_AG6hzg)g`UO02u{AjS=Gw))e`mt2D-VSa2K zi}6P@hh4Ok1-Qv3pM?IHrAdNhi`WpR#vC29e1q4&p%hEG5dwCct59&9-rN#g49~n% z8DYne=vozop`9N3>(|R})c{EpYtUfx0MeUPSy^75y1XPWMLo0EHAVgIb>!z>(0^VI z=k5BmvUD8_Yyf~9_>ClFc(PQ^K4(_fT-o&M zxku2$YQM}isx0%cCCOH_D`;+=3*BxnTXoDCsEga4kA|pWn=qllL`hRkV?+I;TTf00 z_8`I(h<-3qkJz$Rf}9BF~7jA`ckS zGh(c#)mvL1C=#F>vA|4H>&|iKC)fJ4&AnD_#Z#5@2*0njR7c^_vqe@$M%37gb6UA+ z5JppvNzuuqsSi}STuI?XT#OO#RT*zMGccKZdTd^{y8b;RGt-7c*lfEo>JZDRzL>$J zYMo;2)O1@A<=}%<+K}7mt-*+2D(~Lj6g^DhE=jD`)ZWX`8T?=aMslNB36~AW@>Mhc zR=)waO*`2NFNdY}{5CjjlwN{ym3HVhY9=foBCziEqB*Lqu@`yKS3T}F=*fk*p*|e` z28emw2M88cg&8yY%6>pnUv4r27zktP5aw-b?7 zhYOEC9q6YKQ_h=UhVO(;Gi@tXpL~qFPN<-4)nf&mQ|+-xKj9u>whE7NWu%(`pia9D zTDR3T4v^lk6=nBXlhEtU%XUvl3_EpW(F81U^sChHVlHZvuwl%+@LqZrc}#=#s+M|j z#u|NZ*YCoc>1$@4g_eUidK}KOV|8a^4(5)u8TIQqOi_&hc+W}d`?Fz+^jYW1&dQ9E zFP0AC38E~vL3nxy2R8YJfxP~Luy&y+T3B+ zp`PsGnwKz8^|%yk-L`Cu4!U3JTqZoI*$PX*-XY8?s%pe3jd$4#%^6)w30JZD#XbQ zia{LuM0!rKCI$;dqQs9cYPuzk0y)pa5~F{5Myx>+;}lP!3@PhB6^JeU=CS)wNqLwL za)=ugEz4R%aixv?pNbQYPDNr0HXL2?lFMNw?4Ic!Tb?zoy|E>-TxH+3d0RzMJ*7y` zEl-(69_w^i)za+OXE$OK)$Ti7leIHAm6e1A;_#QTSaBA)N&yC*@QCPW+UG>Mp9vo9IJA-VoCtyi#dW4D4;TE2d6N8v{nt4{lR3&-T{r9;B;Fase z`>=4i_ps`@v#%S|oOWTJq&D{Sy)LX*xQ5CDzP4i@=Y;Htqc9f=6AsKr9*pY?3po975&brVo+K z#PG=cfgJcoLYr7dLkQ#`OI#3#PdFl@4^15@@mI5{hmzdqCWeOz(F)km$VV!tbgR zs#`8~4wo+l;(HT!!vAt6S9Q0>M^n4uJ{Io-m3kS#rnVAKxSthgI#TmMJW9MHe8iz6 z%jt)am$q-<=u#_oo5!4qy`LctS&adh1Fw0MO;EPcJyE^3j-9aNYqq-YcH~#SNthPB zwH1+U!$!o57v0Md=gl@8EkyZLg(l4ef2h!o?dS?)N>ft$X~Av;W?LsA3C=nbBdw5^ zqsU)3x^c3)8-E4}liuWn{?X;Gh3wv)ZOGO9KLJw?ZgdaJvpIOyiqhz)O%A)lIL4>^ zXW4EX`##Fyz95S^S45t4qCf;mSv-zu*LoK>+PFkqIvtURvjR=*v~~zEi4~w}{;fLkFRoF} zUrnScid@I`hg_;PHPowYU#t#92sY|T9)t-D_*2L#eI>*pb+Kip$;KOU#D7X-!;tCP zjC%lTdm_m8RAV+#4CIUocz?YK=7B)B(?7_R7ifmRG~NNIMqcbB-vzcH8``RL7)jJhG5tf17jx!-CPdU*&bZ{(pRvbx?Ac~7@ z?k-*rab=66k2doX6vi0^}1ZLPy7hMuff|Did6MQ~edI`;XQr&Mw*<-A=e6L|ARJ<)*5#BgPsVo$Cc=&A;u1s;(PxqO%vvn*G~d$IH4=oYomrjJ?n+mqssZ^Q z+zy(^x(Qn!KgdHJ-|nhT3@=k(6oZy~jX_Ih+kW^-l>&_zjJ{)vKWP^ z?~Cz|M@#lPaZE8Rrc3H4XK%GVGp~2kR-x3kt29+%q(&y26t#FQKXIJsswW+zO7(ocWw{ZLBSu5p~L^%N(Rok6!u09T8FlK!9$QFci3)F5m$CxM2bfwql zRcePboLEeNFvE816*&Rr$E8^8t#6Ij<|sH!8h}tNcRzZ5>TjXr77Eh4KM}MrcBtYg zmA3>~A9s*~;q7w(cnZTKI)P3N>4fTspJGWL4s)Q2vLt&CG_kTqoUFWYF(YF^BpkF& zo#e_2bxycECShHDD}2Q`z-S{4vtL{pRo@CJ-uY}NoE(`u`!q)bj*cnUkEds```75a zA_7JKf0lft9?R^=SjJWi(~9vlX^gV6m?lKTukpQ;(TJrfM*pw5=&MK0rg;L-VSg~s zp-9{80WsSZJ~F07)_6uz{MKB{8X0|_b{A3r>BJlkHMPE8JNN8RR)JX(F;4 z_|W!Vw>c5Ny-LlVjfka!{+orutx!;(WB%uCv>haQsWYoLj>($j+LGv*Hk^ZpxWDGW zgL|o~E6XRmgjjZoaPx8Uh7?km%QolOT)YAo#TSO=w1$&pGYa;}Jq*~YjMccC5OrJC zOPpnUOhQ(!d{eth(4D&cZ>|)Gg@_NU!>7W_#xWK;5ta$c0M@ zCVhXUj>DuX2r(Mv)~u8J*X0ork~dnF;LkB8Zzrac9h{XkV@hxlgqmhsYoaxh6SbUW z!i`4+srD^(_fOE`o&hG&B?~~pG<1JE#B(-23X}FoDU|$fqq|T%ANsuEn9b>=2lSx*_XNriZgM$ zJ5%MJxMjd@hLbEm1F*( z1zIGsz}wOS>9N??sy&W2H<|Y}TC_)mWH>^EyEBw#zLr#yF#wKMm^bif79?#E zM@;|{8&I+x*mT?i(*$4u{F)wG5Qqa`JOVDbzQ;zi2)tWZ>Glyzl2B5tKv0fdh{(tw z+-F3GHY;AkoaioTL8q8TT3T8{>e|~=M$SCEncr!#oF;!WfAk!#zP#5tU7UBvDTsfw z59#ZZJ6sj2G8eZ{1JA;bYR2QR7Vmr%qYwTWsIpFW_f}u7c!Th>HKeeMvBxM%#arTv z&Rk}D^{9GT`#2v=Q+eIs%#Az1xl8j8t14Y-`WmzmOIgwgj^Vq&AkdO!%d3k({3fjk zVVi7fuF;YD(1nBac)dyVW4Z0hrA|D{c}_$_|40Gpc{)z{<uj_CN*dow-6vUDS2Up@CYkf7W*I&MN z_7F$R_F1ftj_DnHg`Yk>naAHFZ+7-HZ$KOvvk4Ya{Pg6VC!PNc`ACjN9I-SSHpSGqR0*B0Tu(ua3hHK1)V(mBCeKMnU zrkK=18I#SSQY~U1#aTP^7)_ztyhWeL6=J34EYNoJlJwq#?Qd-_6e5WP@yo)rkuclU zOeXttxb8*Bx&udq9%eiE6njdw+NzlikpvmmbVk-kVg`02sZ2G)HO5Z}qQ1_+8qk(0}URl$bV}V5!U=oanw3(#Go< z+j*kQ#Zlr|5Hq0`r?*o=)pd!hXoAh;ld+Wv)|}j$mUc#+Gp$DpYi#}9!bS}&ObP(G zMa8AgzM<)hm+Q2iD7P^>7^1ERRbkytV2-7A;I<%oorePC$PzPz($Uo@L*WqD%x^6! z56Ho++|n@wHG696+k!Siz#Al-bdR@ATYm&$X!$p)llpQkl`w8cnxFNKjzKrJVT+|7 z;1!sOlU_YV%KI4xda^ki;}Gv^YrLed5u9de{nGpx?cTYzI>dsC6;;dTES*^~qiSKr zf|*tGXD*z*Y>tJW$eu^_ zv|6&D0KwfNyy^*D@{jyN;`R zrv;oV)b*wAjq1|-&be}rtV81V}8pf>=mMd8Idld+r; zhL{`4#4T=5%$46JjMGtUVh4|VkEKp)+QSV;qo{$_KsoSP@Z*@8Q zTQV{RC5Esz&xt5!wt4WuDfC1{yk=ee7wNBgAkFztNyq4QnWvR`K{mF)t}`^?@;96_ z*Bw3)ly4M)M+{XC6}uchnLT})F)J7xiVKaEjr3TE;m!z2*8O@`T$3hmNL&$HwZ@Uf z9YV!Nn*kaVDxug~VCI=Rb~wXpBI-M+GTC-EB5~BzMMRPzZG$(7QqEw!`-09a)NIP3 z`8Xz~E&5C*s)Tb)26l;KQj~bMn6uHkqQj>x3x#Hhv_q3tSa%2;eMrcBv-#Y%wmKU! zn!!}V?le%AQ2=d>J;2y?Sv8E1MJBjKJ9sbgEH-7&C=%D#p+ka3SHR=4=_Sq3&F97$ ztIwDo(Odkk+z8DQX^Uy-`JXE7*}2ll!d#kjeU__V)Vg??*xn8-izYe*1Zj=wsE7|g(~xlL_)@n^)mCHZU;c`# zT77(zbB#K`1bNiNRY+W_PImWEFMWWngCTMIT^#B!dK@KS{o%{|c&c878kK%M>08q2 zr|usjle)45nGdgh)u!#}9q0mb|L$62K9!%0k5e5t;wt;;wGz0DWgk+}zD;J{IjVOl zak|j{Zo3&1ciQQ0+)g8PDJySAFr}ZCiHJ%+9Z_bNeEll4MQ#f4K^K4W9cJ-;6c>hD zeOo-+PQ34N(&;L1?+RB=7qx#CUv*sJ{dD@Bvs`1$4-E&*La_;S)9`JVp&jvFfODPB z_L#Kg!L#|W;VM*BbOD=XaNe)B>lk)6Ezn6^K}-|%(?4@btXq2i%{ZIYMO_yeu-m_- z`!9Dz0sB<9+`7?~Ia(IP?ds;gQ;~ls`Ym1Z(Czv3GA@qUvlB0@`ssv9o^+w>&Zhgi zxn)x*KtJWwfQ@wl4UL?!U*Cyd5GD6jS0A7Sl-F0e&qjKt+qZQ#?bF$ccDd@zLXW+l zbh`M)DHKoMe(Fz+jGxZ&pd0;_jBY3->er9HMZ}%+4OQyb{;Tcs27PDu=#sP1@}b^7 zYD+f+c6tm})i7%M>DCV!1M-$jnZ~y9d6U-n_vmNa+TZD)4Y1YkJU=4FMwU@ z)y|pfA6L0EGsNJgxv3P=T~rgQw3GNb>YQ(!{RU2*Yq>Etp@^IshRj{GVr13)MYEwo zkDfVyh}zp@V86BbX|u!)GRSvnn&^>sut5PhrY=J{CoE3R`aYlL)*?^9B^xX}<_Q83zs zB+=A~oEkb8e2h4FMxK|io@sRVSG}%ARqE+R_XvyubVTSames_|on<%? zA)+W{5kQ)oOMGh26bQZaWLS{TZzuiKNcvRO?=jcFoLuvqDpa)16XAfxNkG_vk#?1a z9BzH>Omj6{Mr=rIZ{J|#THhq@FhbRjzYvIy>}ZL8uV@N-jzNe0%{Mw?FReD&$y)vTp3TC})lpkp^G5F4MCVf^ zh@KFbrM13Br_C{U1-=JMQ8hCebhdK4v}x$ZO|(!a=k&ucdh~T+wI1S|TdYr@qT?sQ zo3M^VRU0=|HMhV8(%B}3dwb9nt)0|@@*$zBK2$5$fn#AaDVzrGVz9YcW)e4tL>w#2 zYqF}UIzm@6fEqAIS+vt7eOv4FJ+@3QbMDA_$LVgq1$BwtyvV7@+h%Cd^F5YWf2>h^j>jVAe} z2~$bb*P63kz+;SSUu!=9$F?UEmd;=~~V#Y#*}MLgb3Rt7c-GpQmf_+)8g_Ly1&G z<02NF@dQFPelic=K zB`|MDIC%)T9~>pirE`hlB$*9Ija6=FEeUb8Nu2H6y|KNatzPhuKyo@#&tTQoi^V)D zZBnCotdl|XPXNaHG^1I@!c^&iASq`#`8I*)u#)t3falU2Ln0lS-@G1JvR>C)A3|2M z8L5Kii_01TAQjmQ+I-ItI;K=I8%Z^URh ztQ;9h6HKwjbZ)(K*asI^cs=OQ*B0?zq!4&##hV^9XV#KG^8uQpv8lrpw*|>9D1S= zePVEpPA=*CM$|FDM&!^6nRf2Uo|dJiFcYajV@q3bg0|=lnn@c0F*d~OtQBlm;K+)W zZpV4*)vf!{-4hx%x^HW}>#H`^Z?4+V2B4D-Ec?l<2G*o7d=72C)z;XgSdyjy@!`nD<*+mr&Q?} zV2(=&H3q$dW5+(WKe07%7OF98h)ogSyx4EOW2#5X3VmY7Tp8D5-BbJthFUi0B#0Qq z!>urz#MP_6xj{fALkWGv)t;yYOkf>}8oPiTp}zgHc9P9PJz|9~!f2}c$;gbU+Z;L=E_23qfOEY943Qfd@7qL3rItVCssI(SQ7up8GDU&8g z^JbGbalK!iJU%xo@@Z*DENk(P3E&i$oKw%NaSoj>Z~XEemCakPzW*>)xJ8XSk_jf6e%9FJR5x8hPDlQ=q9R)ik$w%F?s9}rY$-H0~1Zo6_^QY zRd26zQm%yyM8QLFiNN@hF&e~2F7e8W2mZ8E?klm@MKZbv=jFNk<>obtZ*L9@GPAM~ zOfvxCf`Cn;bW-2Q>Zzt zux`u?2KhEX{pmaI<~sUn_k<#0?(pqb@UzWD5eFr$wd(voxGPwXow0LEu*TQWP%3I9 zRf5NQ+Q$EFaIN2G|L*I;-PTDn z*M+;RQ~NK&lY+R>?ZU~WtmoI{QM|{vq)!c5N4^#Fim=G9kL$vLM&xfHhBI1(gyG5pf)6{ zGV{rJO;x46-6=gsmW&u(Ql^I|y2&~r9xaEdGKCtgrE+3n=r;MPG`C4s@?efO+$IIf z$^Hf~1|K!*X*RP97bi{Rgn~MSu~8iDmp*~S=N%E3IS17TIW>S=3h;A^%9>(M$Q91{I`fTs|5+Gr)#;(xAFe#h9jjItD(F@=PG z1e6mtj;$nQW=w@$pjlRl>Xb6~;_1KD&A9r~JcZU6dBR=rj17uzPzmAe{zFaaPh4_( ztqnAz9jmWZ&mDC39V=pMkTC@ej8CHXdt5;pSq{@xWo61PkN+Np;KL%Qz#L|KVVG~# zLPvncHNz^3KcZwzT&9>y798WEwAj2&7RSPDyajQj7ppWp@;RKkV9P~*rgE`fH!F3!kNDT7+EJk z-opWRPU_M%fRYK+!$LkKAUAmKeAw`vslgabEqFw>VPV>`W`r1Gs46&|{b=qO-t9Pa z$pm4fSf=TP;iLuAhNd~PXSMoJtJC}IKc)`p=hP9>02&pxme@fqxf)Gq&v?XO z6P^&yPNPs31h8jm998_AI7-X0N;%#jL5?AC)~v=l*G3JR`s=37nTk>1{HyWSd4Dyg z?`7w?{X@ITn%6oox%M791{TzGhCsH9ztCb3PEub~xTh$gkSL2i++RihunZt=oht_eej+llQJ_G_8cL%Rhd zPQ@9)s5$Jm=gKhTe}4s%N{Q<#IM=TZ+>BLa&10_I!I_%)5~h+xNeDbbNq+&9uhzGQ z=qpcCdpB}*sV>yb7Vgz!n&~=IJVB6L-Fh`sa7zsrwVirCu4G3a=bk31b4~hH@{MS1 zYtnp?0W%_1nIOzWpSn`hV9t`_zR! zW?oBS>7cu z)!_6#YqmH_udjjhGUv^j6oe^SXWBl;IL1Ve6&7=Xb2jYN8qmIFSUGow##B}b!UOk& zvoQCKOJ;s>jFbY^pYF%=<=0bOOOmazRorBnOVwTr1GR|H|AD)`*js-8F-9f3POacRm>Z~CqgkPw9d?g)&r;=Vf{ z;A6ubD{jfFuFO#7GSq9p*Fmr$qCXUtJFM&QZIkqVOQEAuSycsiABem(7MjrypX2MTbIy@Ub}RbX_Nq zG3=OVr!f_}%A>9vEE8q9PZ+w*uPqtm5h?@Id0h-*;?CK*k<+|DhRMe#V|5TBBAR%J zo!B&9#yC&lRV2fhXv*BqDXpdelFgjq^q6eos>^Q9z z8uxK>4Slza`sQMp3YbIOw#->bl^%z47MKuOUG>5l2JSA=F&dXP1?>1nrKN0}Ty_572#4VW?5JwXOOS?EZ} zV{;bAe2+2DgyYzoJh@S@sj06QqDQ9Ss3u$iefp|vPzYY6+~?w{Zbqq>ZB%0pNZADG z{f1_a7FY&fF7qM{CN-<%hSp_UDYCYCjiuGF6j$C6Sxe3SmzWa% z>0+-Bmsit=#^1-z)Dvb?rk2%&8Ew0X;pt-jK4}YTjWY+k@ri%2r*BU) zd3|$fs}Clj5a$)@*3&$_)q(pwUDZu*bNkV4-@s_nl&s{)w<>5wTq2vdw>b>eXxs<} zX6GxwqcynP?9h+0cy*mqSO7ILDO>d#0wvv$G)G3d-D%Gl5Zmb%kz7TL$^p10A!V>e@ z_>!^R{=I9Y`p09a*Zw61Ci%lnZa;2kby~jnRR?yXaN74NXO$Y$>>jR0kHAR#%d?%u zs_->bclUO4&%mA6EmwZ#R>3(CmsJ(6>3GzAs}$47%g(_sWQF-09D#*T(gV&(39Ho- zU-n>i?-uuw3G*TqbyZhf0O!zig)FPi!GtLOiOPD3Kj#R;GIBgY_x$+Zcm}S0j4mzr&9i&S4;nIvdZ6sOg zxwucCZax<#yM5}FWYkAJ=YnWnuLS>{o9u2jU(b981iEbxinuR-B79Fck81fcS4JwB z1aeRo(4;Gz#q?Tt^7W^jC##IC{4ABb&3Teq*UUB62R-gJYUe)J+>58=XLgYs3-;kE z`Cz3hs8avTn2!4ckp29of=sn2KR-=XA8(oeYR-Ljlac0Z=B#IrU|eyKI6Z=P;jO#hc(xWT7^v*jooP z1>&tnERlsxA$xn0+A=D?f1+cYIiUA#gS2nD68CKbRr8guoSs^%rqE*g9iijYncpJN zxbPZxt=jUArMI6~!K=pLMz!J%eTm9M#Of`;ur(AzY# zJR_M~L-g^5ZIjtmtLB)SOw&1&zH`ozF?6fEk#4U!nm=8`6bDjR^>5cYmziz;O|tAD))WM7!d{VU<`*`L0A z_b_#GDkt-G-+Qvvo2L}?Qrq+0c>}U6rn3prY+IUgkJ`4DLYGXVl#0#Z$Q@U@atCC9 zjN6)FG(?~d{=EToCamXZ)&mO66hXCmI|Nc@w6_RYMu*b7(bL-21|7g{5G}3sqOq6Q zsJwfbV@R3aYQT%mK3zZ|Cd|}P3(hY{SHG-fNY<9I!ymX3ooA^;{Zh+ibV7-$mJQB~ zY*F$kMde?FN&1{$h5nzfsdRn2w^cpxJvEe_h%xfzxookcssOeq4EI+JbJ5V%F2v8j z(4C}9QujZNDRJ?ixo9smm_5+tTwagKVHdyjG`mn=IH*57FwNDgTl!Kq#Z0yL9Ov}> zmX=M$xCHQxAFCykBh5hwj2~Myc62G^;Yf4h$NHSPiOD+8?2A*~8G}tH>AhwON(RN% zgAlc>2>h0AP6=ShXG+3;N^!4K8NawP)an&Z=VX2ElQHgLQ*?45(JqK>>voj6GVPDT z_2=x+Sk3G~jH%tzAlV@`OVydz;_-^7KAGNz7VM)Z|{US-zQcdG?xlB7EuLVU`Z2vk^~vMhV|j*W)OKo0xGYKRQU(!bL;bY1Ie5$Jl= z&Z&&smXU5(k|>RuyMVHs>hsgkb_kq{>0i-R_~xezDeBpCu|n1E@pTejVVhkD2kzBv zG&CBwP5K)O0MoyzpvijOcfS)ymlY2%@u4yf*56g&$x|AgR_B+d)}jGt9=Rn_Whgf! z(YbJAeteqintsR!Z!YWSo}Ak3FRiQP5ZMvw8W&d<#B8Z7<-d~w`}>9N!h}@y?7J)w zX;?~|wlb`$H<_Zk5}AyG_F7FI_E-$Zm8~GAx=g;WgAQ}3S-YF2VEga_1)1H7X z49itxI%zj4(<3Ph)Sh=)Q+6>xitR3(LCS!gdzGta8DteZ7HM(u-58q)L;*OEr5rlFn>ho*YTEBfnJ3y9{H^@dULy9KRVRZ?AwyC*vS% zFHhb1E+#5ZJ_BWTUo%E6TXLW>|M@PU)lQPt!$h2=V0yTg7K7hf&%Gi|(3>nNRZn3{ zJy%0SCaSyLhbo|h*$-&bv|eMaBfd;HRCF|h-qJ~$k_}&BF1FsutZ6X_j7!x60=g7f zhEj&O4Hn%5bMj;%qJ#icIP|Mi?f4Flkh^v`>w1{xzM@XmB&0w1PgYi8fb+dai>8&G&*Kl=7_8FdNi z10VMY&FJGHYZSC#E$Ux_v~pzCadd_Jut`A9&h@pPyo%8U}p4efZW@)&Yg4|%uwzTqUOm9VU=568#D`#BVdR=Ftka`62Ml!-c4I&wQ|VTdPsnU!mwwk3`M6~55%r3CIy;m`BpYk!Z;KA z^J-ywAfeQ0CyB*=5onW}m#ma_6q%jYvaYN1sHL|cUVEem_@Z$%PsQ&!(<&0Qwg{xi zIfR@_(qGNP>SI}mIew|W|TA~vtL{atvl4JKk1gM zt9=~s|FRvLRrhB0d(Hwi_*5u;Ui)>kD2OHR;gkHaJL$apW1z+#9-!Z$&G5=cABFGE z<=gO`jc9~sezPhW%?EtTgG~8ev`Gjj&u~XRA)8{XmxnkyY+}gHqoVJzW9TUxUg8_Kk zhGN{(Ojf;51-h)Ggl-mio&K?FuoGG`>|hhMGWQz9`de$zc*I+5+xO0ji@VUyv){uI zwEaECs3i#a*&?m`#m5NpbVk4Uyjr}icF%CR6H)&-`D0g=UO7GetR##BSg`^W)c)<9 zo{Fz_rFJtZJ(Yhooa0yaa1ecgU91|9g^ZqdwQFHX5z_B^TuI9k2W+4##UVB#n=^qM zs6~is0G#^ePI4FK($K$u@0_oUI~k~Ox~H(&ZxRS_8-^azVUb3QY+W-#?mBC$-54ikOev(RlM#GaHCfhMJRb z)^=xlpDs1Pyd=-y!5&AK;&xgE$H$tX9wC$SCWD2lX5w0pLyV*nJdS*QFt;=gZAD|& zB3e*5qqE^l4{4e{HMfg`g(Jm8t2}mk?&&EM-!nKpYh-4IItF2Rr2TvqW{YAGf*;gO zfi&nLp`RWpLp|}aYo>a72IMlJBPH1y51I0QU91(JsjhhduG)?Q_Xu^}drmw8zQ?OG z9W&sxyIlQ4-s)VCykzx0rTmU%@nCpOp7^?Gb@@X%kb(5{#KN^2@eXIDovee4EmXwrCAY-YR-<67GMyV=Fce_+*r?Z>M z!d-Tki&J2_+uaqRMomzK3*5sJAuNh=QQa7Gk-J>}8LA$?3p(iBozAqbCXoBf_s*F~ z9c^{v)hRoj{S#YjXUb9Zrac6|cK?lF+tji0{@Kq7L|UOx!VNkbvE=iLx}eSg3yIIsO8Pu;sg`JgFj zrrdH7;N`|#5GYUG)wr3Ql64;adPX_~PuX?&`7`!_t*?9*rsSei-9uN|2uxt1);!g^ z)1ss*gVN2M!f=W(QA-&XR2dnFb>V__7~*JU+=hDX{v=AcX~I!xso$l!R;n-4Vf8<8 zEIe#!Oq#!e8#+p*RCVfd1QA0%fop$Hx_g!WEUXj3WTn<$l-p5Q*8|b_JiF(g_!z27 zgXDX7GpPC2otznYnvmONP5TMq1VlKQBgT&&J$Bsa(PiUCjVn8H%$N~lM~qcp0Dn{3 zS~;!y{XsS8Jl7cYWUi|?O&Ch%|9UDgQYfv*{sG`&);zV&nWPe*bM_gPjF(M**inR& zJ%uAY6DMkP>S}KiZ@Wylws~0((y&E_VO=B|uNE6f7b^oRHV8+6+qnES`);H;71z0k zj1TtgFlJh zYDs;5p4zqT?u?5w|B{+)n7@lrPz+hmkw2HM{A$mIr(N;=pFe$L#kU_;oU@RobBda7 zUsxmWa_uN_OQDQ|9B5nHDz)HKb2ewgh^?K&!ffyz?QLlHolqdEVFl#{i)8B-oMh<* zwQ>a+qk$!TWyIu_q;eFnD>Q{haxgBWpj3q}!s{3ei;qX*!f9LzDTjG9Iu#zzc7JZ23R0$=ls;=1Hes`^1)m zjoUL{2;Y6mfK7j`-goS*wU>Qe9rt@9>7NIyJ$=^S{^5kLr~Fv`gfH$_1AK&XZwq)# zt#NCF5lC?+#koc8l6GG^x7=tMmu%Hzsvn(j>V_Yx3m?AY=X-C+`Y7erz9%%j_WXe1 zi|?2-W5(&TUzk}QDta=v>Va3=7MxPPId}E_gSzi9-hX5MXIH#k=X@&T_9MRe^y~L_ z%y?>#qv^qula8(Z;-Ql&uNZl8xYyMBj`SI9=JnU^pV8L8Z^HAFd%f|_ zD?Mt4-o4t|wDOKK|DCa*-|X8y{P4in zf4gVZtv`PG*P|}Fv~Z4V^6E$W2U5TKq-IRE7JIc@e-jp)rmhk2!%-SPT9|Q! z0vcZXE$$Eu7xR!UKn^?!eP50>N8wOYm6IwKi$y|f6Kh>8@x*4WwyM6x&vt4AJ zfklHpXO%X)6c(CEg4T0#oZBLIt#Xkr-m-jEYR+EwfKcPwCtfOA{Bcd7;@V@5cW=8# zu8$SrK`o}n^#Iq;PR@CKbpOz(q`&^MdH4-)eDK5P^&cnwzP#YoxrHfn?m6b4zgv*L z{qwqa2XEf9cKVy|`__Ni@9UR8-ck7Bup2M=`k#qUA9-cfik04<=AZmR?@xv={d;oy zd7~ab^Y>>Tn?3NFQ;t5ma_zd0iVG$m?E1tbD^42s?x&LmUUm6-TRwEIt8!lOM4!xO z@;@ls`t0Ihd-unBU2;oP{`Q5!^Ic>nAZKAy~ia@Xg#`Vd#y4W1nysEcTH^u-4$z!=-hWf2Y>l8+Y_Vga@giM)cK^E8rP~eFS_sAY|qLh zg~mo%cG7$`ZRFLiyTRYSCgD94WBchV2J03_;6|~zeoatUY?<#A*T~q>`N(@QVt+iL zfLyd97#zt!rzpr0O%mG!Am437L>1mTQ6KXcqm5f^RwW5c1Y(vc{3$!L{IweFM+u-< z_*YN`#g>N=U6E}LZpW%~-_LcaOaJWdKiBR#Ii!|q^Iy%YGs$+J*j>?H2rBrO!FF?O z+M1bb`J(3?WaL#XD{}^@rTi0_ckj2^uKul>*I>aoVr&Uen&ex{ny)ZWZZwM>|vVKCGPiC-0$bOp8>H9xg7aNUgRzMPwZFy zC6d<6)hYFexR3g^QwlRvG?@zDLbH3t{g%i5M#cT6#QnNCI{!D^(fPl;xZjVRf1w{= zj{C`w#Qxv;&C%(bq-#PgQ=f|Tfyh@ox5mc>4uO%&I;4D{{)AO#6Eh&&OcN4fCeSwqB|8RwFG&oLODvQ$Ou-rym))a0kj2-{x{~ zG-WHcVhawyIcco-Eiy06f`?@`O6_{c?Ws2@ThH9mMJ8K)VY8>cxu#9r*fnC*QCm{o z04ZNB7`v)*ePdhfyC7R_;k=AWk2c+CSg=`hTdG>xS~2Q2e=4EblQp6~?k8M`*k1v^ zG=6LN_2B1IpRdYsscj!3^Z0C4j%Qk1l^-}EzW<9F|66Vzx95{Hxg*kuy;P$&DuMX;zBwU&NBru1c{TESUy=D+X zzkn(l%wcpmF0mfUti}77^>^C%6Z)^%F~9Vso1g9T=Cz+sSqvWs|L&-aLtP3L&odT| zLf^K{^9B9ZqMhE_u&}+c+85$3woPm)VZyS1QFoSi_>t3L%+3@g&qW;|?U=|)O{ztA z{h}xTxOLXf*>8`Z>`Qz4!8_8Q%C4=PeCuVmt$O#B&tLUCa7p;*ugd!lx@vUciRV1r zrRwB2_C9j=#y8qmuXVQFUhX|F^v$%$fLH@Fn4jHi`Flj%fAE9RxQAfUPMLkRU9EhQ zR(5&sxL-%ykHv?6k0r>e#Lvu0lLubC(D%fhH!MB>+0x^WshiaM;e9Wju%YkvZu?)F z_Pbjj_3iumlDfnL?-V|KT#f77ITNe?amUzihMwDW-J<@Np49DD{G6J$1h#UdT6Y_` zgIbHlYl{#7VmBKo4)~!+(O-mv#AplGC-$e=51h1S25KNP#>LKRDl&)`WsgXs} z!{K;V@-SrA-*o3=$L8HJ_@1#J4!Q8ol#9-q@rS{AIY-@gX4SO=ox5jV0@$fGd1FV@}4k=TCnOmFe{@4ZxRET}w829TI_p`fg&PTb&S$Oln?d!@v zd!cywA4i8m&z&$0^8)RcqQW!~TOP41Fj+nuMwXXrq*7j9@2{$F7Fj_DP@{{FHDpKN~N?(id??&&XXx%Te!ruO)v;6z99 zzBAw5vFG(oe>wX2GbcRs-uClDzrQGB+N!@DmvZ&edvlKO_RsxuCfzuA+70jK_`fX} zHfYzU15O$HKz`is)rCw1+Xo|2l@t9y^0J^3e*$ZkZY z5qVs)``j~5-u2BnPZxf;@3E8q)#I8UPM&hcZHv!%{+YK{y!f-@^b;>x{npNlLpxLZ ze4bkua{Mi$SI-{Z)6-H@lDlXMk?NJvObNKEV^A+bxBq;gCoQ05P!DFW1jrOk0TK>+Id`I0^>q%7&7)< zdY>I60aRw^K!of*`&WV-2=Ie{VcZHK?cS*Jm!tE(xY?5udNA(ijQiQ2r5^dYte^P? zE7SVf?>m3xXMcZn!wpw%Xua&Z38xeq^&<*G6?OsoFM_QS-B8YBNE=IPI|$Nn?N!7t z?*g8q2%$<7lvo&v9 zyv29E*<|cSBJ_L0@NYL6%Lt8xXL-MgQ0eF}0)%&YexC4dw+`bpLSAx*F^rIg1Sy}8 z*uBH}(b-}2=I>aME)jm$qa$QIPhu(TUc%&GHW@EdVYNIH3aDt(pblfnRK!(;Q+U3e z@FZai?`sIRmGMsaJX_YOyu{z1cz>TzJ}HE3 zi$tgMavb5Rk`AMk!u#<2*_00B44&^@PS0C9j9kJ;JSQDZMxF}^BaZDbW)c?iJdxn5 zB@f|h!ZzNIB|Kl(VSGo}%k#yA{0$w(hwD3xF9|<~_~&gRf0hr;9mdo^hf&5~*YQ+D zn8^^9f%y(L)N);rSrn8Yy_knN)aQhoJ~P&SKOEf982N;qh%9#_{LVLB%vl zxS+#0k8lCcrxHTN7j+n0FJUM&j<%>QGDQBU}W=XVIFUrXVH)Vt{g?>lblFrFa1 zOPEERlQ7^GMugD7^Af_{JfB6_PWU}x4{;X}{&8oA(Ty_R=I@id|M_m_|2tm(M547s z%p=^$dnJXxLc$vfx9*{*Pm^JGz<7{Q_I!u&!3%_!8KG_gvlh7~`Jp zF#bijp11(v@n<@W2M8a{2^cRBk`HzmfBd||_$y&2VarjWfKh)`z?kI-80!e1%?lV$ z5hmsa3_sxh;nmIMq%7_~59bR~RS7BGg8{sGeZ3AYXm z7>^JxA?-ZEOw#V6(iPNKK`^8Np?`N64;|<*E~ICR2s=Ju{^-Fno_iBk@VxFBdcpHn zLZ1&=WCYK59mWa#{Wrau&GP`BpX7NZ;pT5x?S#9iZseW;AEm5z-ftj-Gv3u$1^$2u(asAoTAYFy_+Gd9wmW3gJBFee_cl*pV{1j1h!0JOQJMh7|F)D}UGb3$ZXp2aIu}0>(Rpr&*dU`opYrGHy9O zU@Y(ljPFVOD&aEaPOEg@o`mbmDrZh;V@SJHBH6|9&qkl#ujw!1##B{?F4O67J#oRKk^fd$A>8{6qsT zAzVx2GHK+cJm(R{Z4DT?&1^NEy@VB{{ed)_Xkaa2)=4a8!eYWi!Z<=TBXTlnyL`_4 z54$j6Os2p!M7;G`z<8VIOor;uyze0Vvz^uwJ|%p8kOmPFDCAQLSw#hN2AT%-~aJMQjOF2g;UpA43nV1*Da3tBxR!!1{2OavAH(`YG#tqy zihWOudyoAl&+k~@i(<+kK4c8$!$!iTgtPfLhcISv(AYC18jg>9pC9)gn^vB`u)ZG= zQ-;LX5dV9^J%l>m#|#MtjgHYlKPM8uj&Kwss-kuaRPFzTu zu|ebY@j>G?zCBO4>fWHypK#~$pz#Fpr959r8BZ+^8eb8vyq|Ii7akupZX%pZsA>rs zd-?l*bI|yh@VAg8AOyDs4bQnjV>t=-@vaCV;_`_rrsDkjg2pJqR-RKEf=2Jgppm#H zX#8tI(72iSiwVcm$eRK|ljf5d|VmFP;BwR(~9-y2JJcs^ychGp6 z-dr;|Xk0`@H^M_Cc#Uu(Jz7UNW_8eLAq1#o4WS1GoD^uJ~n80N%IY9-Xwf?bkKO==wQhBl!qTi1&!yn2aQMQ?dODsa~MM2 zUp$Xt<8Sv1g2ubVU3ETl_lKbI1~^hM|hs|K4rfbG+KGSh4kAA z9~1W@VSK1*vr$UHQeg{W3e z{Oe|;kTCoT-mlmkGM4dDLs-9Kv+*VgUnIi^gl;4d9kCfOvAN{dCpT}2%9&WQi&Ubd zHV9*Kvkwt`o9H4fhU3h^e#28w&Y#?!chL$LN!ncW3Z}LDgL6qIETzJYO$$A1JtuL$ zL1W|kP-EL-*d=lkipU?tBMK&sevvk`zzSXIb~skIk6#N%rdF7P{`T5tZfNz1{+1kB zg&QVEKhfcvwc?mcxpH$U9Ozuq3a4K<@T(}p%cUcl!=nG$GR5HtO()yJSp(|pnrF^f zv|uLgzW+d`d02-mrgsii5zfm>O(jaWYU!#zoHtwD5zZ?dFpT%%ggJzHgrf+{2|zNP#ogqUMmi<&`9%P6u^jX5{U-(Fwc$W02<1=>$&ldyL+y3OwFG4Lt?+s zVuvFf5=ORg5JZ<>d^o+jj|u;Dvyn>}`UG=Lm`zyA`#i!5o=+m2#`E!nPkHY1f_L6qlyO~A^)?@MlZrmJikV`lQ4q! zJi-$^xBh>;y#;s`$=0?V+}$C8;0!K<41*+ikR&9yOM+_%8tDW=1QLkvxD$f=;1FyE z3GVLh3~uYYYs(D7;hgup|Mh?0%ysYQS*xn6tGhR_ySus?F0$YsFc05~#wX)dhc@Di z6>*c%<=tceG{m=taQs|YTg*)^!7F%6ybn5-bd%K@iNgds$VS2f3RG~Dr^Lg{xyeLm zPFxPAcZe!h+po zY^*yclMlPxB*zXnDYD&7uE0!4fM(E_{I8UE+36-rUhG)4+Lr zlWZQ+A)ALLV=y~OJb(@PJtVoXfrbSF}!Z3(IDpIU=L|C)I%B$@ep_DGt)ynW*P9rzk)L` z#lu7Pc^RnUNeufS2kl&?Y$!f@o`+=l7`TaF0cD9_`+G>Yg$5b~u(6O^Ti_wKP>jGC zQs9t|Eif`4jfOP1566=|WMGPiJVT42H_#nRJfvxcf$QlWvL8M|%tjCCzR5#Qq88{L z)Ra@I&{TyU+t|A824>>R;t!#@c6vzAE&~nlC&3%)?e&m*`waBO*TyeHdmr+UbB7Jw z!I#H>Mz0?6kjSG3@??3)CFl>+&T;(t_!rjxAgAhuL99_#ti00h_dFy7N_|61qtAZ- zpLtcM(pwW8w_~pjfzltLDu0_dE&M0-r@!%#u3!Hq(CBxdQ+`0f{GRd;G!lisOa4#s zKN?`!!N%o(v|I>f6~Dn3{~4A*asf}#)JHEE1N&iEK?A4pt?{*B4BRAcQOHxmiy81P z>M4UDqll->EbJ*4A(S`?icx1ZYDMl5_(L_8ZA!j06oAT5x0t6UnPolYRe1wz%Xvx> zSOmvlA9=+)yc;?ZzEVGt*b+|TtB~skf#!6gqJd-!Pnib|;Trio=t=kpBdAj!63LIQ zr+Lb{2A+}z(e*rK1?<7EhG+Fz0IuNoLuZ%)o2jGx4WnPx&{N7c_LM@f7k><_@r@y^ zk*BPMUU)0mg1-%isH1!@jid_7HSv@ea2x7FODOZRr{skh_<>D5<)>z>2%PcLn|n$h zD>?!tTX>2&IN^IkftDPuUp(b4bnfgaWxIGvI+_I&p&_v~yu$Yj!uViDqiJ0|C9}Jy zoa^Q(1JDs@pB|p_6oQG@+OqZJ=An&IZwREUGMbz6eJuY19j5BNxLm;J?UgxFn>}}kQ>#R-H$W$Lm)QD6W)jvzsj+MTWTH1=d z&QjI#Qd_wU(mr-jY{vNpOsjZRLD7v zXUuipoh-}cwVlA|yD?5Kk@|i-rnwtx&1!d9J+5FCsaD{nR%La!LS=213nP9_x6t+H z3H&ry_s`Us46{(^=U`MP9=5~|&fGg=P@eHF&0pg?7zgU4esvoMDyso{`v08NC{Rvx z)X#ZKCVS%Ny}BL8NzXXO6EI$5vc{dfNz{FTGS$d& z{Syw1N3b%ksN*E3&dkinZMdn^)euTYMo12y(8-CxBl<^YI;nlg>49n7k7JUv}@n3V-Ls9jy3~2cC_u-tAkx%Ta|BbXKUNhy1PS1>kj=*1Dn*J2X*Fe+!V7S zh83Bq6LaNrb{ml^A78c1d6s7Oq- z`fqDn!yveOoVlz2P8c=QsPEgVcAeM(Y7&e3+{^xAYCu2SOr(g**5Lsr*~NlwV13 z6>qnUUq7onr45)Z=f})y{+Zt9$;D<*DY}MVNpKQ>8{F6OD{7;sEI{9Hc(ab*dZ@}PuiNb@$M^D!2ijzM$}(q7k|${r4pm2K z(hgSP6JW*|P5fds>7J@dTiB4qX@8og$&OW;tbwX4G#Rx<6L**lE!S$YXOAZR_p=b3 z!{36j_&(5NuO>Ijc}bHB26C16k_;FP?w!44qmh%SXBRKI4<&58B$Id|{tj%_Z217^ z?q2e`o0lZ@@RB2ti}*0Sfy$I$A-9k6Zp3HM_3$e>Uua50zteC_2!gM~1-p7ldDueS z3@w7zQZZ#V{a8)E??3Lxvf!!=Hf^7~t$BMMoRh zkN*vdkMfefx*rq%pe9xuedKp}ReoTFm((=U234Fh z#v@jH$@Z1(dUT*M7lC@M(7fdO8ZTM4p53+9OJ3l|qU+%(v{=V+LPIE5gcGlY>39=k zC|6$TkNCdKv|K@!d9TsfPnhrVp(Ees{-^lcy2?K_w)>;y%1}O^a)qWoR8R74@RBa* z1!xLo;nGHS8TaMjN9wN_opp7)I<>+FSg{IilIoo-l~Amn?S< zABJX9uOa2p@Dx_VKFC+bTLwcD=mLyI_7)dRGQ5E!a07mW{AIl*z{*>$LIP}n575Kf zTdG0}C=4TDCai%^a26iGUMSqoTYiRsPTtbLv$u4I)A;ky2R}yRa`O&>R{K zBZh#%-m-;Q8;H4vsffNri&2;pbj15$U(ll@BOz@WA z6U@Pnhw@ae1pfHhkQ-XDf;MO)*o?ojgk!zbTW&$2bZ?15yOZ049)rvHrR29Bpo71A z%Wzl-Rp2nZhNPN&RQ!Vl(R^qjv^iXd_bfOAJ%(-$E^K}!m;M*A{&e=QGr?i{Q!#Z~ zo21Un8b)rdrF*e+ThWkU#><+{S#_D}^fFVOG$yI4nd;2ZN`=Gj@s6BKwWOsw`Mhz9 zaMqz6MRjZMG5?eo^&)?+lvmeqt0nVa-Xt|lEuZ%`uHi#ItkmgevkDf)icA|b-PMV6 z1miSQx?%cLRMn{dY}itrP7YHYvV6KFug+@#4K}>4)}cQUf5@4oYS~MF=B(;^sV-Zp zlieGtK%J3y|MrZ08b9eq8s~iC33AhEK+Bdkll8y+{%yJO$F$B$wLOe8=VGQI;ihvF zb6vJcmSuFo59p)UqAJX)S*|JW<13)GwbwS+++AG{gVnVcB34pGbUa?gBwpU>rYZ`oOr#D zI$~benFKQ9R)wb+%K3Bw)vA_>3^c6D zIEjIN*s7XSkJ((*WBO{M5B=$>YQ<91|4di!bDVCR%SoNLIq~F=<>V>q-rm2Io1WY@ zmiJ;BGj(x5|7IrVzu#WV+g#NwG4=U9Y~5>UJ3EK&*0vpnc5r4k-LXte$7!VceoSts zeo^qDGvz@^UFB2T z%4938dl^)vjL!dM#iE-hlr*nZR15y#EtS9WFI3*Sav8n+nZGuLzaT#HFAr?{tV3;9cRrIfqx2C^ApdPS2AQXXnYuGxMYd zS`n>&Zl1V;8}Yt#+C0g7X`blv_())0A9({+VMsn7(Lv+b3BZ?!S-&=k`9brh|_>=;$K@P>)VN(gq&}Ux`~2=Rz-P zRJ={F$iYXt^!AZqjy`e;e(U2S$9nn5UUI$AR>bwlPwwj@zq|)GKlsR_cRq3yjX--t7G<-DOW|95@{xiN0!Q=B7vKEzrD~!1G6|AP&X)`5 zx$^U6YlZoeWstCUR?1f@|LQBJo6!cb8_RcV>njnheWhL-UrB4_D^^y%;$-bB z=ZTZrQ=hWB?KNMCrEnE&q{0^(xk14xbOa4tV1Z&Cd}S=1`kop#|ICf(`pU+F`xBo%U9V-Gy`l@(WgCFc`gX+wSnb!|WSiU$Xj_9H+s;q?I`~P~_I|P*{vdwd!LO$b>*yz?DL9ETe;i{wM({5X z^B<^rkeCRBONsi+%2USh=2_-YPy=;_j(48TiLBd4iRI;NpSjMCBc!*tXzAN6}iUEo$jc+~h6 z+p)7I*iV@-ON}*B57%+}h; zdF0KNOX)M}(JFTnI@z#~t!FiE+KETqdJK0NuO57{88y69cOD~Z&&nKJCw8*#*SKki z2_wh$nLO619edA_;X6GT-P4vI%^KUNaf|7o9yR9i8do*zu9~Ec zdCwJ;U<1qW zt?>n5N~E96jW+NUe;vNURh^%>Cisb0ih+`eei8sNunTfS8@RL2PnsVvkZ-@Atc3A! z$*qAF zP#O{`dj!$6Rr|i5B+%YV7y(m=J;5Bb7(S+v3{(j;{+*w!dhaK1(GKVZw9y9|M@xL- z59>!iIRrk?$;@9qXEU%Cp8{VYe_4MSRnEX9d?{E54?t)C5467$XZ~66SAH}3-Jn!0 zth~~!@%~bOiobN8=r1KE_)8>u9X`U^N&eypr72ewoa`^P;Nv$$sJfFie^KT~sLJ2w zO$!H-p9QObz*0K(ZT^3XS8Lxj;$n<{v|t=%*}q}=RDUt?#OTdk{N)7xd)BV^m+%e# zQhTGnRDtsFfmkb!sR>q_{N)g2{pK$_&>iSvbfwDUcWq@?Z}XQU&=R&oA*c-p;n{X} z|4x6ow98*k!C_bid*M7>+v6{z_xj6Y7yy@{-d=xAx?&!{i+$|Y{r++vCc$~=2t(iw z+&JJbV}2(OL*Nf+3bt?tuKz*#L4O&4$X^Dc1JU|uHyDF&nB^~9q4iNV3ay7~Ssed3 zf|dkU$JkQHI?mRkJJ7}GN|nbao${BTPW#I$Fo$?}POc!j95$X|nX|0;9A7@@2DPC* z3<9t7{*v#4zXZW&ya#$*!#sfn1i=^mrQ9VNhJp|T*U5c`82p;c{?g(KD}g$&626kF zfNq83SN)~mHGjDR-5?7p!mn@!c97a4nnmCnC>u^!0HZL3R!nq3AzJa zjILC9{F(=J;2{k@q626h^eedv_!fAxr~VQEg`W9~JNgCeU;^YPSM<3*4??lWU-(NP z8u)_aKNRDx3P?`*lW!$_e$8G%pP;+ZD=LqF_Re2szW0|;Fb*C=YZw6U!R#X)fI^>W z6a4~qFah$DtN)q5N8r~l95S@d7mmLNCI(uNwED`{!&YI%=rS}ET?4=2hh-0thwvmv zfLuYZpli@9mB(l14iK9>0df>t!A>Xwb>T3a$QvO2^99JD`~lJ(?XF=eVOl|de8WNk zvICYCreQQ1or@+yI^MomfLw&Z#aSuZ15HGCzySQP5_ANfl%#X$6?6@nrSkZ$+$rtC zk0<8XR=-)Cbwy8Fl+?V&1;`lx02v75W(CO12?286JwOhP50C_KCtg6=G-xzAKsv#0 zd^$Xt8X(zR0^}b4AY`8&AZ@{(I=RpnWlpX02{Otob5c(E;Y>xr?q9X}DI`cz}70>~*K=1`IIon*D{Z zE`5Nxqh=$rn)}7mABa5iT_~s4E|de1*KeV;gW!OLa*6l|3?_DikNC$h-G8C@L*8`@ z<%5dD7Ro#*O`Hc(@ohFQl=v;Q1O4&ZzJ-#xf1zxEV7w;B7mCx#h2nDJZ{C07zs>(| z{fTed{pHj``O_j$?pF%b>mB@sN`ac3bqSQFu7MITEl{#xI@l1$!VUZyw3u6G z1881!9XcO959aU~3VR01UYG)5&;!QL4U|Ij0wn=m3GVO{aTjn83Y5%6n)(QoWP+w> z4#)@#lsSdb${LfuOM5e(2FfGa(^_LzV|Jj2VGP`Z-Q+H)7`6EvC?mhHW#~s( z1ow%Z(M=L4ZD2e!gaf&PWNID*KjjXR3NRDimJbpKa{~h^1W7iCuMnik8BF!sLDCK; zgS}CeSNSn<+#|Md~J`{tD8i-o`fQunP5*{8T^CN@ACMrnE#RN&|_#hda7$nw79IE6X z*_09_(Wyb)!eP%W36dM@gT(x|ASnWsH?Y+kgXHHeLGlTn!HO+G{pE1UMN+5qBAHui zksN@j(295woWm!g$15$8Dwd0+5!}EZHtMfvU8DD_vPkyBB8UN9tGyN$o1KT5pUAJ7 zMk|?ysh9@Zn1-vEMzA>=$8nj4R~bhXF%P|Agpq0Bnl*F!jvd*%#eX@{Nb9ezIH;jS zO4U_`u})kQ=iS(*A#|ppd8TV0T$E>0dS*~Hj;1mWH2eQJKuw#_+%%xfG|~$yRc;K|hd9KT?Rx{`x(Jem{)MG$yb;Bk9x-K-0K0UY#?|Sz}VP zkyDwkWQyyUeU@fsV;Rck?Bb%IFWofYOy3}vJ34l6Z0p$Hwmox{4OiD!)GqFAYtyr1 zcbj(V-69x1LeaCjz9eVYryld}nTE}*F z{V3?{VBNl>X{^-08%w3OL|uPU6Ras^wp#s2H`8cH(~v%9G11T6Y#hTlt-jHy>pYC) z9LcyS{XBPE-O!lm(#FX&HqbbPb(-k{j((5ukd|H{Y;QUhnmJ(+1d?lZ`a+va-?>(m=hO+!%~T-)iV7PWSDby1_lCQTTwpUlO@)ua>kF(bzG+Cv*P zQVsB$X74h2%vjz;*H7ILn=r$>lua0_fOw* zzH!VcsJ|K6XVkO~YBCtZOlOlOsA*=H{gp9p%$%y;qdux0_nk&NtC{}Pa84U$*K%P9 zY6mVBc4tCX51D0^94~zsZ1AZ+tY@1<^~?r1tYwQ(^Hsm)evkENN{FtY+~DK8ere(lBdsZ6iR zcsjeG9UUC(985PVCr>lHoYld3H2cS8wwgkDihf8gSJ}pP9qFo{rM+SOU-a6jenX=+ zGR@wu*CzEF4!5+Kq6QMo$mB+DwBn~paxkUMYJOlEfEzs*yEs@P}K zdHI=h@42bDz3#n>xli%pyF~7P5_tyip!6=?qG{$8wesPMWL)GT83=XoJvRTCo;!b> zU%q{j{JwROC{@cUue5%<#c~6jVIA}aQ%WLm=Yo9?42qV6Ro}sOC)ZNN5eyG=bj{gUe*+|%f zGqj*!BbC4D`8wsaFv#w<1{lp$&{&5v<9iOg7Mn z#hzeMEGFK4J6HzZ36@T98J~7HSVrIj-vmqUx51Kuo(FjyERBdyf26~of+YtugtG-g zB(hM5xE2hNG$;w{iEqIfe7(XU(xIRhA{#1)NUJI#@&dI)Yjpja)<(Yy&DA|bPNLPi zg-E3VA<}6`h-@Ah!Xu`vXe7%xlXD7@{?K@Sh}>TgBG=(Is5tFlh_pNuB3IG(e}qV{ z!y)ph4j)0VhJuSHLS)v-5XlV<;p6QP*?T8M3c_g6Rla+<5A+i%r z;Ge)n{2$=R`aC4wsdS( zs5C@#Quc~`LkL_*M^=W)I*pG>f%G&aR92!};61r}P-+pC!DdycG>37EL&Y0L;Jd-s zuuy3fj)&dEA#f%#RB{nV;m1KR@d`MM{|zcEV;Q)QKL*;L%h{DHLgf?sghZ~@25(D; zYDR=gAsQ=-Zao+(zK7VgMpeEA^nwYX;-lY`skjI%hhf>m#1RS~X5}y#KN;R;g=##E z&kBx)N;rwR(BfPum+(Vn6+RM*TnLqVa0I^*+FuHlQSbqOAI3gmS=a#9*;xsEcpWO$ z-h|3nd=IdbP$>_Upbo4j7YnmQ3zelL=0O&TO^}Xn1H2_o>f?;YM4B<43k#X!SK zPH>2YX3@ZU8aTrOC7XoFQzM(v5k~CL9#(Y1+JFl_H~tKIv1^!kb_A0(rMVY;m4S5H03puG3ad;cnnI_!pbX^ePLp~ zKTHmwCLS66`tS0pyg}CATsv&=O8*7z2Zg4Ea~uhi`S9`R-?Tbr@DotW9}swfz4IN5 z{zI&(%HLP`zJaU82EMPS;$j!WBmp&%o7f$yL*+{b&fp(_Epb+na6MPA@+aad$3G`# z!R0W?dnHWTUgM7jw7(uESJ6J?JCNUjRwEwD!isti_{-ydm{@`TJ-)y&p4)iz*TTLLtGHu@ia^t;uRNI@nLuf2kBTp8r}5Pz|l8hvKAhJ-6i%QD^@&y%-<_8 z1@b)!lcMAlP4T5^`!c%c5r6(KQK1Ax5)3052*0SpLg9K`--SsPxcZ(2KZHp#Wxo^G z0e7%~N7usS59%uhv-euSO;9WRlf$J4KN8;&o^eRhi9wTr1;V9D!EiZ+4&aMqaf`ns zZidMk$cHZpHl4$zewT2m4E^v;#)eDIap4k*Zh`(_PFxSJ;b)^$P)D>zRJgQ=4wrN2 z2UrNv#9P5Ux&}$iUXmBlG3aV2dMjK8-VPUAn2y)o%&b^zb5go_zkJ$}&*2hKCPLhy z#Fubs1-)SlaX9>%Cqjln7JeIK6^fAYkf(5j6o*&j@|BH{N5v!LmSu!|Kr0d#gb5{C zhPtY)6sVCaLUyyhuF6CHFYK}Ebt0IoF+%FXSbQvOgfYY&Af`DnxZ}sco7NEwvx|_H zZ6c&2tR(jbtZBzeY$IeBdWZNJROt{Q52!m4?*I#%Mo1aj{@5u(&cUQQT7*OnijcUG z5waL^4UUlVunHdydxz2~rwH*FA0bl|&Jp4V0r)vkeRPD}oF5_mec4)2K6+t<91e_- zov<2zJc7L#$qIjj_FeKBmHo*LjA5%_MC|{}9O{*%-u;9KaZHSmXa5Dcsgnen>&6HP z{w+e{q2Q(nX#)db8*vuQ!S9D_@Qm1ObA&v{7r|%8mxNaM8RV9uJK!+>674$RouD?c z*Jt)HDDCh*LN1nxlxmeDH7Qd$QeKyfl)B|3sCZc8jQy;1z*@fyd0wN$Kfu#AkKnHkV~^$wnj3bL!+ObjCYDP0C8a>^G4T31N6|xc-60XyXC?G#vcQ7DJIQ94=O324VOu zFc9As#^umSvm822e#LZx)g*P0h(8L;;2`lj*o7Yqeeu7-47>*`$YfZCaSHR`@n zCyuD1`)Zw(TceXh=%+t)(&UhVA!xh9IwE!8zq~d zFL=V70#Q;|D;Oo~Fkc`U^ht6`O@1YDFx)e$@`^Xbqr|Xhhxu{-_Ww<;O+Krb*F~0YmW9;CK9bXfQ#G7TXEY za*g0H9G%EY;4S_Ze8ks6&$7@LV_x}2Q=%miLLvXuXvyIcE#sy|%V4;MKZTZ^5iOJ4 zqGh6cv&1 zw{>IWC~?kuF;b;oj3yRMVx)d^12I3x$W-DC^mj;a6C)El8Q9!5MqFWxRgBz+k6mJ9 zi>(3QuB;HMb&Fy4r5JJU9V6@e8mQWbm4P=bhTVf>q{RpWO@?YQk}`ybhsH=eJRkRC z>W=?$z6kj;pj0iZywcWFVkB|0f!|PttufbSYK%02bU3XUD;1*fJ$}@zzbQ34MihSJ zf&*h@<)Rqb8x$j*P+PR!;uyII?!;59G|4l=u{=g-V@cWvNZ99PAP+1JQBBg7)kh%e2$6Ql=-{3ob^wqr>1GyzCV#^LpvnAMbZ^D>nA z8&%car4hLPV8Qd`icyxGN(tX#^IdEzuTFj%7=Z8DV%35S0s zr3wp7BsV(hpET6PO4JYXXUVI&1-`3)$XIu{v0T-O{l<@uVmGU#HGEkcD;L+r%82!U zWARL4kL%GM)Gw_?yMa zGDv~-gOiaqr~_>59w#ogaT3xaPHLe=&`W4tyEtjuJ5Kt818f9MeJp|$ z=sz${yavaK-=H|DiEbo*fc6{`Cmv35k_<8M*~mHc5$qWoCuhdT$2dN3TBK`yaY*FM zVC8FADYS;MMy8@Z&~PJL_gkF2+Y~2B=tAOwo8#mtyxJ8fC3eS2K^S4A9qI@*_p$5u z$H^yj0s05p^gx`fgmp*ac1Aa$buaMUxyEsaZZOk`reQ)M@j5-e87Hnc_@<&(=xVh3EjsZa zPP#)!m}+D;8VHx5;Um7F598zsG=pT~5|85~_yt=D%OU$q1K02`p%w9=mmL4OujuV- zjx~vMc=JE`bNrTF1({Ixoq^Z*Joxso;606?-sp1lGwS{!jsXO5avHMWy%95^GcXi# zWQ&(-X7RECUJwt-rp3!yk}dPb%RuM_UPk=USh%k=f4uC-7cbpVfAlRnu|T{`D;Ce( zx$zPNTaD~N&p?&p@iL)AysSX$p)=7FXuFc}5>h^1*24;okMl;ZqpzT4g?I@zkC($} zcQg|Hf=;$zfhzHm1qZ;Qs(}yqg7^`zr5bIZuIMhbdi8kG!RgxZ@*18($2tZoquS4W z^lK0==NiS!n}+eS2wg?orZHOvwSSG5uFxK0jm$(BK$X_<@~KU{G=|^cEAjBQ>`_?P zC0fj~5%*jcXIO1(7b3o>W{X7e(ffN#!3$$FsjJO@-^k#pz&OupsUO{`l5I z=-^=L;unxp{=kex={YY^I>79iiSm`WJ=z=glUon>XD7-T_y{|ogT}`TDz>1o227uo zDDz+oJ{?@=B#IRbfG#vth1|~&i@!*{+n`q17>ZD*kSLGpM}iP7UYz_5T7WW6BDH+yur^&N|f4}>=8)C?*vN+f(N_%WZ+XyI3JBXok-T!)Vy<0xQ1AE{6MfpG%1{|4O3Ff+YNU*r5Cs zzKQoQC(36yP2xAm30AP3N_o&LMz6E1S#kEJrWOP9Xq}$3F)tE%(l?RUqwy7alPD== zlOzHX@%v$&@~|gol3arW_zkeNK$6^soCTBQEAd&dDV!vupmMn+$p!vJlB5^(2PbeQ zX9KOuB#CPoCI+>~Xe1_rGv19#CGgpx1o3EA5KP0P;bx&ExnDntH(Ajb{MjH$N;OOp zFZ?7p-7-lYKsbIb*&~S` z%5)68h@D_A-kmyT_&YSvka)Y5p)<{hr_=Cd=Op=KRFZ6ir}+A#*%OnKcv~Lr;nSfs zadxP!jZc!cP@kYYcuq{>rJ(GtSxM3zeDSd`4&MiUo{=PuFc&`wCQnb2pgBo0e_oQz zf;?_XQUgNpb76o-l6c1?Nui~58j|peIUBW-mBV@b1L%lv3@273$(0ox|A7Qu z;0}qJtCD2X@g&KBFZdR#*}Z56Y+I8gQ_!h!nDPy9aUFY(I=AsBq4OqILV2ANNm34u zY)F#d;RNh~9guP-Ngh9BgB~Tx=an4)1t0iEf8+}S8}M`UCd)qb2=P_O!uJ(C`il56 zJjCZfOMOa`4`>0X4y}nRLks+PnDHe^enmTyQ~q3`WT{d(SxUhgsG=25mRBW{1q2^PX2{I67~kN*>&i9ZYB#QmW;xkVk4!cSk~yVJmI^Q) zKNmXTn?nv8ma$6~R|hr*R^hjUmqW59Q%Q`mPnIr@$r9N&SpvYWSF$YWlPu=={`f?6 zAq3;6_D+`d{gWkj5RJlJ{5x2Ij{@5P$r3i0y*V^ldP4ZHWEnmrS;|49uw?nPI9WoV z8nMSvjowm82=>oT=HI4dara1;4`?mQ{NOV2Oz&j5J~x@0pve;Nmn^@{qZ2ICGALPe z`i2bcyj;K`A`YQV4W^G^PmD|!GjdPiGW2ueu#8HUg7{EvY_jAV#{%Qo>IuoRVPdje zo60VA{R>!_hIO0jz7J>2-o0!c(Qz@v8-wAMHf~8osyF!=o-5hvQm=e z)Q)5swJTW?4$%JbWTwX8dqsXe<=PBB3a)3jZKknD?1iVvvKhKPN#;dxGzQjiyLO7S zX_+F8V11nwISgI#zrwk?De|IK3bSyfNJ+@BPT{r6DYCk2ij22Uks**`mm+x`QY5@r ziu^P*Ma-e^fD~pG8J;2uQ&J=Z-rqZuvF8WL_U&`ZQc(Scu6q@Y=7XKEmLlEV|$R(gQFofI$ zh_*%VX9=}zvoO^s^rN?m5)m~oJ&&WVtT67 zT9zu$;T9yq*yX9r6`m@Gz;ij1!!IE5h2R+sg9%V{CA$-Kg+!Q79pzPC`LpQCRg}Ra z{98DU-w%zU-|AGcT9YbGU?P4tjK=qawfIkFX_A#KO$KDs(!>i>8ScOvNC)feY0?6% zfNsf|CTDV|$)j9pG6|i5j?0rK+481I8u5Pg2ss_v35|dx%A2C)DL>EhIf-2YbfW~QQ(&c!Xd}_W#p26!AY0~Conk+|`z!oUlVhPigE|G3$(!?2V6Q6{2 zm(%1m-nk<7%@}-Hh{j!AD#@?b=x6>q=gdc3D!dbYD&w|ahP^jH< zi4=yf^_EEa`Ya5MiETmot#l@mj<`TkI#L_%;*Y_*i)qq_@)*27)H#qxrRPR5j_MZy> zACzf-ZOwnPGPRYadVk>e!!3Ab%$H&hyfk`MPaQ5({d4$=L@EJcRV2MnEZEKdu&9w$@;rrlQK-Zm1Uq8DIZ~%E;k?<4#Oj zk}j5EtS~lRVip?kCDxMDvRG9!d)jneioHeG>|++{p4nSe)V7{Wm$Nt0 zMqD4J;}^hs{9L$lEnUi9PnV)s(&ak-7&+w!(8gw#UjQNaZIGL?GsLg)g=u5p&2&v_ zksQH-i=qC-ba6&!l2g9i!*qEAo{#?Km+xX#W)8i-sk4YW@xmd1@`?H)}d?>RT$SU{aB#vP~iyzh;OI&a}*s=B+a%%PK==*<{FgSk*B@e(RYbOB^yJ3L5vzkSSv_7@(UW z$Kd)TRyc>c{uwd^9^kjSWyoQOA@+ydo*5De@8)D^{5;DLdsye5!O)h!E9Lackjk)% zvS^s)ogqPRSk;AXei{5~%aHSPGh`=voSgEqFhjNnX2@!o0u6&Qq(5|rNa(jSLt387 zka|!!Q_GN*yEEh}Jc6Mlt>MqC3@MPAAy)WG;JznA63%DH<4YNG4KCy3FK5UvcQT|d z+`_+xj`(J<=1K-vC0QB11I)U`u6~;#=O7t2f=8}pQccUt2izfOm3x`=fT^&B_ziTZ zv`n@daYH9U2)y`tne1wA;9=8c;tqM5Et8?0f6R)1lh-^b&_JnLSb3!`cFQE%*1%d+ z@y?j@N1qcXI4qL`#yYLYRe`;I{-#J@gYSVpCjUL*QOj&(ZOk(HJ$jjRMIF#ivCFsy zzD&G`lj4@iQgYMKD(F;jr>q$I7B)mJlN;2tr`#}>>_cyh`;|2RI$veLI}vAafhb}P z4TWe(fYS|@OWTIa<c%#ooKdUa)H{SYua|QLq34)~F|HqQ(|G_TEL15(fq89i_KK zV~Jf8YwTrx_i<)q95FHN{r&TKUH3fCT6^ua_c>>VfdOZ}LJ=bx>3zAAZ|BvT-Jf_!{-Pdo9K8rfl=2=@yMl*gqQ62Iv?m@2 zW>Cr8Lk`18aDlFn1ed`bURim_?1~=J2F5`t*aT%OdGH^_JtQ}J6#X3agQ>6$dP3F! z59xHUpNCu-=po*NJVfz7%*;o=s6B}r@ z{)jw+7&s5!ptv6qn+-?g#YP>!;XjA=`q+?nBMv!oMEd$1kuiZsq>wLo(;Kz*Ji;&N zjwo`|>xc{sIwJGI51jR?dUxuiS1N0>h|4Bz|c~AMMf~Smur+8IW zs==#{*&ONQDJquGw2P;>LP8hCQ#7xQ8hG*txt>yGu&11d6YwKA4e^wPLp|klm<|cU zJmoUv9_}gYAQ8HbU?H>u`jYy`)K!IEkl)2qWbx|3E)z1vXF(WjT4+0%4&ksBj=~bifERG<8oh3?FwB5&u6s(| zo1QWOejvV#zPj$&SN3DNG8hW$s(8t&s$S9t#=|S(eP|NQhG$R%uD}h(N}>UfhVO?S zLbZDio4b`PZ-4%!EPTSVB|NF{O7@`vFys77_r}5I-IZshykt!aFIfm>OM6LgNG{_g z+lZHe6Y(nW!S4XyPrW1_qVRrjw-WnzkPe;HkM%}Z{=9*BT0H@)N=I1khGs`}lK_Jjj?sUzYkXAi19^OE!`N2PN$P`G(U z@LkoTG8j5{I4Wb{dvMmP>ec+A9!I6-7e^%?y$_3f9hFHCrdQRgv>TN(vvbHRYVjx- zuU9ozy{Z)^9u>C`2(DKHbvkNE-yyZM`=qqn&A>PsxR3BQvNA7>@BUc~; zKdF$93@G9w^$Yt*0<ra z1otsMG8qn%Z$tbLHG@**hC_w1KB9zTvRr+n)-)YG-F&1K1j3iI**#1LODHzSN0y?6 z^wgf~BZXlwtR<(?iZiOxeueS>323!`(*_%?2N70`sDLWNeI% z!qGmmAF9C2(>{`zpkp__B>o{9oSri;-jhF1{u-#N&Q*PIIy+tV3#a;`j_0U~a!D5_ zp~qnAWgjW4uN#hbfF3upS*G`asB;cnxx*dwu8%xH%c6tY`%0e4f& z4Xk}7%-dHg`})c(A742M4$y>nAtd14(EvYRo|Jv%8d?lZMrUh%WzKP5afS`}LvUF2 zaNgfneusFxC%nKb%`v_d2|=3Pn+N#H*>GP;gt|e#G7_BN(+D<7?nE%-FrT<5ObDeB z{DwaQN%%ZrYz~x2Unvh?;3tC*ehr+(uL<*2WG}`SUXi>8pRz!As0wAHe8mjf;WMf6 zV0;~1$1h=#-1u!QcnQDlq_5ag*A%X^+1zX}2ESS*#8>u1J!)?g-@;d9&bqq_34-km zth-BtkNsq013!M?^^+y|J#YZO9%737$!`#dKLjt!_(|=ue$ok^5}$%4<^040EF1bs zUdUbEPg)XpK)XS2at^StzMp*A+)p+sn1v*q;Sl~I#ij7CXf}Y@heej+M?xjFaeF`B zS;J3?fSt9U%!8WvGO)3upELq{aD;*6D#Lf({G*e)7DB zpLmf-#cLsGsGp2sQVsm0;eOJWF$b7OJQ2qA@{_M1FY|vTJ~NC>QMZW=p2HU)uX=Z7 zX$1@I`b_hi`FXow_qpfH%YEGG_DgZ&*HvF>cb+qMGEF-c(IYOO@88v{}RmcjbH~}foWSf`v?4_=?`2*=ziEwG*HvukJtCOiv{~h zSNvdwn*t=tLD&iIivfO;gmxpY3neM65B7K)Xol|%i}B7d48I!s9p`?EE+ePKHS9zK`F)ym>-h{Py}j2 zS+D~Iob{@DS0k^+<6#1*^=hm#5Qdo_Q>42-F&Lc*)AX^SuqW|iSPE@m6|{%RV5n({ z@2HQfqVu7TJ~q_ktV(v1oD2Tr@xQyMdX$E_&G1d2AB@!JzeR2JUaeCvm!ZB3euW{f zp*IcD*@mQv)*~KPEt{=+e;S>a1JipQlbrB-H_xY~lXQpedR1f9tNO9cG3gAkeX_Z& z_s2}~YE7}p9I4|mIfVWMJ)kG?Y$ymRFpFH&f@3oDn`8270oT7CX8f9Cl4tEPxs5J> zp6i%E+-S!!@dsO24mb836V2XZk`J1~Fyd9{nPBFHei+q4jOvseCViYkPHn!;c%n&- zx&epF$K=_S4`Zpm*5-W^=Dw#<$@k>dKI#TuzvZbrZ+Tis>w49^v!!D7^GhlGQsiE4 zt$bZbE3WWyeyy~G{&13b1?>DtD^XCruvQ)s*ZNp1?O+jcFIb5Wfgd4%5v?2~m#-jo z(3kS78tS7~~nJmAk}g_;7oz zd@-F`sH9B5fCIr$cr{Tg)15d2u38!4q7|=MT8Uqvl^{sP7hb59flIa04LaZlz&LzA zxUxtq6_;zJ?`o}dg2pSg(h)}Bd&9Hu*)Z{dRjjp^v*fPj^R&2`OHhA3yWXf3n?NSP z!%bS=@=Ggj_%Tpnn^tmdVG~=mauYnsZGoWeTFJdbD`lb1Nff4fX(fXE9mX@@+kIRj zdiBM(gaM3=hn0a`|Jfu~?bOQU6s>f*!1aca=~}s+!S%nyX)ooB`hu+p~ZM-x|iMjcfQz+z@Kva!r4!Q_G)^e({&9 z#7Xd5ZGS0I$6v|}rI*4@5Wxj#jyH#@9sH#~OoDa9Lt$4(e~E@j{9agK<1am+4-AF! z!~Eqr`3-~pB?@*yS8~-si=RqO2;&FAiTEdLf3d(Tm)KED8h`BQFN4?kiw4f&%Q*Q< zU06*#15%v*{<2@|FO`q6X;>NV zFSlSl?1Czh{&F{t%Lw_S{H1Xwm*zZ|7>zpXFP*M){fFH0=c6boy2;{p$N99Jz;AqY;?Jt33oosfHI8}uS-$f;`ZMH-)wwM}$1!)L*F z3OAbOC&Z$qj_>hfTF?aD+V%uL4eN-;Z)$f!K7(i0%;|7Ka)C8`+wp{)>7>I8Z;3a9 zK|`|Hp!YH8Y$KW&f})2`$OUkOwa^rvz{iI<0(2nS6RnSGFBGz{DU&Cx)GPPKl`Xzi z8q9ksqh9bkRR{@sDGIt4+LPahhQV353k7(t@xOXP3ST=Rzo3udG*l%19K1dYkdoyC zq(`{`eq0QYd&I%!0peg8AYWSq$bI+}9O?(iaadJ9;4|5anFDPa1V{#~fH2V7RIzX~ zQ*1g1$O$+M1L4M@0GW3rK-}OJzTjc{;OD|H{Phz7GBqSXwgd&pp5Oqfc``t9hXzQg zumGt{{?l-lN(qpBX#tXk-bjUffv?GxKah8$3zX48&e9Gl1UV}*0b>Jgp)k0@y%~Yx z@l~K~of9awN}x2H7s&TIfiiVrpbS|QC~X!8%IWU{#d}Ghj9MBf^Optky-c9of^!f8 z2lfX_Dc?X|4q?7WphO)Alq5*?36uy}e31SJM+VA8f)vPmh-7%6EQ|=0nc$880;b^| z;1#}eBy~}N@)%tU=kW)k17$N52K$&mDG?he`CvC*%YUPKQJ~~cAH5RCSA5PJ%!P9w zy>hSLz{0#!g^WPnp)QbjsG|pX5$_^?4n@J~$3R{Z4V0$nRK`3m1xm){K)H_AMrVTi zy+J7@wYwWwtSgw?e!P3jRu=V?Zpkm@GxK2SZ4oSM(EHGTQn2_>4wfj?Ku?p{kpHV% z#WB0*a>roa-fC&EoLn9(#lRj$tqzt2Yl9_rO|Vo&WA+A1?!&?I*}-5baVS{4_XkT} zk6?KTONhVr43?b-f~64Jg0Y(T*^I^Q3zk*PX^+lg{+1)ba_Nf@>D4nt3PM@P)l&(1 zlT-%{1!ek$NKOoRPre!XcA%;{PxY!M&JB?rtWggJz(ZnxG!|w-Y31t>DU7)T&iIIV zA@V8Mz#-ySX!H3YvIO-&FOYLVmu(D@4qHN`)#eaMfaRM)`6S!@JdhCV~5{1hS? z7g!MPLWPSus-VqaDg?q7@PMx`awTS63K0hgfrhXc*6Y0*|67!&*C+7u7tR!nf(i7~~EMBcdn zA?B=m5+dI}hdC?8#XU3zgL2q4GPr01ZLwjR=*!aCmH}oPtQWr{^hJ*e+DQgo5KjrM4!N z|CJRgkBK$JXW`y+{wmKTjH1K$lak*_fV+xhOV$x&m43G z6!lU!?;R?aj)uxobOMPkKB2N79FNl!7Q;C`L1-dOJIQ83s0(I;Xfko}&`_BQkN$u8 z!bjc0_oJnIgo!efo6Sse1ibmALOWN?_& zgX+*<&oI;xz8o1Q1xIrUMzJtFCe{$gf@T~C2gA+FLaYrr>q(W^c9Ur0PU;@NBbIH)zXdv2b3P%bXr?Cm}g+kMHT*E(`ri4jP5h$|hVI!Up1RKv~)^TsFc{f-P{qf4E$*<=RXN z7e~k#6E2^OW2dl`*bTaj50}yK3qBr3JA_LbbqDe8aMhkmNUi~tn;b5`k~@TthT+7G zq0j`zCxk0cB;s-UOc!Wf=2%IH80ZuXDQl0#H{7JB2?Ag!ZGUgX9kHXE7bKx@J63Oe~ z@*8Z&dqe&k;qsWc?bUGU3d?SWOZi(|4)DYWLoIw+NW-6nw)i@51%Kc-dfW|{r*}B8 z+g!f95mEzR4~md~jw&s=`JKUvB#J_PVh8924T&vb34S|t#y5ro_zguOWWpyAG6FpD zPtaeAMo2nTgz?29q+SU;Y{&0F*OZLlO)(AMFiNo;c zp$KsmxP~_)UmM>QO5wXg^~n)Z2JJ&m^||P|ig>cZO*1CB_KA?YUq;9zHgUdxgzU44 z5TC&jvUEs<^d1x;qlQMvXvQuRyE0~puY_;IW?O$7A$u0FIhcaCT+Cw2BBUTp{w_j- zQO^~eA;?%BA??18kj1Mb0la$0;Ebig-&{ESzIPWX{f8*c;l_*vkJ-wo4X##XNX5|V0AZV#v9 zK!p6hH$n<{u^>JuGeUa&iU%c&Yx!e@3UIgnUcBFTOD>yugtYA3npi|2abD z-iqMk61lIy64(ItP+B5*wu}%DrC6lcSm6jdGE)utcP!z#?K_urC!Utzitg zSKtG_#UtgsI*0sSSPPe{M9ME!bqqwi!dO^PH&XV(_pk@Np?CdA{*IiR;jjp1LDANc z@@X3#&iLN29!lxS%a}^TFC%3MbOJj#Vjn4ICg|AY5Gl*x03^gm%GakNB_H&Khs1^) zs=NsrW<<)(OdZ4U_3%f~PcB5tOeh5dVdKR}x$}#TaC~EYX^| z1EMRauGj0oM@rp?oFddfhTd;8$*beTUqy=FOC9m3N*~e1yyKB9gwDC5?l+>>gC6(Yj{s(kV z?I>}F=lIe!$>Dc`cdaOi0wsmuI5Y)&XiZUbG*j<`>O}Egc~Np0a@CEJ5)gy`0krj^ z%!g8=7wp|*fND0gl*h6v=T55TeH26M>H>!`4 zI7lImA|A1l4WL%5qNF=rYOmRHBiimr<*x|Em7jU zWl$9FeV0w~ZBcR>7DH|$hI>Xye=q9L9eUq_xDdV+dK{gg_s>w>|KYK5v3OEMS*U#} z!}*=mSeV4ked0%Ogg?S7Wf?7ftfJ*CS{Lnsu0o4djFz@&19UUFSM{?w(jZz?EMZi` zoY|6{SKca87+3_Vs*_c(>aJ$lT-N(i&7&m-Z%Xa9(ek@>wB+d!Ei3UGpg2A^IJb|M z8Bh#w2?ec{X!){TwERHPCrm0wQuVt#MN4|uXg=nQqsO0v`}j++rAst#w;wI{@VUB0 zOKEg(=V*CO&1d-MD)?ewM9b`+(XtO};H$x2ydO-**Xb86-IM{*GO~ZP`~o*goFkq( zFj~r@%?CwGJMx9l6O4U~FU8nF{0jUR=nU$vlPg&BW5ly9#c2CBOl}_|O^9o>i;)w=yU;a^ z{Y-wxaPlK!r0&QV-dHC_PLGO_c2i>b?Nf~OaE{?KNn&K#H!-|PXpAI$7bBgQ#z@a4 zF%pjMT@@p@m&M4Q12KvO9FCFHLo9|qI}jtqJz``$Xoydu7G5#3^BhNUhMoT$BZtmX zdp$X{qE~6TB40SbX z#L6Dxbkw?KtaND|D+5}^%0XC9yqWke+#~MXCYE;$jFs=5dd5oc-m&tuSFF^siRGuD zSXn`Q3HFd%PTU7A3JT-Ri4&P~3m*)F`o_x5QL$nRyWyT4bz@?sm1C@UO=8i>)WYDY zvHbZ$thnzKi<0hvODc5KF8s!#VAOdSLUVNNnG!3j zA!%l;+@?WG{2eIoLJsyo9QkqN%BgvLS8}UiuxqTmKu3JTSy-qe86N`H-!i@;R#L!u zMJ#W4fa(5ytjtGC>FKgER;q&&EF!1!^(q}tw#16rwpiJ+HCC>`(7mxTZ=a6&_(zZh zO^Q&9vB2ET3*WrY!JkaMlDJ|o86Ph@=0n7A7N$4>+*FGC7Yn``2^X9_97`uINgrhwry6PR@WbYI&R_VEUjt(I6O(pT8nb3Vk0Z-@_}sf+nN4 zVHw_MWt_BH6(_+^54^w(EFcg< z3iU=4U=rSKZ=Ae_6$$yxD= z;L<_^@P<5K1wjxI$o21al4}d?ArwkN14w|hAnpUfT;C9`D{6yQM%%*(e3S4vISJMg zadH%Gh%P{PKwEsL$T&F-eWT(e1hq!jphuxM-X&Uz?Y{Mz_9F+atTLorwdm&oNpx51v%oS_7c9IRj`JRnyL^#ng9kyDh! zqR;@mArDwV5d4zN9VjJE?!ZVm4-KI={0jF{<77ZuoODQ!ldfnZv>e(DTH}AujFUN8 zJT!ld6KC`ubcE6HO4Uj~#mQl)e})~Smgp381=PX!JIfae81*xk1nqB-tHXt zVwiHCJ0@z2`l3nTh+m&x0 zybMZF_S$K1Q|Qt4jHcp3Y9yo7)|c)$Wkhp+RU zlF9{7$&&)7cxyPFs$S&`d2NMl78}fzi97qa4DFP*YvZW`8-r3#_8;eV5f0( zbHKZp=hFRiD3<57>93E!)@wCaHBSi5fdAjpJA+ zI|s+{_A{L|tmy3G2+!^#n(`3BHWuT*-#%0_jr|JFOTr{?mJ87IXWE{uNbk(>_ z)3}VXw{^60wYQz9v2WC}K@sh+Ewt(&6hW;()>PuSaZ4K{yv{> znv-8SS}c8i?OC-)|GcQ;)eZjb93l^=e13mK&ub4#ZLe(oUGI<*$IdqS)+tZ7o1eOE zy^yeLqs?IJZFibJ>a$|Xl03y5Y<8Tw(RvbRz;32hKaI1Ki<`!-*VIXF4$hM_Rvqn~ z9L8!~ZER;w=Ik;)WvYXV#%`eVco$ncjV`WEqPNQ_Dd>7icA)++9V!uj0T=OOQTKa? zEShPH?y>m!BeT5j^PH^8xZiydP{4h(lT`utyNCJ2>-HWN2MQ`bx}BDSQ%}n^^z@9= zvJ0N$&1RmK#!wV~n0;E7KxO<5^x53g5(FvmjQF#!PfNtI)BJ}2wA@2$p(!g*OPf`v zB@6uwEwbsfoQ3)DYU3Lk%Jr?M#cvyv;YYlI$vaO=>s_bi7j&c%>IaL~(uQd*uI3v& zx@3YJgJQ4_Lc1r(oE`~M5^BRu;&o^c41f$+GCo22*eA#Z^abpL?}&H7=WrI>t@lDeZdyYVBhyTnypBXLokTA!de{p)Ey*t#oGKHi-us{RVq^j?h()Z3dV<@Y6usshdQUX2ahKaj{ba*3kq zb+p7`omXQ6sRxxrDa%0W!9>Y}*42A8HZaB`QTiN76jd9e6ZKw=4K$2p6Q>fzA}&#K z#V5)>;$BY@rT_CpY56o!Dm+V+Fk*-5Ns?4INxIZX67M=mlG&fcv|dS4#U@F{^iGn3 zeUjuJaoF@Eah{bVo->kU(99%hgPQM3k_88n~xakk4=(a;*(?} zvG$vt77cPMU-~A?$C1f$B_>%$MJ3Ce*kp120VUr`n=H0|$?_B(NKMh8WO0v3mWlq! zviAfv$C9Nab8H#k$ejAr6jJBYYfWIXOom?gFUhr{Pb@vJP`4Xh5SAOtaDq zz6?&5rYz8lf>;{gp{RdovMgfk2e72B&+%lb&Uiz{lUdk2I$2U#+yOlU!7Qes&qlNm zH9wHcBvyOeA#R5^W4;;V)nSoVNtSPER6aae64}xB6rO?ffMlu2?zJo$%!H0K+D(J* zA;}WTCJr;F1$@O3|4hx7j5X$rd{5mybQQUa)Yd+kEb}<1k2sKZ#QBJSWGyfHFGn{k zG}}p&OPto4_-OoN8kgp%y0U@qD4a_EH}VJBU>V{gjQKLTG7ZmDV~wA}{5;eZVexCI zf{vwj1ap>h)XmT@sHqA=7(0n>Wiv`RH$sDl6x3yxPBa})te&#}0m}bkkv~|2>;FGE z%J;9K{BKV4dpDr`pB}v*kN^MM4gCM>|9^W2{QuYg|Mm;eaN~zxBwzo%d9sM-31S$} zT5Wg&nMtlM&k@h@YV9rJ>BPl(zBo{)mY^s{u-p~bC=P4=u*4R!xa`4aQb8vMigiqWZ2kJ7N2aC``ygPZz%acY0l zd$mrzT!#7-d^vqDKYjirTEM8kp;pxsj7@fMYU$qoqJ@>xmv2hya=$ue#1wMIvFZoF za-*6kYSM|faR17QmfSBhK^-e)RMP{WOP^;;V^{5SMUHD!x^|ut+v7?i)Ei^yFIt~*{t>>zW>zo z?PI=yhD_qC1yZD9!4&cTI7Rw^FSyTJYd%?f@}-6SM~w@o$Ya=0 zMl{t;)16nxCOg}@IgFX4`9d?(wTr_fO(!RfYi}pF&NCcb-8#N`rK^LB(?pHqKu1Sj zyt3=BnQZH9@8sg{r7d4k>8O8gs`HGo8jYRCZp_rN6E$w5cs*~tqxxEp{0DhETSJ0Z)?U9#XNWa3oShuim-6%z?07}b&4K+Jb~1|d!RvJcd5x{RU7x9Lea7{( zbsVp0(6CYCCQUzY*1U!7n6Y-6aou(EJKEc-3us(A+Pb*#8fPb`>5d(prYeqZHX4`7 z?1a5_(l|P3?5yqVTsVc+)7ZZ)r`B+W`tV|)`Z8hm0@fWmcIw=vf9C-My7%tdf7F2P zy*l?9IG{^E>t3Bl_3u8k^Qg}K`t|AO%9*sCWaZ}MWHrgwWxS?ypDtETj#jRkN#p7| zH+FF5I=+7S)S8zrom_aC@QvxEZp(2zuQR^;YG;E#d$sc`!-;d9>F8!VV~+M>0n609 zN)L+^akhM$t0uXr`naS?o#{M7+|8)Yo4H+xe=%XXF7E!$fCB?sSX(nimexvF=>~2%k@`=sOx+yZGUWycjCa@6-)K8Hh^b%?xd!O%6@Y0?aNqtl)ZDAjGoXdDZFcGij)L*vy~MZXq%L^oNcBQx}PEje#WcR zhp`V*hz^1cQ1xYsoP$hZP2xtcQe*~{&7CTR zp(NPpP^3MkKkS1Sc~a$b@Q2*skT+G%!0nGyrBuOGDFQ9@Sfc}AGxRQ;Do%w`>iG&?0U2ObT1k~rrBdZ0)P`?Lr}D-UsnWSZs!RksSgB_NdKg~8 z01KL!r%Ew&C>n}3woH{SRZ?XVXke9|ji?7af}Yh-iNGDA^)a*0oBN9W7Jk3v@E^ z$E{Jw+c{Ngfl`^9nRSG zadt+g%C!+32%2j+XJb^Vq(U$IRG9`&kgVsheX7FSmb3GTsq$cQs+53(&}veujC4$u zqmXMFi$W#%M$bsp1&Yp0m1VP1WiQ$ebwHn?_Fu7yd0d|P95GDP(-|ECAAOrD0Si<4 z#9yxeEX*(xl^4+zwya2%NC*O}?{z%Ge}eyU4X4eWQ@fta1dZ3G$_8QqWk)LSR+}n2 zALD;OoJ>vK4=uw3`>>15!^Y$c~rpy;$Y$$k*QMpbgHz4W>9P+H!7~M z2;7f8w5Xtbc`j89)I3i+_=;S~drW=6$wj~Zo$0S={ghcBr%CZbX}n`lnoL9EilvEv z;WX(|E=@8kq)E~8X)+J$TBM1FxVw3pJRlB0f2O8X#WWevE=?L)r}0TlX^NEZm?lvj z(!_;CG^}W!CR2!8pie1uX1oINar{~QQE1vJP0IC46TALtvULE9qKyW!5ZaB{7rl?3 zpk@VZV62TMO=^uJhA8}fwD$N$6pc@lFqk+cO*~xF# zO|+-0SMV^?9(ZE0E4TZxB9k+2Xp!$oMCo+gFB3LX*nKyPGlD4A(e5^BJ!jI^fG4>KN${+K3fVHh|@9orf?dxcI7Ms^H%A0F-^R|1s1^wh=Mb)1@3~jlcnXj-0nX9mL=RzR<WH8MzN-bEV7Pyy@~365%qOfKT$J zOJx|6KV5!>Bl+v4OBlux%sxt&PazXu8(n}lMmIrsZ~?7b70agi`V>l+i=c&5unQi+ zw8H7qstC)XMbSNIUvwo@g+#bSZXdb~JptqK?g^XCD{0HsvaFm(shlq5tEBU%i|KL} zjzUA?u5cgkjP8M|RXGAwKnu-@zkm`j65`0sMaxx7mq_#stc3=|UEm&m19}K`LepBL zOO2N4qTIl|f+nrgWigBdSLhB~;c44+>D7+Y2+iRW7z6z}aO@o!M~kAX(7xz+s0#Za ziQF929^DTE9o27G`Bu})&1I(5bXx~ED{ZTKmPPWHTD|jy_`p}sM1JItbc0as!HSk< zx!s31v23htoRuyYAOw4z1dv;{RhRc9R%_~R<7AVY4CY(X`>Ho@I3AoX+hfwjSXFNz z#>g9TS3|PL)ttNY=avWZOs@0Ny?isv5z3|%9(;Pbr*apB0OD^l-ey^vE;dW&dSt#m z_9?Z4$PcB)m|??)jTkYaV7+UX(#4q8mv!-g%juf82GpWT`a$Cfs((QK@Kx^DS2#In z88qN#x@dk)m)W<{-Tg~2_bGL>2eY_!eLkp z?x963Tf1kqvRqs?E?%eGn z(^ze8$QksnE@<4tFjp~{|5^>3HmH6*<(lD+(zZLiDqC21!h9k{+Bg#8R{cmlcVOQM-k~{I7gCE^3L$!^QyD-w>>% zz~KK)t*Yea#-|1Z(Y%`9L9_%|B>Hjve5f#mG=$&-F!9u!d2cn&2JyI zQE%m~(_u95xATUxr|R&pr@SE&pKqQi$`nb$mb;f761$8$ar$>!og>!CQ;yHf7pZt;?sd!`CK< zotjR_DgGyO)qYA&O+O@OSlFN+GAD-`9{>OF$kh$}Ob-LSh|dt4a_!4^b7%T+{Y?x1 zYP?6^SlvLd$s%gbw4e20UGDXmdi_lcJ|v#m@9)hs?X8$5{wzM!U$?ONkbh+Z%3nTu zhk?31ec(Y`t`pMUv!G- z*-wEf>X>Qn--uuLRanrl0pq4>&Nx>6zp)Y19*XHA|5a>Q*r57#ly{Euf3bn{Ju<`( zqI+=t)u7vqDR0<5bBbKbfko8hl>bLLg@s<}8>^cbYO=7JGhM)tGpOnKhs1`t%7+yH zn>82o2eehEe2}uq5&zfmJpFoQ&;nm_{R{AgBtLvJC`0<7ro1n2TK8AuQtEmN3#uD1 zT|~{9HZ;^|-m_8D`kZ1z55t&ZF#ok07B;AUJ>{LF{I51*SXk8yZ{Ygp;Z%1X`Y!Lw z=T!Swa)!R@Ci1A)-*~c`G>%noJi&DAL*pNLcFd_($tn47=8E!tg4%D5$${$E;QuS- zaO(ffoRfaxzI@wtQO|NT3Z4z-`agSZvQ;;b9h;8--Pq7q-GsqEQ}m0gNz=xLB6YW> zV;>qDdc3b*dEdZ4%^Mar=zIDpfBVSZ)9_6{!@{cm#-mE52KNP3)i3utxc-LV?SbsP zVf^o^;rYd|3FAJ$DR1pYx2Rzw>TZpT|B5&C__I06pB4Poal^s}{ge44{`L{Rud!ia zRkd}7SZ>L!WW`j>^>u8;Tvo7<9}A{2G?0_4(%Q%ya(`C~>U*{3i|q=~_fcM(y*Vrt zqt8{-Z|3hT{5XfcZ};Io{&wQuiHqou@J#lR=Dd#j9QR*rV3dC0b6ip%yvj;F#$GWb z|E?N0GxqQ6XQn~+o9&?Kj^zn0_r|CI@bg$?>w=H^(d7+sef3rxlh3#+RC z8<{%+!MSpk8J;2cp(E@W@!=?crT9Z?>*lb5g>0xktcBSSkqy7&&JO-3-tMjS3hH*_ zLDIdDtz|j)L3Wm(xZfRZ>Fw_CVA)CGk4QphX2{pGGQN}U_lecnDJHC@c zW5WV}c>{|6$kh$F(m2Rnr!!I2chIZq{|gkg>1S-hwE68Ea;7zZ7DxQ~rp;e3{Jsrn zv&LISn7Qw8uq>;@Z^@8jTmR4CT|558#RvXDubdBbWQI&Pnlul;)F{qrbK^|L*XiTo z=yszqXVs78L@TWmGvq+h+YBN$B#ndB67HM$M$ zb}2(1pdX`t=t$HJEMW=6ksE(GLk?fdkghQA8ef9_u4YL0>-_ov){~4zACU7wr=sV; z6<-k@&iLai8B&FKD=0Vk6Gn6-)W)v`b7~5}OZ)+9528VkNlj7s6+WleNyZ!%Zsx)e zNTp~3#4>p2W`<0n$*07s|F2MTYJ7}Sq~=rDl-UPtppnrAx>L z=~W3|AKxDT#Z|8VK+F<~(>dB_&=%k7nY0F7Mw|~VLOdL%Kqul5YI8b} zo%#b&$2Nm$&GgIV_~wA3D{P`S1y!I0JR^2bsBihH_K=(9vAl}9p_eR@6MaqcPpCaa z?hHLX`87l8-g=k)M#U?1ik~`E#O2 z{9z58Aijl`K{L>ejOE6=<2&QO#+OIC5r@L=#~CsLoezER{$Nc_9jN#uLry*5;Yscn zcuq}YDE62~$xxbHWNrbqG%@Si9Y3MEjT@c&~V~U@Oi1rkH5hr zE&eFYYoZN_zlL>SPkfm6laS}`Mf$*%O=Xm8|UBamG?~8XVkc4jZDc~GgFq=($S!H zrYtgw)x0k`!}y14gF2a_{84d18e4Ldqbp^Kb!DBZJ|`}c&to#S!0PSVjumzBPI{SD zdF_=q&4P3ZvDK^TB9%>=?bbIlt@~>+*Z;3g$hrO!o9oEw9LW752>lS$`XJ>4i$A2H zam{d(jl>bpZjvcsO*6&n^GxZCswf7d>Rh7%wJhksLjz7 z5DKM<2eiwSlduL3fCF5BChaq&AXvgf;_m2-FSt1c%V8I6u+EfUAq+C%2$*%qluw~G ztc1QW4rX@El+&;Rc7t}(Ldyzy6$}2i+#^`c+u85q?d+2on%yl^T6BMxTI5n0s|vHa zWJ+=3zsfo0EbF10*R)5b@>YXI3|8sIN$Q;``E352!qiQHT>~=ZyMdXqW6--;kgpAO zhj4<2o1$dO)1gd)cLy`2t4Y4!uuPe1%cFYihtbaN{dL>avFabt=mIs`I?F5zYq)q>06hlGCjJFH#&&-Y;XJvas{adOZA4-pEM)TgPG1|y7YLsO> zFjw$s)!39IUGY14wQgGu^``URA9MXp2OrbWY(3AV@F~=WDG&*p;V3MG zpWqIZcIRs>w1WXq3+BQaI1WWNWXdJ<2_!%z;<0cYyee}O2GigqZQR{Xt+U*tEI*tn!5*1%4Rt`T1n{*ikgsK+ zsttI+@*rjfXUYrM1*%sW6r$6ks9$8J)QriLFfX0N9tx zePL`G-?&3#xRuJo3|#|XKse-q!w|$+ENY&fDd*4!&=Rl7$dqSj3)CO=L_f{Uls@Q0 z^fI}D=q@w?ej`5)kB@**eCaHnLeN{V3V#IxAPM%tGidc=ri8#E z*aW>H6|TY&DE|}RSfEeA#>I(u1$XT@Nn`7%zCpXAW_pd9+TYwQ^W>?Mb&fN6K2yp- z9r%rSBKkF0Lonoqb>KdwsHKf|(q_vSX3E`PssD|yNzmes4m%@n$eHSJYMSWlS{v0@ z!4EKs)p-?&dm7~m<4eK(+gv?$z#UHB)=^NehBzmUqyC(J&H(Bh~qsC7yDx+(aYV6D$PpbbGi z14HyVwSFd?Vb0*Y+#?i%Vwh3rukZ}=5syI6fvREf0Q?{Tj)2;HJE-HXdW}Wrz#@H| zgl57%*r3m;^{c>)HSXQ#3+j~z>_X45-}&-S(h&a>)zYiv!$0lS=JjGj*+6XGELoT@ zOS-~vctE@vJqlCcCujtbaE`G8sCz@da^gxVt}H z&~yXFad(cqk42WOshB18!2z~dWl6(IS>g_h9 z6u+Wa_5VW@*~TeS7d*kPZhXK7${B6Ym$|<)uNw!kfxIKshuq|nIJ$!PGWZ(!#?-Vy zUC@&p>@QHRqLL+xNTd+N&@7JPBTV`VbtC=_9x|yDxgk)8`~hlnIz!)4YsfF4*5C~~ zit#KkydMJ}7BbmE8@bQ2Req&T$rrK`KIcccR#3Rq3;FGb7t#se3o`3uN%;m@yir`1 z+=D7`ocIakhh`14WGuN#=#_d|eCA`8Tq3^;e+oYyT}xbq@jGx3p8%Wjc^hRZvYetB zFu75dl%@DHv>tS&K%sCrx{rKaI9E4IZbK||q~<5aS}=E1<1F66jxR^Vs{e4f3Ljpa zb8R&?qxR^)2B&<$26nM=!4Ky(rRf{udhzk)Lyg{$ga5OdA z240pk@+;rB%#zeLS>gl-;cRP8KwI_-LBw~^^5{?KR>tze>7=J ztonZs<jYmjw1ScBNVv-IXe)7whN98LCGZ8PD~SJ%IRSV-n%6~}5`P05VG{9m<`_0$tg-q7QFGzcs#?mp zU^@k6X`uDjT29KNjAbv0FoD`XV?K2isOwg0id2HkV z%3@lGgu@8{W5|VHj*~sH6)oC;1CPiI)TT5#nfg{7613p|9r57Vb^ow zSm0MI_Rl7-nRX**Gkv?UxmZrlJD$f3hS7dxIIm@F@PN*-)MvNvv9o$4{e+A0yhJ`d z;3&It#1C=;UsDza+sGoSaRLrb=_r?OAp^}~jMWT!5#kxE3%S3w$OeIpsJ7==h;o&Z zi7zl9xDGO_s)UdfNh6R;T?gR|cD$h)0ech!w`&fZyfgRU(Yc|`P4M`SGYc>0LgVK(t3 zI7DoweFAYjyh>b=y2pthfQiI0Q;*0=7(MNX9L59iyEqd@630(JA{Sx8j3ZKjN8@ey zFr>~1J#zg`<*q(|M20QALGuMS;*#|xw!9roKau# z2d=I~rc!lG&V-uvpZfJ}71^-muom|Y9XVo1i>TrEjcj|LX~eKL!`qB(+3Mb5_YQ4) zZ>yngMzkC{Y)I6#H;Pg}T)BAIQ8^2Dj5sQlVZiX~@e<;LutwF7JSwO0C(wiV(NRaG z7Bq$@DG$O0wxiN<%u!i_>)=;c9+kfD92Eo1Cl2!As-rUb-J=o(5gRE4$*_H0*AilA zQ1zI&z+df{c-kDh{*G1|^$*qU8)`~@CQIUBEOeQeCApKbq|W3l`3e7kKb@8(1E*(6 zB{0p%l8lw#)}0^X?4Mn?Sw@?qb&aJGwAWwDl5MY(26N#m<%_t3D@#`38Mp~fz`3;D zMtmpnUgB}Y8}MhiFLj$Bi?}>~74}0H%Elqd#`w{RBb-w##)OQga_SbA)BC-eB{B5< zJNW-WpWhi@|63FP&LDqjjIVxk(Rvm?9{B6sr`}Y)dD6u8#iCA8{SBlm02=?Rn>%t;Kfy0^2zEf`4GPYVee*1987{7=t0{=>d)gTYqF#j zbc4F@@sxlW+Q1Z;1AAb=TAm`f1Ac-Oca~I#itemiWdOlYa60N6^P&uyJb1gaq$M5$ zufbh`xCiwWpaqR~s04nsfBl5_ATY=#%U$dY>AEcqIrg00zE z5}Cs=a1Yq>vgAwn7P6stewM5}&D{v&VM_te|CuZq1rEw?tl=ftRiI}{0SOigU9gpg z+wfs*r_NlMCE+*<48%4t(N-P2#JNm13%ekb91rzAJdiQ2(zXHi!Zg@IP9yNr<|i+j zIPP{Dnox0xP6bpfr96&u#-jU-ABQ-TS{pyr$NZQj&3?*~?{F!+6hDCbLv@$}-%=Nk zXJR)vul_j~$@wkz{<>cOA4ypxXRznRXi-rL8)31?1Ilrn6E4FZ3p9Fn*fG zTc8bmMA?aV!Q;^2zHGkc#L3{d@gZ1C{Q_JUr(qrEKpAqL1QR?6wIB&9BxlPWmaOWU($6&#zA zEel~id`j7mFHX&tukclT|H~ZeQq~4maJ|CSSjN?X@syX~0_yB|7WP8aGOkt=g6G*cGtiky(4#rb{59+~QD7`XU%D$5=6YvJ;1YIdV z180ey_yByfimL=Vlmo-N+0qT(Cmx0yH6CK@>fE@XcFT-A?=s#N8fE>E!9CeB9e)hp zL24j=`J-$Z1XG|jITv68_#p6sqtvIQ!#!YuTJRCvyCYl9;0SyOPsHEBTaXDa!d;o! zk_V%~3p00TOVvHuvKt?P&BPDx&6dl!EUveov0*T*h5q|F$U5F^*#-mQUFZ$%zRZ@F z4|3;y#gzmNb{^)|IYQ@eSt#y@f6B?0o+q-U=yyfHmbed2r>;Hjis!)v z>hpcs5{5H$f=L7oNXUcL#K&MGah1GmIY@`?kWBm>xlM6bh^KuxdDAg(S1zwZe@KFc z5JS#B+LGzJh`eIriqwAr%ZTUE-if%+?IcvC@CiH#8=yDzI+-oMz+(6w7C@7H?rBJb z&M*ry3RpN?f&EbBG<6n}F+C*8eKniE@Xj7^rDE<-*cpgV6Tb%s;2Uxl{gN#;zz%^M zBV2eap*%E!>M$I1um!B*aV26^ei~vy<*TxyFARhpfpRpS0I7j;Fs~=&Suj_Z9nBoM1Sb-9B1 z-H7K0%8deUfhPsxU|!JoQ2+hUyuv=ktxy%(z)UK?f>+=@h%cKX)yn0_Tlg6Cu8<=a zVK#gO1r>9oOMsv83fKnYpt2!H8p2n^z3^Pz9uLH-&+^)gTgR9qRqN!)<8YJ;AFg%> z6X5%BqsG_%*mp*&4#s;!bnOeOo`vtBY26&Y8v2D+h z53wJreZm330PsNn9XYZGrb0R-K}O~SMni}`Et7MDlkh$4g37ydq#j%#HsNn@6Z{E2 z0JVuX;WO|ql%jkWJO<_AcIXPx;G_L0#1k*aPvN1^3VzAV(WM>1RvO*{CoF^K;c4o7 zz&_$|+#6;QyP*^D7wrCD#gxeJ&nz(k6{U) z!BTL;OgIA0%$~-k(K9RgIemn^oDDvSf`L#Ku6?C7V@EGzL`dzOhp)=F!sjsXWu{Mh?e@tJ zxF&WUx7Mz*xwp|t$KhTc8Fxp<)Qfni?DRq;X3%OZaK zBz_v6h2^jYHoz(GRf#=tRW=iEhfg7qx#9t~FTy)upsc>h&@SVb7~}lXhEFc}r1NE;QO>TmAY$n?D2a^q<%{gSSad^fho6!*JTsX1zM;XnNjRQhL zFST*bNip87FIab6c0&Se3s}VkFmC;Ec?){Ml7LnG863Rz^{Zv23ZX6C0h7Acc*u$9Z^3 z`x9~jzJM%9htLiu!~liFjqxU2183CPXZ)g6M!Ctxs^twMQ%}fAcn;o!4AUH=tD?c+ zKEXSaoe;vnOOPJ`XKJawQ+CmdceQxHMja_dsRh#Ruv{ItRVZ$yb|qRleZ`A`5aOa;0ba zTqzHcaEbB|{2a7_Wzeo#u2j4|SN7vvm za0EVFBbQ%PCKv=YU_6|sF%Iv=C!rVdhd2c$6ZeB*&;#bca9{4%kK=fV|d;TGe!q1zvE z?tI_aE@JDLt8#{<&)(u?Xr0~I+i8ucRWT!RtMQJA%I!v6m1>+{9k>fRj>vdzr*UgY zSF87m?BOLf3obet0SnluuSD1k9)f`|4mx&a|KNg8VKO+Ue90?**ly!IgCY9CTp0(- zlfmiw)@ZVheV9{#=l}&J;$YoBwHiCabi^1QsvjJXD{Y_375BhgNr=gnyeGM@2Ia~D zXl}*vxv~?K7bRYgw-Kv0{Zf~Usk%7kZfr3Lhck0)?9VSzZfZzAL3MmU|epWwnX z+$m2HbfBRVcH!Gem&mfZcHn>P!kK6+|3p&F>>Mb~pdJ~j_%CL(?ou+;= zd`o#Pd8>%GQ2!X^!4vgdxpNW|Q8AN>_3#dH3+igXH^d>hJX|1NO6Qlzc^?PEIEUv4XW=HeE#wjJTEHoR@(+RdE3Dd-b9DYEP2s_PJWhZrYCR~+QD8CDL5^uqKVGnK1COFR&8e@&06L&5a=?ZSVW4%{duLrX9r%DTKH7t)r_Oz^(s}-UmBPvD_~i`8G(2eR&C0kz&iL4>c!>B zHfR%|8a@v@1H6e}fd?Qw{(2lu>;?@~zG4DA8keWbbb>@^8bA%MVwH3o1Ka^BSxu}4 zDi=VN)qp>js2fJipx64USdFX3QGHZ7IF9Pul5rE`^y@oOs}8PE?Mw~aiG+OI7^^|m zjt+q8tQNfhj)BTm?W#`2s$NZ~7OTo?GpesbjjhTed^Qar%yWkC)M(n3^XusMDZ6yhb?(w;(rdW}bWmPS^y`!*2Kr<_F>r13rgU zd=ONdat^!7Yq%Reru+IlSVw#e=U>a`qmUZp5jwO9bXrQn?KBRg{1&ll523u9_+|V7j-zcD zoFR^m*uqyba)+-VH0>@ zJnSpSO%BQz1Mv~8+LQ~RR0I!Ng*>SOu>q@C!CTN9lSUecCZ!|}A7>ombi7}ubcQKD za+E>8W9?<>#Aj_U_0kB+6Js*#URS9A)nX!%kU}GiOG}ZP!6JFc**>l%FYz> z`{&6TlFzcbPXbo4qLA{Z@FIEXFa~zQA=m_ESj<#h00+o7kXxTP1S*4{Ia=bY%%M2V z=6(R%eWN)}SQW5}6*J@VBs8Am!x!OQXh^vyIG_BsPUDO*&qh97Mvs}CClSx`5e;X< zYp{ctzKXo`?ZxWl@falW(w6}X0#>oJM6Akbpo7X+WyM3#9~uVAkK?!D_3LH*KZ(t$ z_yP{WEszft;W-EnCM@dqKzSGON5pMPv5HfP6SwJT@b`dsAN(xInb zb8ej%`E0EZ4qcW<`DAb)jE04_>+iU`+*X{?`}xR(kXup?T$bI5#m-&xBkPpzS>~w!94lw zYo0k=051m0n{YZD0_XTQBKuTt@(m9HnKkhMXdfs$^WKPTVE8PbR~;B%kjLNXx_Mb0 z)K3>LJJ08U&=U^8^)Gk1Rz!w{S~5dVN~=;QrF_^)X#jDRPfF@-C*>r>!`INi%1MdA zIk2?qN!e5Fq&$B6N%;VG!h2v1aZh~hD;U+@ihNQx)jcWE&eiW~Qv_LtS z^Y5+SnDE~Z_7BF=OYBJPGPsDr#4+#;%na18!LtLg%2Sssn4d_zIZ(C)JOHN$;$U9T z{iq)~BzcIlYT25VoZfAbw>XV$jgc8|t&D6Js+(fCDWDbf1~bfqw_!=ZDqdP5R^flgD+q^gwHuC^`T0@D!#o$tjgt} z0;qgdR$L|)I2))d#&xK#8E6mY`KfP8UGq8I9LFiNqL7Cxl}OB{oDZtgZhRO1Ay5tu z^zY5h@$U!u7h~upcC2<8T+C78!|)@7267tX(k1fMM%8zRHPsx%&YO6~#WhXQuGG9qhbyqFRBV2D0y+$nKD0?dW+umf_y8?cJMDiN#l zF4zMqUzHV`U>m#>C~v{v!Z(3(FmE;G0w^4JN|#p&&VdW|Lon$T;uV4N415CC2Fk&l ze{cQ9g#Ui9e=wF_Vn=G1!9_TU7r}b?Fi?LIe;kNap1NGY{I`g|3zTOCybvD?#KF9v z=TrYg-`;)RKDafqRP?d^r{vzxPsu!730M5~lr#e6bFldcGlL&?9lg$0;uBe?_%j=) zq+B-bzEd*e6wW^-qhTUAJHHv(&)M;ty0tT2`!F&wL|;@hU$(=`kOAr7hjO*@r8r;} zONm&Of1vy$sC-pc94F3)uLE^?xHR>lf%ahDVd|?;cYCdTU3OEbLt!7j48f$G#9su; z>u?2fj+ST-=KVYCHzxdd1O3Bs^b$v-b{Sm6r^Ft}hBJZsO5~mm#41l+u3-L`#5DtB zZ4A_ZfWu3SAIw$WO4}1@J(Efei!-X9CaCH(eiFG+f2Kpe_}c$<{!V_m-xyo<|LVqk ziGOSIzq8O_ZggM~t#Lc&lm_+dIZu2Vc|yPPP`)Jo4gOC4;@=oo^&fnrKH+ao{&yA{ z%smvCECXk_KZ_h6a@&N~#j=L4@o$08V0LSM%wkt$g8q4QzT^$h7sHTzu|CZ+4qJxu zn2yL79pXpj%O&cvW4P&t<;yFB^X0;Te958hm66F{Sv7A zn6Z!R{qtp78UenUuoCr~SWp}t*OB*6*phO+-<<&m$A}IFom1H@$JUDp5?Q74`>ay= z&v=`BU!af5ZAEN;vi~iipM*FUe;N6}(6&vAr3d8jWt0K< zEWQGj_z9nuz_;V18$3JUvV`(;Mm>lhhkj6ox-!%~weYeGrfh=|#OkMn98i|FgoVy_ zUq#016^P65Gi0~IXy!5CyP!QxpzOBi%fe@`vyZ#%XUL#j3{i?H+)-1xrJ>XGzm5J+ zI{g>>aEt$gRsZ+;=zssn{&eyWxfJ(J%a^@45}Lyt7zU40{~ebsxM@8Y{1YE9G0;Eh zPoMusu75Je?&SE_!IQ)hun9WpT>th|&R2#1g?r)8#{5^;|IY^h3+?~suKyZt-l|i1 z{&x}BxCC4AF)qUwaFw_Rb%&uJl;YAHr0!|jeuNi^h5DH|9)dd!r*1M#A*V**a=HTT z=c&JodX;MkUTQrU{7cse3>;j@U-kc8*M9;>^&s5EX`E(9gNe;}DLg^^Nnn>N@qOe} zr|f#4%>?W->O z(9y}ml7^2kj!=J@Br%C^!=@#U7(Q$WKMgcGd4e%1b;Q__@kwdg-TD0MvVc!v@ojh@ zHk{_}K9?_DpgFXKJ0ao+K2`Y>UZs7@5BWp>lQ{KHI{evyztz6_JlkBB8yVd_=k@}L zu2CRgRxgn9cradre}JCQq-KF^rmiCHf?t6%)HlTEpccGD+1WlXar>nV_B0jpT?1m$LL7s%W16i6$|8fE1mTd2?ftU#LXWR!Cx^M9n_$g2h=Iy6^ zEBO)dA#r8=G5)SZ-ZtVLf%03p6gl2tyG|iE*#8OZ{~MF4T?WV9Lc9sSf}B8o88&_5 zdaPedTpegoopupd44le4f%^6M=Mp)=!IjriKjr?@G9MQPQpwi6!fQE8cZ&px++nxAK2gr!$dSm2_ma0kjfvurBCua)a@o z`Fj@jXF2*GC8$NMi|5XURq%7%b>1f~lWG3@&)D zMw09S3w#3wHInpem8zj+W3c?+bZ}xd`3>|Nt5K8PXt*8+7jU6YlC+FWk_YQ0$qv|K zOp=!=r$b}d3hk(0iwDwH6Y4ielCkxZWEVU@+~)2iY1TSPo(ovT&2;|v2o*i=NRlqi zlEipdlEmMcBp%!eZ^UjoZ--AQr(-Lgh6mTZ!D8xWlDm>|-XK$M#rKwmEu!`Jt z@IdOj63+(*Bn4c2`i$hCJ)=vVvuC8+_h-b8EwKN)Gg1YXL&Kso@@e52*@yeVl{3H3 zt^ONr3rpmgi6=0|7UuY${q-}#TW?7sla(jQ4C8)b2VsTs@Xu%DIXT0h);J?Iag0_d zVbpD<-G*4Oc=3YI+Pp2^+UPNx|pUy~i;_ZwRMS16?Gg1x~ z>2w%F(2zm5Fv!u%XJjqF)&;F5 z{!gs`&fxz^_?`BDaMZs#jbML082p*lf;w^2h26qa@HhE`e*AcBV6Z<(`cF)&p^SX4kZRs1FQPS zs8d#xlx$aJHHjLqE2#XN%f9eJnFsS}53+``iQLdzx&Fb*cd1Zu(82nkRefF{M|BS7 z{$75`_IfKa#NlurK7wMM|22lyr3>X*yemLMCOAW^+=$Mq{y&`p^#i$gRF3Lf zh8&fvPy?&_+o@A7hLY{792`$CPm<~otO%BKsgJ4n+q@caz23r(f&_D|fwnH?S#Y^u z_g_Gr$}2Ip{y!!;6iCYag9Vfv#HNmwLBC|Ol6{6VPX7uw7I0gjy(0B@u*jK|SC!@Z z2Uq@fV70;3?PcKef!&mxFxVdSY9>*!nmowl68%));37lG&7`eUuw5^4#8XPFHn^yu zI|ddPEdQC+LPpa^Jt5BrPN-y`9|LuI$;#mBf2;1d+JbpoInuV!2_ix5uwlS{7I6{^ zAqRd8cq2J0A`1EQ^aN^!?*!~2VH0eFwXieb738cWeic@L6W$A0wap@)4AUSD<_Fx9 zaqoxLa3^`41CFNs(Q;h>-UJW9pn&fu$xPe|?uX{kEnw9)iUBI{=vBw+Mhb@*+RF!g zm7~`vUnKV`d=F(PE2}mi{u++L7drntr2_a=-9Y#Q6+;Gm9Z>^N4QRqKA=!)J$l_LRt)G_C||+n50gimA07hdV|<(d3-p0imO=@6vQR4Z zx^5LK_EMjzli;D@I0IJbecdWn^m~F&PH9i2{bS0XQC1Fen)=oB+0vJ`K75pfF2t(t z0^C7)2IYhO3S~R}s`bBa6)SS7*T<6d8cEBj@CB@5#Tv?GNxA})DED9hjAEUtBx#`Ctv{(>;EY<;ZlUz`4@W~n*3(eV$@_e*9RBy$+Nuh(Ecr6ia${h2MM+X%fGT-BJo!Zf3ZF|xSITCt}W&_ z>Vxy_n#T3d=6_$o8Tb)YWsqQ7u>9Y2U~K)`O%^N%9b7;jZ5k`D#_q~vGpM>C!M0%eFIxZ40DsgWIJlbpX4GO- z-<#`$<8^(9P5mxh|KDq@xw25=-v0ge-|P3c>h<4U8DB_x>wjnRlH=-sXSLr47Q2O$ z@xy(bj%yX4y1{cWi}HeiAHh#ST_}8$e{KalnN6K1uIZ-kU0(lH5G3SXK1CuSj)e7V zuMeyop;J%G~;DN6L<*+S$OesM&^^ItM8dUz3jotW+bra9) zWQgBe$8vtze@X@K>L@pj|{LLzYEuX!a+C*KSAkY;ScwUG=xhY#>DqS zH|Pa}AQn<#3-it@mb+y!g*RXw?0_%e2;{?gD25Pz!pY$LcueivGyK)-9}Cex*u$CZ z=hFjdA8_-4Ro(CL=w3ddhNS`2IDPls$j>1@@)cjAghK~;75VzQGXhq1pkHeY6#hrN z`Ahz(!2qMLC(D#?t`DN}zo$*LE30xa4tjZD;*xD8=eeF&iu>~VPw`)@RexJ(*c%a- z`M1X7#@c$%%0<$rW|1teUL-G8Et2F|3sZ4*+scpqat~&9{m`50e%Z+-BTnVG%MmQp^8dN z4GI~3>ek;Ls-KT7k}h#Y(iob-kCe|Q7D7z;T+|>u|*O!u84PBDUy0{nzE!6 z$rGtX(i-lEFql27NG?5BB+mz&Kc`6cLt((xmoYYU24Y?IRX8gr{{(Nvv$6_;c{@wQ z!McBD{l=h2eq+#$)ODzPR))ezP;rl_vvTN9=+*YDw1r?^j}mdP?wWi5$w0qKzA1OW zZw%U*x(r|a`Y{jd?H>r$x^>qyqa{|NiGA2LF;p}5ij^JMhV!ror%w*m%ui5{Jva|* zy<;W(*-*`b+fTuLVnut3yuPvG_%2j);pu+z`o+qu@KTxuuf#4q?}<{nX6PR)Tb?MT z*>N8BV?*y!nl+jMu@{fR<^i#?2y0KqN<<&>anDQ!8pwjMHzrn!v2{?am>Ps>mceWY zo2{{8$EG1njEzHMII$w? z@o;Q^orP+pH4kn&sQ9n+6-V#EJ(S-elSlbFW>K8ocpk+J}Fw2KH#AIC~2_Tpk}`-Ge5c_#Rj zqr`5!1Y34+QrM5R`3&$GJI1D++@#ox?eUa%tEYvDaLe6z59JRT?{n@M?Ei*K^%3*v zIk6J;R2j|a<0yxe(OkGu-7=aF8;6$BEXQNTf(<8PWjyxabZpOMA=sM7&am+$`NQak zyJOcW?jdZ+=OnQk@56=y+T+V;W*mcc(`l{|f$>bN_@oaA9s zsW^#P#{$CQq$M_#j*}Rym5Gz-*pFAQ(>bzR;^ZI|-tagn#-3Z_q``U?P&Q6_Vpq91 zNyd(dI9Z16<>O=rwpECeB5bV~Csj7E07IO#$L30LG8~&K$H_cwye&>PVndZUIfk{W zagzBd<6%wTK|{4TiNY>y!=~HgWF>ZEA2wHylj@(bKy1O*8gViU`>_YxYsSeXY^W6{ zrk#v~M`2^_IB{V&K8($E;>56vad3BRy(3O^JAscN-Oqq^IXY!yoEY!8MYGl81h5~E z$JR&&#HRXjvJZQ35jHl6ld!tCXfABRhCAco>P7T%0}Y`ljBVncI1PV5Ali6h5;?8Uwo94YqR%SjZm)B89w z>~6`x*wrdd8dVF|46Vt#D_pbTMdxV8Zft17wZ>L_2^*u>*m=gqhEn00r7iag_UHto z2u$r50K2dU8}8?5u^m?r3)lR(E4H?00oaR|VRHv|j@|eIHg;serNcD`?uoTdTsrK* zerz$b(Z1y4OspF^b5lJ>#|PrXflXaF0c`HdN@vmGLE5pk8w2%YAe?^ht(xT_?g8w> zD_2tP&Vbm1CzUO$X+3znuo=%gM|)2;hOLjYQ0%qDNz?PU>YC{Zp3CzLgpbj|*qi6J zTv^SEeHF`UZk$)WtY+xLJyHYr}&geYpCNvYP8DF6j`Ri3YLrS*&<)oNU1kJiTjK&1B^!d7qBM*a>!z;5pvP1S8|5 z02`lPyE;eUZW1r{fsBi1S*dRtFI|U}(=5&6#fBZY z`qOOeo_Jl%1S{`}m*TeNv~#$2yK-9V=JC=V>o^AQ!;^4T6BFYn@pildAH(^$7&mP} z|NF~nDY!lU0LS1m_tGEt#mn&9csnk-S7!i%miI9Lo`h?+XXQA0B0Fpu&qp^dO{;i5 z=VNC$ow6Gr#J1M-!-h8T(qKCMa8K-rikD<;ZW}Ky?8p1CyIs6oz_$CDX9oE?K~Dm6 z`*>+Nr<`W$z>2Z4BS(o1o#JIR*33+Z{kRzWIy2#126%w}*wcjxvAZif#I6V9`OJrf zbc>fFY=04W`v682d*3GD5~&ameRc81-(+1Y#+(1&Y|9ev{^9^3oH%OY&+&(ULRbUa^2E2nFg z0r3*CfCW6s31HJeP5>KYI00;UiW9)vAWi`LaWVD{<^&upz{&|=&k#-kyN7ZD*foq3 zz>eXZ0Je|d1QxP@k(>awKFtX%)VV81aROABM{`%MU_fla)>!Ud?8hE#kBgT}Sc{Jr zQ#xhr!iI!+IgDM{@Fp8bjF;}%jqR$O6faw_2m7(v7B7w7VjgVO2`ppcWeN6SFSd=1 zm+-fl7@M(g96Q6_`rCEl}wz*QDevWco~oF6F4z!dnR6d*gBD&zr#F} zSQz%>N!T$tUUWBs=~=D?_TuWR=*Uyi6C3R80K4%`;Rlvz%{~0bxYx2(W0*1Bk=>I@@ z&4KM$w|q|nfzi*=U>}~>gO#1*nqv$0VmB_vw(~p{lWG5fBgSrg30p4kR6I+6JPO+{ zvN7z(VLA)=k#_9GG1&YQOe_`V}=tPG@?AV+jChW)2*w;Bh?AZH2f~>@zE(zkr?yd=P z3A-Llknu-YXtxAejqMLH9=3Joq>pmqJrZ~$2gZFkL6=Dcu7?xEjm?j+BkaS*!;~Lm z$2lzQadwQ2mIU4wiG}rIVJDanAC9b`*`7!cL;VVTF^UD=SwZt-!~GRBYacEt_To|4 z+&4iMVXYsR20Qxc+!PN~&|LjF;;sx7oxtaQG(5@8fvp2s@#74D&Dasc&amMrCU~}j zX2+X*n=H|IT38Ma!)x~zz~ieyN9unWz44!=NiAtibik~rB~2Q*oOUh zCAN*^?tP0g9*?b0bCmBeFfPWXQ3=v$6$9dy8RU;nka(=cGLb6dmfL9`!wF*Bcy3}` z)6P8J3OxS=QD4!3Jy{hr-%KXRsi0Y&V_`maI*Yp%yRg?!c{UScFSea$M{_tqtj%S@ zA6O{vBaAnXdkUML=Td4FH9wBV_W7K!Dr0k4MV-%Xd7MgD)O^^4%?=u>SJd1%9vc@j zFm~V_SbKrH8ryK~8uY{6vE{`CNyZ-R!uCbn8`$s?&wJA9h=`vknO6BFGW|>Tx+@3 z*szY1!M64E!^REVD+9>G!=GZ@57?+akew1(2b1_AJH^^Z38IZ;pj{mGsEV2?lS`9G z85d#0Zl3p~ikcT&uyqgZ$t(;PVDnz?i3POdrcO?7AD3bS^I$Kw?Ppw7#(KeaR`xk} z`3EFoGq!xe&4zv0@DT$ZOpqAtIgEGE@mqGXkNP9r_1KLUVcSt2%l$0q7)Oo$I0hTD z7!P}JIyPr>$v&rFHqU=Dfh~uZ*e_V|ac)Lz&to7j9r76f+rDFG*!(>==K&Uaj+^pJ zCcw47W}qMG_YHZ)+~wFCnkeJH<>X2wN`qsJQ#w)R9l>Q1{JIDg zWfQsE8K7Juze+&Ih(xht4=y;xg32d~F`uKakSL7`D{8H9dUb;~3VW~%w`^+A3>6c3 zw@8C#$Mdk+kSIH_7mvTspjj%>4}0*ARtC+e*G&{#FB0+iWP|3$>DXvY6fbt*Vr;3$ z1StkB8@u-!v`UeQvJYGEto`(BlqkzSr(fel$;1wP0c&@&@GlIS4fn)8JRVz`Fb~!Z zO%vr9feUZ>iUjQN)3F%|*xo!*!p<|WDN&|hq>L|IVnS@V%s?#?r9JlI@GAz*kE4F3 zz7^x(6ztY2@h>L&VXZYM7+y(hjvLgdq-#?My4I+qd9h|Bp$!SxjJsk}6bop~0C;7? zN}30|?y01GjSqIIq=mOl6hFQnM|7>ECE`YSIqr%NVk^F-U7}3FW}Fwzc-SyNucR68 zX9oi+X%0LJYwZ(d5%%DsK`fvH_rS19n!O80JBE%p5Bsn-wvy)R%8s$|LHbQ3uV_cM{|F$ONhSWFz+b|_K0Ip~?UT8=uniYuJD%iXfM;3Y3I^19oUj{P-{A!9iF^Z| zes~hL;8|&x`Y?7vZ)*)c2DCHVC(cmS%M8SxT!X>Q=CcJGBZ&w zVcRUOE%nyfJU!Tsr(@&XMA?Y7dE{@RKMp%f-t%lIqmnim7vlrC_LfRo>L}! z+cRl@flG^xFLFtKQYW{Wn~Vw<&ZNTr84JPN_j9ECDrx7i4d4Aa*A828@fR!X~X|c=%9`O2*WOTBo0G+*xvjGHIkw_**<4C|2M(`Nnb&?6 zj;+{SrLwMh2u7)j9PV1|!`?e9YkpjWO+HSh5gqZt#+5Y-_G3GaxVy6Ez>Tm6Pr^RD z1RIaDA#BEZ*p9U(rU^jjb z@56pvfXn4^k2I^S)x}0^#XIh+ti6QWQ=WD*QKGR6C+h?r0tfct)!2KA4?cV=)|k&x zcL~+}*wB@4sTObvumjJ+KD+~4&vI=aBoBARw(sbVz2|Ai)*pE3#U5U_Ru7W!M;-bdLp)kC5ej#yRg=S zgJmLzRCkzmVCT3Rl@AnU2ln_*F#g!x}rcNARnP z*n_o4sOOhzt=P;j*e=6%oQbuHNn+?p`8Ix?k$e{(PT5wKiLv^X#;`{jr)83i!ltMs zY5ExLQT#$??IEnJZIVP|d%Gkt)8NJqRUXaGvH9gBX+MUErZ7R16e(a_Ptz0$dz=k4OOZ_K9rvV& ziL#-2io`!2s%s8{l~nk!M>UvIlrbzeMoW!F{j2-<_L=T%oLw^Rw9xDsLh9Mj&13U0a?8Sz;>||&PUu=FiJyV&$fv0h;m8Y{H?3%&7qslXx zcp>A>;!o~gC*x`DP4m&omV(i_>^N)R-xcgtH!)A7h zjqlSDyS8ys*pFMfm|#1P6*hjr(}P{O0BawnNQ32^EVg1VUWRR+6!9!XFjwfN`P8NW@_yRWX;$+ep2ghSuCYJ(xc5|}o9>9Le?ma0I z{U+^uIXUdb#X5m`A1fu%g`2*`j=yFi>^jN>*mR5u-sWVoIeO(BE(z9-v#^!q;Yrwf zGDW=Dc8b@HcWBS&X~JIY!1e;}A?!cRO}&Z*o#FYf-G{_Nt{oNHS?+4=z?sTS ze-VNG3M+n(MBEg6eql#gE0ro5lz)I<}Th<*lu#FO$m8h_F*^ax>m7 zsr+mRCl{V7eOQ8rOHO^iC`e?E>FUG5-OzfGasBt z#Z(!^Kwf;9vfYr%zhs!8QmR<6zjCU~qTO*@DnIkV!m6c89(L47mG&FC#5I`*yK1G1 zPx%h!Bj2FcWui?~;Dc0naWZAC9tqfu{n!`D&NeggovE@!xe@hPYmzDj^mE{reJM9( z$Jm8k*o&hx*jO{hqini|{*(>P*$CFX1m-Oqp@{{M;KvdD@V%)riF!{<>an90M^C-C zO{%QM)+l!NJ`2O+v864S0vp?)*nhaRFshFK!}i#oMVj zMW>44Lrx0Uev$B29coy~!OqEPsb&TQKeniDn+_l&-h$F{t zD?3mF4&_Ka41^5>IqG37kg^M#DBFj#W6EAUiLz@%s-$DX(^%z=;-r+5xP%`wj*XjK zwU0>^eHj%#g76q79-As*pOApf*ffs2o_a5~QZ^^^7-2ik#E$Xge@g#JTr%vjvtX=E zQ9QsDO3kE?%1c{USKwqX}`;EmXYqi8ohPdoN4&{O3Yfqfx2$4(Mos$imTUqgTF z)(NIFf!EC?7{Y+-crGd1ad;*P8#sEbZR94x20RPfup1jUvGCmth|SoA`(QU7g*|u@ zwrpl%Y{dnt9T#KWLtxm$Kp7m-ckJ*pp3Cn!%H3R3Y&pzC*n5nlBhQ>oN6Pm6RNmv8 z6T>#_!WKW}(`-nU@e*u2!wFy$-iJLnd@l>}GyYzlf9*$ZDk@x8dBMQukTmJOk0UFS zCMy}xRWVJLPDRlY4vEaz~QG=AiY1y)Vt2a7nF`f0M7JR|mC2d;9S_6BKU#;(TX zWBc8-V_$RHf6(b@PLokTFmY!lRDO_&u)P}-U0~-AQI8EhsK-9s^CCNWI87#DYtJ;v z#O_CF$F9fH#PlN*Thb&M+k2&nTa|mK$px(SO_Qjf7zdBi2|WGSA=aYPBo7+~Fc3TN zJeelOODyOq2EwipOoX*jX;S?%j%5IBicga**qWHemtfg>a+<_o&qOB1#%I$+yGnmM z8^YeHY2w0`8EK;XRqz}~RLqKIb41uWkA-04{4{CsGYfFA0PK1pO?F`8OB~%Vl$~iZ z9D83*`~N7q`v9q`vH{?uu82x{Q&cL{(NIy*Mx~;noRW%?@|LJ*YfVN*MKvYnE-cL5 zWq}13y1Y@5QH_d4Ni`)FCh1sISXj5hL_-}7byc)$Vo_1&{oTKQ_k2I+Ip;2Z46|Vq z)34bfqi6N~UKb`Gcu=Xb<+{+r^cUBK?W}E;IY!&;^dM#Su=HD*W9yICh4EcJ zE57qOpQ1DVp@vK2q5QBE9jwFS*M*skpK|8R{%*pe{>AIUq)|R}zSo(v_L57)%0G-d z#Db-sFpI52d%{N6599Cggq^I<>ha(GrTX%o(D!>s zcSTQF%hCsWLOC;ExA~b~*%Nx$XnwFKtnpC$kjVaEfm%;k&&r2;LYp=2V9F7;xt}?s zKWe|q4%uec;W9K^KrDUK!bSOGJ)tzlhUWBy>1=b5(WiStKE~(&JD=$Z(_ZF`>ph`n zqRM9tRBnE*C(KhWUt{OW3ERrec|Bp`5hl9U4q5(uPuR>l_p+4O;gK@Qtt|HoATl4P zvN|9Wf3hL=L=BNGHi3o~_cB{zf|r|csZ6lCOn?R?>?r4)r5p|Qgt@FOm${=Xv_d^o zu3>$ZOfg&C6J{JOfHgfK)4$E8a^*`h+9)2rY)51Hl^*{k)B@bV=msf1#?HT~o>5ak zMVTGu9Dl3;Z?tgXO)ei(j<9sIyKeR_(7a;YK@Qjr)pm-;=2wj_mtAes{J^wwx(job*cNAGzhsxRLp7GF;Se z>Is!s@y9)lFxNwUvrEQ|(Rd5o(GwCACqL~8Rpp#R%5Vr4i37P-7 zC(Jxasvoi=mj7ZRCLCOAVo zXRtb^H>|Nhjcb*om-U7{MLWlzY2G7x!-k@rvy`(Vd&AI~-v3(E8@8%wzq~h0nq=Tn zy#@CE}b@r1?#DqJT zF*;Ai&Jq}-vmFgHjxayBH_V%C{CT~hw9^k9mYKb-H?-7O-elZsW$MknKL6vPewYT<$&Fb54>kT`V(`k<6LGS(Bd&9n>|2qZ#dKsK9aJD#4d-N{z zFlW~k0lm97R0}V3_N>n6ZG_xIHbY9^AhP$!gaH{RJ>>o59QE;gMb6SiCQzTUqg;>O z3FY$pr1Fj4j`#P5Ey_82l;ewS>@WUQ&09a;+ zn@m)mWuiCP+2w98OWn?t)elPXR14R7L(Jw?j)K|j-jFlDTEK61L?7=Blg(H9q&uQq z{*(w3f3^WB9W6Ep9%6V?{EBW(Be zhNK95k@vhX5#Yl%G@w5_gWB0%YF;*4L%m_Yht>+O!y`Hl_l7>^t8`!|^?I7P^+i7q zs#5+X{ne+89@Wl?tbEx5OgM`f>qR>UnR6|xUvZR0J-0pTpa1LYycQiDIKt-FMf{le z^cxmrlQj#Mn~s958@0bxCT{lHFi+Zy9j5UIIurr?(CuaQHg|)S+g-NDUACV{Eu%YJy1zQpJKbjHTl~ah z=Pq|)w+yre%=XW1afiZ4o3I7y)6G$>RH`xLV>mZ zB*3Rke7_%9%IO0##?oJmE9yD*?K1Ue#%>=9FKVan;x1^ zi=6Fe{Akpne!~1P=liP_>LOe%N04HmXlAm>hmG2^8|H`ogH2;KkQ`r1%X_soiQtaw=ip*bd>T3`k%~IUf5d=&7G{&}qWmutX|Mg;&Xn66^B(p8k%`$B z+CM)uS>vw4|IQCnKPsdDn;&NBm$Oef3-iNV<*2kEbd>8Hf3^2N^Dygb0}faaHnM); zg0Q#npamf@pv~@&S*UA47-r0M>g#M36CS)E>}QMHihiROgz4`U$RP_t*BqG|y}++5 zQh(@zu!9+=e%uBRTM*VaJhTsA;IGk2-IxVo#wRTBG7GbO#DXxwobe|OIC4QqS&9~f z?QF3;*Ijw}f-sLAZnSXuD1j-rxu>WXrOjkO*+9(FJ}c0m~Z zX%QZ02W*d%2?KMkQSOXi5XOGS!pG}(ks~-^LFiL1owy)mOv?+xl)8+ZB%s2R1yVR+ zK^XU0ft_k&Y;y~1r!8oNnI=k4TM*{3%|4bUN~sPl#-B66=~B-oQ|*;A>`1xIu4{}x zQ;OM~WIWS3X+?lslXlo98t)#ulsd1W;*M&_h;{I#$n-a<;fe$J)6fzt%#W z$>_WVVX$zrBPe|Bf-vdx?gIDfUwWO1->054S>_y8*vBeUmfoP=xN_qiQtzSmPAR=k zr0y;T!W%T|9q0T1PvvTo* zu#=6Jhs=WInG3?0`69f8?>F(KcA(t3%mB7#*&&;kF9_2XsQ-X={hHk}aj^|txge}n zpVkC6Q-GYs=)=yORjy&38<=p*Oz(gFDrc=C{)mB>h+JJty zyCaty$C`5W#|uJ5x&9NGVVfHmZT9{*bx7`z3KgB7I%DPZ&IMueVjZ?D2&F3o_A?PH zXPlwjVU6v(rC5FWo&{ka<6mkYJg8K=*JWh7-P@vH#6ZQI+*7bePQx) z3!dH=Qby@M{R<^&~7sjnJ&kcS4)|>W?`ZKyi|1SvW zm-;i^r9YdE5d%_@{nG%(hb;8B)^s>-VHmgCj?P#Z<}#kTFtiJ2s{cRzXDl+8EezwoRJ{LxUKr+hDDSj@ zGpawhFl-|sn+R;~a*k`9~|7&3=`A4Sc-wQ)ixx+n7 z_Ad-mZjjpl+6j~YnSgPyldlP+v?$DBdcdNviOGSBLTR1$gBFDuOu82NV1n@nFA6)E zk6IKaeBEo;Ib>0&e_g}qMPUn*Ll=dO_c*Jg7KPE@5ZKX+d@#X)v5P{J?PC^&Jxq^X z6sCMrCXQPa23Z-mC}eEDYEc;9wD5TXVtKNFn6q@Feysn6#7_w<02nKkcl@N_;U-sZBZC|vjs0&6l!e6i^4j#*~JTe_X*s%=EaM` zdR8u76!x+`%LcS3moEy9(d#{QO9fk3Eeg|F{@5a)WH2Fzi}J@Uz=RoVpEMEca~Js= zkIJ7CI9r^-@@Hg}Ifog2)_B&qohe7yp0}tG#(YaEu3hAl40@ivKg|2Vw&oV2$i^9~R%x-4vV>Dl;*yIS?++Vn`u_%n&Ak~W&g~{wNF3SBf zz-Yh@*yIM*7Yl%`K}S}!FA>0ZEWC74n8-G#v$f0ym<-tfb8aZg%Z)F}9AVs8xhRbJ zt_9XeA!}cAX3RN{^{=}mtbEhuEXqx1%j8B!!2BjhaI5;8jb~-OBPhzZI0DwbWdkgI zTL5fwTj2%)un~R7E#GLz-?cEa@4MxUf4nHs^2rgFI_t3oc0UlZHvMhmj7rX zw*Krb&>lVDtXbnWW)BJM`;O#cN5SaPMWN0734#B>`(Js|nQc`u!FR#@z{ICC!W71p zh7XO~Dc2R{xA?3GE9W=Dq?U=Q{@XE|(;B|_LjV`LOFvXU!)MBvzo!vmwk~Oe)ckR+ z5t_;=Hx>P^^4$|Z^!}GW+VC|SD*RzI;YT9p47U3Pz>MoyA83TiFWr&hMo3tFuHmyF z#yxMr+l zR{}XRX@prGs%Ir(koB{Zu$isbh?Hq13FTj_KPL$@Sv}8ASe~4OEv&pQ2_wuHZ4=n* zwX;4Y2~+MB*c+0Nu=Ym%S$UI8u{1RalYe8}n;UlGq4gF!WOBYUW36i8-&*Kx7G``w z64IhP&5_(AFitLfha*wndZ&eyYtt>9>Gv*~VDxS~W|MhQf1yCP>&HoduwG+^RH(=~ zqiA@Ki8Qphh1tbY_(v1WbTrH^afw*H)XrJ?ptJmwRDWFNSo)+R+F?G{7=2m*tTSiE zN%z~(XOb|Njn3ypYT?o~E{%%%yd>;p`C6Ck&jMi&E1%b1cwG`o4>nZvGTA0Z!kYoZg|-HAAQZ4tEh48BhF-< z*QoFtNmxt&-#qMQ$|0HRaO|T3yiq@vZ_=;u<|M4sUgsX=Y`q0L=Do#&EPcy{Sh>yk z$E^DknP_;(J#1yN+2wlN0<1E=LkCuVo`ms#wUb|3u<%z&XtBvXEd5sh-NyY+%31%t zjIfotTTht(4>H2&Pwo`!JCd-U+5O)CsZUzq0ShtRsRKJ55k6&s$DAcAkJ}lezq;*3 zJ;#oy-z^}fPiSZUq=lJ1^t}Q) zu0O0}BYK4ZJk(yv(#|7qcq?U3D4EX>M#4P^ZyM|NPBfBv^1qxV~o^^1)=Nc~LXSi01LtX?J~OlDcH%l8Fd-X9t@ z59KRdHs;*TO1CpR*uX0V#11zx`jA`BxYi%0j56-S{XPw29NVmX#KMOdH`^s+#$mQT z>g{22wL3K0_>Va%rgQwGRntTEaSOBc2`N0(f}gZ7TXUTylTW$TY=7EYa+rai@%k~V zyBmx?C&h=G_!@VEm3bCs{o4MJvHE#;YK%a8WQ6sF+SzV2bnuWZ(cxuwG~{-(vcm0V zbyz#wsrUW}6a1euWc@2%FE+pG?O?i2`;q#6Lp$@Pc2;ig58GJ3r9X_0)PF~Stbe~h zBt^OLBdPOHzTGWl^A4$fx$<3JL)P2w0-HaVdgfcTA7$cuwX=1f46*Zjmyxv{j_zpv zcltTP?4f=iHj$Y}oqb`)5sVe+WBp+!8|}xvmmVs+`@{CaC!FCie9~LM=2OnNa6}+% zJ?;H1+Mjh4zJ9o}$4|Jz=lXs4M8D@m>{ZqjI&mQ6Y_W2(yHOqp^H@GfsjqmKGDuuXJfyI+(Y>kJ2`zIY+!t*oipK>Q$;#yAPlj^ z^+oxt0lzU&JGZ`DV6V}iNo62Rx=?D*l}RR-4TP>4=D*gs*!b%PLWiaK`n}IQ3;Zk9 z91rdO0sqxoWQ*fi2z_j?keSn*;TJ@%oP0^-%B8P3vWx9-oqnu*U3sD-;uL0F z$LJd}$Ao*>V%O<5_)VE*`(lQU@AG$M_T99)Y|486$lx`acBOYp; zaGBI@61fQ~tSRT*#?I|_Qq=#%M6(3QX=e-g4imA-x$5gbRc42~i+*>S_j3KV*qDA9 zYs#&=WcG6Jf8}nkg$jR(D~!EDAdK1OFiSso*@}AZFZ_kq?E~t!O0@~wT%+9nrH!!s zEARVj^y4J9IH6kr+q{lNnZwG-z1Hpa{Uc`AQ!1jW36Hcow$YuIMB@j;P3AZ5h>_9KBUZ2brxxMPkkGr&tc1!V9#&ZtiC%jE8Jt+g{spk~NPq~zAay_df z=41J3@BhAHz%v73>SQ~3)=#dF=&;AzP?WiYouaJ1^}I|dr+>4+Yn3^U87I-db%trI zzaYhhFZuyxT;-pRZnmTRx1(k2e>TSYfsMtXQw%(4ap?M}GvQ>$U5i6Ea}E`bS{!z= ze(2&b>1zFtSRB@{b=2appXFl~hxlXak6j#6c9^mJip8PwIve6NwwN$}<>IiLdBel> z*Gtu_7KcH$xQ?aqi^C?y+|DLoQl6vV$tF^6y?Sxj$IgVsVb&Y9pSsvrGD`Jn zi+u&7yTiC};^NR^i(46;A>gUXXD$xIQ@#K7vljcPl!e*#W&_S%9A-0pjnrGPc8-BX z{ke<7gtwSrvU)aOyEyD&#;)^~U$;0+VaAx{*PGY)>*_!G|s(iB}`FO(u z=Q}eMrMJoeD;)h+^&HQX6?VAs(?$0<345K1&hO6)^63#=zBKyY2$vjIMkW^YH?^}9-@0K_!*J?P6IoC6e*(} z>gz7m{pwkIP(72!-5CoucMJFe?N2TaJ?xAqe^wwbxXi4-xH#-!{tsvVISc>SWn?mH zFl^PoHEOUCG8NgOgJGwN(qV&P!ZpgA!P?6P!yff@j-F;9$Fp?AV5qXfRKHd<79|3kj56OV2E&wj0vdNKg8-u=XM~CuY7%D1G8Vu33BIf3z z{OZ9lOSyc?VA#OQ#KEw?D4!v~&+B*AU}&=W8iBvVg69l|5#@NY1+UX@iU3)8lK|P7 zIv6JP2=Fa~{yM)v8gCs8+dS0XE@BgO-eHHm0-8P;X0!V4!LX6}g@a*l;YEXC`g{w% zZ!oOWKe~7@WK3sTNPYEEnPh(1U>NgG3teFYY<1fx%OBLAam_l@z5n&A219v)ijN3D zMK*gdOkOXtkBP8w?O^Dzb%V%nF=12cSi5mBtYvnSoiV?8Ftqywbjx5E`z=TG?ZHrE zZNp$#!{&De!!EYIYvFHe-zbxP#XtXle=tm3sN)X@LpR%-90gmq3rNTMPX@#GqJ7I? z*rMFI%LI$;v^^N+vh$0<&|-V51=#$hyW+Ku?;Q-&Sh~-VZczT6jI#6xN6Y%3Wav9Z zhx;x39Vy&tB6c1b3|-%~K*t#~easGu@{`V%$sT8WtDWXj&eBUVP?Z1Ua&5HGp-aLr z>xV4~J6Jn>Nf`4zLQ{l3(lvLtjfI&Dc<$E>m>kMq!@f71&d-IaeVmxC>==z~??_CmRGI{@!uz{V6m-wnh>u_DM z;hFj~Vq>d^vWK0Fxrc2|Oa#KIEL~zD)-GET_A@Osac$O;5cLa)6WHcd=0*8O%9k$* zv2w=Q?68OF6-z>s?JJh}e=$Xaift@^V2MvM2!uHk&M;Bjy~J0rYroPC2fR)k#~LTG z{h=jcJLB4tP+4por?K_nC1H>qu4T@RMfs{FVQ*2ssv(twCjQ70Uj|`fPG-#MY_e9A zXGW<&W7RV{T%?ZESHD+sv6YJajEJkmFdMV@HfxWx|Z_m9UpeL2P1>(n5;m)Ev^~sK zka;ml2j%2!zq~cEUO*{ls|AVP(~lu!U{zWBCg* zyIGlaR#TU7v-iLHMQ10H8aqtbb%#s$r6pksTb#%8mklV&+{frECj6ziP(~^)C-t5fH-(j@HM%KHWTZ-4W zjZGd(KNm4mPT6W<&SU)-A}#!-GcM|XWhcMvDkZ-*0ZZHT6F|%%Hn~oHdawSh{ze9V zWns=K{H-HmyxnV9^xy9N@A|a}?{gMxF=hNaXU5uJ1hh^2BaVP6x3To-lF(k}tl4$1 za>saPBNk@uX+H;kV?NF;+@n9M&v|Wss~@X{&o`vpL!3(ylNVg7?NY-!T zpB-=ptN*fN#{YIyO#kDx`kjULTad|rz5mP(UK;i>9ktXK8w&W4r6FO9+gNRkUK*lI zDmaTd*RXo%(vUIZxIdWiu%)4!rNftowM@B#(HP_Zs2`^>Izqk7#9XUfI&x_kDKf?V zY;*dMb=b{D6fF%M9owv{h+e+bUypO<>}KsK6EWisCP!Ovhm4F}8fG(RleJ@(hFxrP z-2E0jcByaGSLRIRDb8alkXUmLo`85`1%)Lebia`G&gRHT` zb!?wwe#Yl6^`(^RIk(}Ve%{isi5d5qs5#lrm2*ydSU|5^8U|T=y_B)T$_nGAXn#aM z&SC2fGQs4HGO4}I=uzX|v^30M#v#_H3P^jxM$1FX!&Y{ylg9H+|Ty3r6GRYf^T=Xv^P1ZTzkh-pa1hvdgszG zxoF^sa(TKG{gv;MLbkb%o%ec;cI$W1(lE?8HgPeIb=KY|aP>L6p3wgOrJ>65#oj7L zGX=yJr#`9vl7={TinLWyfrDZ!y8;j^Zf+a4t(%I0Eg> zLgm&6ELgO63v@*LmBwk0Id-M`hKDI0TAaZ)Ys@&09S$+)I+i}TG_)9TE6d!;3iq(e z(kcsZENh&|I;S$>us|xcrC~c8(N)guX%l`#ggTTtn-%sH12{{2?V|!<{u!5(rO$f5 zi~bz%hV@1LJb^Lem@n7}%Pd{%s2Oq1Gv5Df*qIj-tTNHF2CS7z#$R9R z|Ml9@H(WNR-;{a-o9t$bb+$QJOxU!uJ=(d2l^bP**-hS(=WJxXd6|97>&twDqj;`i z;H^45FXHdnIpZJL0Xr=}@mRXe4*q6hPG;wJ@4W?cZe;1lZaX9HV3{MVa6hYzQuA^G zYn;M5XEZz{9%@WEk4+A-#dU16#f)3o;ZEk6H0GSm=nf08!u5=~m38iB%C0XO ze~0&ff`?4SH0GSm=%*%Nh3gq}E9>0NlwE5~zzNJajX7sCy3=@8xSlb$vd-O1+4Uvk z?`)XBL#ARHbIxY8#RRNyJ!5WVox7Q`>&uRc5bM~?HGj9zeu4lR7 zVY7z{x3kI)WA0^*qrYNdj%UIOQ%+-(v)JNXwwW;F8g{sWIk&KMmw&Ec#NBL^J?!&P z;h41oV3{!|v&QMHvzrO)OgYFV*RsWpY_rXbJJ{g}bM9y9Zg0a^1;7bk_5PPVOi@wc z3|3iV%z3PFh;^=G!WL6*Ws^JE;vTkHxE8wNdzXf3=IogNK|A9=X@AiIJG3*sU+UTUvkWkMz+KsE{DY2+$wM;7`d=)> zc$ayYJ#3zr%=3u%f0l=+V28;c$rIYydQv7BjacZPCVtvm@HK&O z99x{kj8%3xlR4+G^o+NF5mT0*@&2#(P*Jg&Rc>d@4r|=YI!CV)2*)#Jg-uRli?i6~ zTxLwz;Tq=Lz|ync0!GYOezxH?@K8~)k5!KOx&T;ajgwjDbSCU($~v1IWQ%Lr=0;|m zEe)oW~A_82!)N!x}fS&TVWoJ#;*zLBvfFv6~s|ESHvrA;xU7#!XDQ zjcs;{`U94QaW|TnlNcYk%-8M7=t0ZETDG~BN!PN_E%5ZBDEen%x;^E6eolQ>oH($0a%w-%c^LZaTKWbSR`yUG)vn|%Y%ve0+(!KL=nWnp5l-m+z( zrCb{lXyes>iRAKSVLG!F%ff6OO4lz7sd9&HwuhI6k)q#9DV}h!zZ)tOtbAEJqZ?%6 z6u(sRW|?6977MWSZ98SU!NRBN_g$%Ha;y27e{Y%p{^!BR)kEnt{%D!6mk=RSR=I&S zPS)Py?4sXo%lvP7zYUXZ?RD;8$`Q7>pKV5d0cpkw>~O1bwcFKCH2&^oKC^wgo&0=R zn8%E5roS)|TMs#-GYTa%m{!j7yCnAC)qZiYn6shC+8y<~+s+4uze}Ikn5e2MvYI%(%TMcMbWz zASpk1DC}aBdzo|0C<~1m3KLjiJW1vb9rDR3WzJx&;i2XsexJd$hTQIvoS;d zzrQkvv}at;oSRvGnSiyIk5JE?W6l=%kpk4-6v8Eg;TOPPm>KC#o;K zN+8O0jz8yM-~a7l);V@QUPO$J7XUL(IakLMq~5^jL>VY1<~;Q&TkMntz{*JiKF@-j z!w%Ooef5xU#V~$?qnIpkt}{>dl%dcwxnXA>+A3Py!8SMPSU%On>~PX+wV!5U)+Y{y zj2(`7oqneakWKcmeTE&fdZrz|-i{{;pjeQD%1ySJoGnw0DN_6zmx%SskpD+(C+8Z# zloQ^de4dOH6R@USnyeqIuXX9z=D0VyOs_W&OK)(8*x^oA-)NyXsehA8$QFlLpE?v8 z+dSkRx~6J)v$ufdw+w|oHo2L#^WAE8Sb4Mh>QI==^sSD7+1o7e7871D6rw`~#8^3* zW+8UoZagdRu%Yv{v&Po+A%CU9fX?)xut7!jT|;4-a>m`t^>^Eea+Bq%OkL=aQs{C@FMNZxsI(^hM2z3T`1<|X4c;CZoN$)?{BzF9@0y7WbHBmT)s zg+8o7hx{r59BwBcadztC*>?U8?d)dyQE!X(j6IC5mI?Ja_cHmovidgHyi-O$F%&i` zmp|#!DkmH>-FWU(-zd-Z142deDVJ!B1vsSK;Z`<3?e?p$*ZD5>>{G6O*4v<*a(z+H zb?Qr>b0=6~r)cN+cboqj8(@5`Oceb-Z~k|C|7#v5z08Ey*%7lI6S6YjYr^INccCaR zbh(Z&;i921nYp8j+3Xh(ON;HC5jV2THY?o0Dn}S|KWiL&WW&xpOgvJAoXV6jo1D!S zd)VeMGd9`bCg$A6(x5xUh&jvbiUh!Mta1`#R$1fBhKIU`In0(y4Rdx_UN+=g?*+76 zKrF2gKvCwlqI|stW*E;ZsblmC;sqW+8S(0la%lGl!Pu4D9N@BdB@O%LPV zYvQ#o7o)E#zg)yzqujhf>X>}Zt-nZM-xLU2O*_)B!@bJcO^znk?`CfmJL}yAHoqk! ztbJRcMSsp?WrO#B()&dC0}H80nJA~XNv(35Bg&OccC1|E2vbgYzjp3duHNnlk5cAL z^_?I4xxvzA8D(_GP#Ar&b$%)U*6ws?m~U~3HhL)CWnz}^Ht|dgwxx>kJyON`&%KUC z{V%*em*~IMM9evl?O#eclV7<5to_<$y;NY^yw0rOCm=?d00mm%9A=F_2*5*qhqFFf zsyLR_`&~NLnHJ?gJCd;id_am>=M1(vo6$}?VudL)?q%&knX_>DA$NmqPP|M8|Kh0G zsO|E;d#F6@MK^YcYtOmeACS`LEzIWMw41QSHLT`- zfD{38FKaJ2x?}a{6gD}7ZPu7^9?O4sd0E=)avtmbk3DQtk#HAV%!>{$3E((^aXc%W z!h|t1&SB{vQeU()WsMtH=N2Z+m~uCp+{YHjG{%Y0Lzx*Tv%~4k+0F7l{TacSLrmCY zlbhJ$HnzEo9p)_Uvw>IG0LQV+NvyKUn2nhpY98jW&ORng+2V$xKG+G{+`*hZjwCv0 zdDx>|W7jM7=Xln-mWQ=09lSiWih6EihaE-EuQ?6x;8=0}qoI4mDu{?~h!u^aHooGBKFl~64;-SSE z%vfX2d5n&f0amzz%uhJHV>Q2rJl8w zQa@z;7X-#Um3o$LSRNYDay$B(R28nXW5(ZbJ3pqwH=RAJ+{BFI=4ijsS+5ZIda3`U z_FG)eRTlV;ow9PP*Kw})jr@W@e&Fa>`;q>PHrY@rBe#41GaWm3cwbdiw>aBRN$Jm| zk`-21<8-F1vCVnRImGf^0xjC_7C_O?(Vv$3wzFo&87$x9Xc@DoXuqeiJft34DmJjg zEk%c4_<8Ud9XNq4PGyHP8EutfR+%v78rGQENcorME84lGXlGWmb2sbU$F$*LOkIjt zW{Z>A=5%K4X3jcGzjEmqaV^W-$O_x6atG@iVa~~))&6UlUCn!KKso-6yP(|2J#11D zZC~zJqu3$Ge$GVq`B|;pW>vZLJE>>H@&6}s&SLy~J7=5owEM-NAuHNB=8NY0gLd_m zKbl85XG=NylS})#;-CLL%+pZXVL=T|wu+7%bB!I|uU@(GXBkrNaN-(1AoWH2PCHSK zcDVz}F-Mf!9QP&T9=1XCZBAFNJ|csKkIKlr;{Er~R*^ntfq7ESiC>n&$6Xdy{_5ug zJDjY&yju!c;~w>G&QWeYVcb^)@T8xR$~pU#lMxxc*0`r-kS%Ux&g~5km1j)Ej8i_Z z!?Pk}vd3j%UTC7$b8hik6Fu)I=5-ciH{-v#WbCj{d-Q@k!0O+<1w8_M(QC+TuRxiz zkI_rs|I|bIA0lDO(Y?z5bhb?Pxy5Y#+ihj^Uw_=rx6uE*K5Pa@RajaPCVf@E16G9n z%B=%egl^@uYeks8Kp>-5_--f*AF?8huz9Gm_UOnJKL2xr36EY8ru2z)?20g(IeS<; zW`*x?5;=30k6jT)FLX34v&|{29JeCOV~xX1xs@I6Vl+-*taAJ!{a&%cXGaD4ipGjC zSX8`nh5r_7#~jNhC$i0{%sEG(*@*&TK1m>7b7{}9Q%0||BbKMG2)kK5Ux4e(dw~tH z{>~L)bK!+6{Qm_3&sY(rF>bs^IfAv-C&YDE~=6yQf!gj6}ZT8fqHJu5<+ zrCxzEUtohb8sBH$8@>Pag*vFHEL!2e{~Oq^!%YGh(1Gz{?X2A@r8nEr#uZ@}J4{)> z+udO6eyLt>o(E)t3AeDilZ!351$8ULgHB@!KYT z^7=5h@Tu#=21ZX`ANCYJqkV$_*v-qCKBC`|*}I1QDhCT* zXdeAqmzn3g>RBnAH5}%$c7?A}X?duBU^wh%!hOs+`BoEj4~OZju$xuZ8FP?zu4TfF zOxb3WJJ{m1?dIb=)~+1(aXy*l9=1N%7!DKfGtq~J!)#VQJRF*Aa~GRe4g0!%<&TJ% z@oWpR{81Ay;l$tD5oa^L+Kw$8eat+{(Hv!V7;O~b$A?3l>Gz4@u$i?+UBe$N{Mq49 zWx_s2*NC*JpC`qCv;)>nP`*|_<%E6ga5F2Pml5rC?p4lM`I7~%b9C$snvd-z!(l(m zONYah9p3+@hj|{F%bY2bArr7Y>`d>s@Jc%=Ts0gzOuyhP|LiEz;jrF<8Mm{vdN|Bc zAFmnq@jVN2AEPhJ&;$I+a7fu=oAq@zwzGKuzu}B_s`#cI6gG#$R#t8t4wD|V0Ou6m zH0&3Ts$VaqEZt&<4=I0Z*e{zG7&o!QoTUwR_!j|j9&6tb7^CmX_%0jdj9uRU^j5c8 zMRlVc7CZUgaLANXj(J$e?@J-;KNt?{*lD?}Z2oXKlpo=30%U2Ej4)+~wc9Q9sK7ac z$&ZJ_P*LVqwtr%SjgGU}Yyx)f5FzV#O4;`eVDy;Oa|T;mhC{;I&-7z-mlQMMtk&Q2MI?e=fr;{l?{G&YYF)!~Xq$w}?DUwP19gGg5AIJL|t64x^utnLo+^ zbFO2&!`VH_2fUW-6c*!mx}-(mOj&-=Tf~@a^=oklOAp!DQ|ce`{#QLz|6*rs?h;us z(ZkMIIp@R?JMMV>*y0A39&-eY8GYYEj}M2jPwW3zKQEL^yY*LYJz>X8p49$~`lp6{ z@v#0Q0@klJ(lB9B@wA1RbJnwbM!gP|XWb3u>T_Njb~t5^K%XBD+qCEGQBMEnHDsK- z6VJ)q3pP+Jz|lXD;lI0t>XR3ZW9cQA_j%=phaL|ZH?j5)3o-tuJ7HkTA?A$#CV+j; zUOD-<%h}TZKLTcx!`e&x?OZwLFr)u^?~8uirak$ejOGFij);v)X{Ar6n1Gp%r2|%m zoE=Vn!9)kH^o1k>~PFpNAlT~p~faRF#6oeu$!f8R)#4r$q2iD zq&#nBs59aq%UsJUH!^0MHSS=YBTP8&rG}2ziL7Yg*xNL4BAcAb7Pncj)w42;{)YwU z3xILo%CLs5MJ6n4tPGWZGLeD8ehU{47`Km$SBAK7P=JL?R)$Wacvxz|e{q?e6b?yQ z;qsNC^lz?M8KxIrzcQqZSIPwQRRZ~sRHiG#Ff0FOLS|odbo*`SOESyoD=Wh;w$=*p zzsBDn5F4wrF}v8QhaOhftqfb(;XanWE~N%kzu`zWNo~^vtllVftlcC~CO69g|4h++rL%-;z0&HW>e7tbt8TdZ~H%TcwcStF#ZI@BU z+E(p9G10GOfax|z6YTU}mrgnV?aB~s=I`AZmj1NTUoH{Y{VPMCe$5Bnt-^;_`XIun zQsprlX6Z?1mh0Gh+5&f2_?eYHP%x@g-XlWg+H+EQz^GE^`IUa}w;kjweFe)X|FL;x zn4_Hj-45A#ab=ivr&Pb>C|Li8d71o2pj#Lm1*=`F!VXqOukv?H1k^ZuRha9ccI2wC znbFa!Lf3&7sUKwRTyETb*hQ(vB1PtzQN1{r>_dz**s%a80Vi}volwP*({y4 zDzsSR+>>SK>{Vf#K$6$23LBMMl~ulcVpJ(RXO&;UB*o{h3R4c!&X^hJuzcRCFjc?G zWa}L?%D?}6SfiozT07IwWRubBSB0GADF#fCiK|zIl&vp|yeO}=z$r4(Tor~{`i>p5 z`ePe9Rr}^uA?i|p$Eq-a5r@=wxS7$NtHQoh8#-)R6)LBV@)65bp^u%r?2K`HRTw*Q zRH=Q>D!(DcPJX>AY+`lWs<4}--w5FJQKj_0Rbh~Rd3@N$_73CD(EmZ>Sbao40W>=@ zR|ND|8)WSXccI~-{nV;3`d~YKMk)=6pA%Uz@NagmzWu_gFyl-UT=Ip`WVHDUVQ*0$ z`GOCX=zl;O)-yja4f~jOrD4Wd#*b3Z&LQfV9-4;uZ1snyzOuoFk4=65hli}J;WZ|l zuYu8`H0)>6pN8ob?YE|3NFW`qW3n*~rBRN8g~ocXXSA1KNb+vOlAXiqpzx!!h!%1sU`r}v~`u5$h7Y1qt^ZS}2R7=NyeY!xsYO%L03$e9)mzf8kO zF@W2P@~_emMFRV^z|Ipnrzj`e9FcN-Z|axNSeP~S`EO)UxxL*HOxEu{N5~GhGW(sQ zd#w%rUI4H4{wE$%6>*k^VH0G`iVlBBeY{4Q(^>wboiSy*DF4Y3740m)UPgALp_^?E zGrixPV9rg&2L3FgQ`B=-;R9({JH`87-6^#ynjHHEKA47W22>srp>l_VtpCM=>f3A= zqA8}-bkDBl0=Ho8qtRsLoIfBR1Fj;+@vl=S$$3?>GU(>LI&D}25 zR1-hp3|W8Df=r$=;hXJz#91@_Pa3wczTe$p#>!hP90bgAX?2)xp&HxDtpiqv()luR z;Oa1y2^&2gS_iH68_xv7K32O7P@i%?tD_94ikN+j4p|*Gv(CNjaPnJ~N3RZbR>rOl z+t@m0br}0L?Z>VTb66X{I&3LCes##%JYlu3RxK7jVRdM+bmHo;m2p`IHd(nq{mHAt zJf`eA%7m}hzbH>w?fU_=pRzhkoTfj!8J)V?$8jvgivD$Wl&hz$4%3ulmftSWiH+4^ zmWSr)t3$K!%++Cp(WKS>KED*6wK~jYiyK%ydv(}dSXmt=z0(BeSdcBQWqz)OSUYdE zzg};lDKf&&8*Gf}n{41+`mxGdW2%&T$heiso1M|S4Sb7~v&kOj+{E_zGQ&>Q&MvgG zw+fJzx7h%r3oI~0KUP_vwmKxtxP{5vSBHH?nUmk+{ja`5gdTEkW$T>+c(2H&3xI9T zlCsjf1fm>YXd+f;=y#C`-?KW*X6?Q11l!zOlrIvPaZOfY^|3PR?~_SZE|$sI`(O7k z_I(zZ>1>!?x;m_5a@p#zlhG{g?>F#rnJVmF9d@wIu8Xx_X{W5SkL3>vq^SRp_L;nD zbr=>%!fxgAM_2pAh4I{XRKw0av@~?CmRi>5tPW$2R_3%zls|3)wz-YXPpl53FEx&n z^ou^DpK_-za8^FM+DA6@=T7DF=WO6IndQvFYqYaDZ*|z!C>HXtpOtG@hfG7p@ndD= z^HRquW7e({D4UFCY42GbW-#e>H<&SJG~eyM+)*)Ro5M^N$Q+|SM{S;%jolt{578AO zTWBY&F7mpu!xqcll1@=(H9N^XXES0u z3yfK0Cred@L4`86vce`~?q-dnOgQ#P2{2-VQ`qDTwm63=E6hD)XR>xCS$&B+!id{h zSnBOKD*NxhLQ$c~*(`O+lqt6|w@gBexSIvezg)sy{u{xh+YWq6qCL)sq6<_fo) z$-@%9!h+U%j#0lvSXl45viHBXQRZb2Y_bz9e$7N|ar~$4$k*L+)*f**Ouu1AB$D53 zMLB#yG93|^pB%ZZ%4-4OMmyVVQ$Fs@8(cb^ucWt4DJm)ZCg#|8Tkv%MN zm}NFt;ZDZf!y5N9Vg79r;6ye!l}*lMi)E&qUscF`@1d}WdG@l%IxF19gd=QnFLPV1 zhswt~+Im|7v5|FScz|Hu11Px}E&Ld@dWCBAA&B8M#r zldcwb+>$VdwZoT$I+M372`%&Gj;JmPW3I7+@k{(siGdu?8jISKw=M}aHjnfG;|WW` zWc_s(+2Sk~j$RT9*J^*;k}!|yF-yW`M#nA*DND!eZ#SMZ?lNwoL|LkyAR~p8!v@q( zT@prFoV+AVz0Sm(akoHkUlKZ4IDJXzXIxkk7U-{^wIpn1>l_QX-U6l?&(=F7&cZbP zjL%yV_OMyBfE&cSa7h?pwW%4} zD`w?Y3wyxxW0!{MU$(O+FZC~}jlXDVNWWY);QdSeNrW@!w6A#Z153kVR%R{@yO?sG z{>mjw!yx@VZP>%shn9x?gPyx=X(%(9wKOD5IpHP=eq?Ew!5YhKaRCb-T^eePIapO_ zDm1bHAESDH_R_GQWsdv2OgWj+$0foFV>Z~s{3n+B)+^(=oprXD`{dFv$`XA7h2Nq{ zc)p1_i8WTIDdaAf8B44&VbKHer(~E7Fv8rGOT(C3tdIq^IGwqvmn;FgN3V?hPEZVW@#ufy{5V}?9BpR>p=|_ZqEj^+p;eR z#0g8)uXAZw;|O!tTe1E^W~X+Rn7=_B#@x=7W0r~Yd5N>h&dm7|W~+L$2fJ*=7nb@5 z!4g^E?3i*=H*Xb?l@2RlUBY8~)MJ;6O)g+^*V3?=xx3wJ#+)R<1}85U_lu5#F?*PD zJFBIIGF%}Lr?YU6vtoMh(y)`YMcM^wani$9a{tmWm$`?Q`X`$v=yALCH#xRf`@`x? zdc6(I4`^TM`TA0S=pgY&Ow8mPj$)PfKexq7RvEa}7PIkV1G5P^X0-&i**caVbw`+c z%;jT~i;T-{ch-p=WIGcMGUZ6t{m0YnLZ7trYpMb%LGp z&mDDDp`fsjMYi2$VoqS41vWXIDQ7eHqD#aI=k*J`OF))hvNJ6H(owAw_gDHEwe&Op zvVP`X(Z60iR_7_SUNwNt-3GAnYXb%(@EZY`{MO1%*x+s!_Smu8P0XomaUKi5b9WfC zhfUTQ{oa|g!WJ7GW&RJ||9poB|6uD_;#5{RlQotZr6#yTI~TM57eA1g{?+Tt{60H& zr#OGNkSt-Qto%b9?afhd35)-h5R?DtXa2ulr%CQW{67;h4KioxfX>il{WYDTEjI9V zonZxd|4Yv5O&M<6Tf%DYM<2%Dv){gEB`62zs zcZRvFR3~+YEei1|CfaDgWPv=Gp4J)0_`eHEr+0?g+FR!c$jT=>LvEPYbo#m;-r5-k zS-7h+?9b}!J40!cI0Kzw5$l8EvAm%(O#7;Kme}OP|I6P0Z*+zQ3gsVkh8@g3-Wj4F zbElQE@k{+Cmk8`$`(%pNz<|2jiITd!FbMh$GeZdsW4O)G3u*Is`8vM~J# z6O3Kvmrd?Qep#roco?-8k67j_TqHVvStvYdAxAC?9gL4&7Mg5D%Y568{^P{m;f!l% zEDL)zl%_26+bIFhSr+E9zy)k_AM5W}7V_T~aO$!!iFNj~_|9cvKjU+kg=mX*PG$72 zWnn%mT+HIMWnqvdZe@d`RfYV!1^$i!oXF@rD`SlvS^Iko%<9a4S3<>QVJ3^`FY~=V zCgirPog-{lSt5+hDyfz^^iQDH7iT);9Hv%-WiH?zj=Ot_16rfhJ` zRta!CTb#_4MdmJC7G|-)c`UPowF{S3L&pviPj_}2D%_%8yl7b%`;-Bk#*_<~d#^1w zuE;HHvZ1{&LjvEo!uMGS%j{sx8WZ+s_4gak!Ux3tfjBd(%R*V9K66> zd`f&4M#R}E{)^(X8vn)w3i;o8t)7?hAD4w5mQt4}TghLkUi`bWd_nsGU7?fFfn8w_ z9a?PqpwT$jJ^F~M89d<>Ta-r5zWj#%OG#xpvh%Xi0n{-iE{)+6p&T_OIt_rG#> zSJ%(D2}_t}yOJm+kVdFpuS{y8JzlK0@JszHaz4vk z#F)Lz|4LvMIGXiy>?@vU#0ICZ#p=Yr2-FggDSKIdSt3k0%GxU)_^WJSj@to+zG}UWs6h(sr}CqXPv{WrClL6s=lu(bA|lh z-Ch>|A!8Q)*%c=K%S4>T;-~}}|I4k<+W&3hf7_}5bcG%^_Dh^8bN_K<|MeV8{}Y!9 zcQ9q!e(^$An9h1N*BurrG!N(w+gN)|cNk^mwcTOPf7Qoy`?47WUuT@1YI2u)@xbmd z{(k~;7L$Xz!ywCT-C;KyjDk1^i^IknxkcD~4(|@*UUQJo@9XwuGY9!!NV-E$c66EQrMGtbdw_%dFD4d{^&i>o z_x}g^KA~=(q;OC!KcPEpW|=7)oIK_r|NsBny2G$Q(J@vy#zc_->SZ?6E5~*FG8zGn z?+$ZW=lEBxoc-#_L=&kOPw-q;=R)-s`x%|s9i|+3kblN6aaJbVY3-%cy2FHnst5U< zPIt)fw$+?{koxJ}p_4UkW~pFco5ao#m@RH&@yza!JNTen?yPSAh+SZ|v!2z(D^D>Y zb7zagI(zgN&gu5cYKd|}_4OutM|Y?&H`Q6Q^-cp=IoFo|+NI+p);Ns`ORRG)OXqcm zI-3`D`*b_Lw>!-EjZ6GK3wwhtztlM9KOzC`xhowto7Z%QYT>uGQejIru)RA>SC2WH zwd?EzbJur=CJWrd){Ry^_8?!|;qozF>@4@V3pIC%wWaO?i(MA*J3FzwJCs>iB~cdF zNR-jKZeNx7dlPK1ayB-(#R8VT-5vI-H-BKofAGMgE+Z??xcw|V*B!?0mFV;O+5DNU zXJw?@XTND@lL>dT&Qa!mVPf&?zqEsIJjmY*R$UT>&w%ru2kwc7*XJJHo`5XtljnJz5^-FgasTIQ*6&yzwy<&M^3Y-wFAr1v=efc0M@#H(0RJ(LtuZUY zHWm(95ynrI;E^jrJJSg(e5Zpr$E@&&3??{sMVQC@#1&yHizluKJH;!Uv?4^2xRX|d zYP&-I-Tt0d*MD4vbjh?$9wL96~35=i&uojY<_t~HEdI;Jh&pXy~_jrE5aPc zgDZS#gg`G!Xqt(CB_Xzcvm*4f@%t5Fl%>B2_-_7vMMzkG=fh#lLyOok!#0KbzaI|c&o|(ZULUa}Ax>e7B^L6%K61%8 zE@JM`-mv=w?HpyoDJNPHXE68XULUn29xIHvkOlUz%wg853Jrxice24fEFRVyCY~e_ zPG!QGY_iN~T(3V?vs3KJ+PRs;EhUfwVjx-Sy_A)xEH_Y~6nIl>M1OYD;kR_JiCZPU=i`is<)_;s0VjNk> zbmNZg4K+5nW4iZ0e_U^9yU5m@)Eg2HrrgfjBwMGwe6k6%{!>hNv8_F|H%w=ZaaNz) z8@96ec8R~&_|tpCe3lC0uzp5wD9n)XnG$53gG|rr4f*#~ZOydau;6_HyxSJC$&}GW z&hY(K#9r2BNZ@1vIEnf98K=F%$sZ8s{dSDC4;at*gZi1j#L8!CXPkMdqs}aeSN))X zA99wgeAp3WUS>;8kZ|H9Rz9mY%vEo2mU`_YR>0_^#|t0tIj!0p~! zHd)WS!|TJ6{;3}qFm`sVF_KV&Th%LfSqYn*qCL8spD_N5;;EN7hcRRA@j_?M7Ax8d z)qC8+PYQgmtzvYa*Mki_a`wq@&W9m@m8Wp1!@ zpVmLr8>TV0(ObkCH!~V`G>jR2M&g_71f#Et&-iOz>(6-q3tyMb17wr_PX#=WH!=&-aG0?auZEJHq&90#)bmwl+|10nREQM0b#7xhv{F5I*H}Nn2+ra2= z-v8YS^}o3!pEuDyx6?#L&dKV3cUjotPA315;CwqYYK6vCI47(Bt2a!Tte^APWWV;} zzg=4O3R~)>|Cr}y@i>o_{oe1oLhirLm^Bt}k=g&Om=*R4Pz=3co4UX33_I29uU+Z) zgSPf{E5mFy4qO?AnQPO&Kmwe4njJZKrGIj5LiRKFhLvHI#jz{H%v&w6`o@)EvqI@j zD}8UD3E0mT+io+#AuGc+^*TqgcJ5`AU+HuH1UhtOXlKkB#^>L>()R$_363y5Y-K3k zuK)0rVUW2aR{D*LI%CgO8wxWul*X?Nis?wL&aNGJ5gK~Pg)uF8CT=D)4l(tNhXS|=ww@V zx`{bUy~!FIr`R%NaaP&UPf(1Kh$gcd)`1WA0;(n?0AG>gX1# zpSv>5$$Xdk8RAZ}1L}=;ON_<$tn^R4b(9t6GUfu-iUKirzAa{flkf2$+s?EDoWPU? z<}UEO{>sI6ARG5y31#*7JDPhXG;?L>WaEP?!)`{G+WPzKOlf7PPFKi(*cP&KnU%6W z%jL=1KWf57+COIN*_`b*v-AmP%xI1kF}_@)Oh2_UME4tCwldZ}y)tw#f2FO?+UJVP z;#Dhseu#uVx3U_hC`4CV0pn|A%Jf=+nZHh8R<0NLOCGqv*)zIPV8%BI%-sByVHe9c zdn*VC~+OKKtDY?{j1|6D-ot^!}Bhm&pSXV6@l~JS5So!tAW@ zWdSn3A^=MdnqUcQ5@h)yXUmj(7%$PkluPw9-|2ZK9LZd!zf)pe;#(kkwZ@^DcK`l}mJ{E#quf5-VYgBaGLq42z8`uk~7;Wjxzi z9B`+mm}t<^=x=PWBi)`GmZdvemMP#sk$Oj;GjeOthj1!U%Vwa*sQ(D+;>bkV^t_He&4E4 zX8HZAs$r)At@q1NLppO+NY(QnT;-2RB*v!p`Xv%kZ*n^GB@<`;obX-Ge|S}>Fq*x} zZ$i~SX@|aN2g|EMJIixdg$5h*EOe{(_Eml%X?&$>D-=pMt_u4zZ(kKk-#5V>wv@@8 ztHPpQiE)p5>wi}G6YU4D4m(+T!|Kqhzsx$Lv8%(xNA1{~R)=ls@u923eD%r^tHXA- zCaew<9gd^r3pBd(ZtoE#5y-Kcf#thg9YwplQUMC_@vcgAye*QZPIF= z|80dVGv$0nC$IML9TMP(35%ylSiQ!rtQJmP9oiC^a1v{iJ;?fLt3$Ni3f?XN^QT)8 z%gjBly|6mWVv98v&yXk^Y8r!Ir%cFF=0&SRKa-1BhaQQh9Q(8ten3BSGgpV0P3~m=lGP#q zjPWe8bg6zeN{;NAstG={I_%X@|F9is3UJx#FgJ6SEiyr#{puAq)nm4@{*O4zX9ePH z=07GO=00v5i=WW{Q~jLH_>*=btIx48CYRf(>T@3W)ao#uHO5T2m6a=;ZC0P>ZtN7` zYDdH3HSU5$O026#*IED*PI}%1?W@B)#@9J(rX0-{a=kl{wR7AHcKC+X{{BayrZ9Gm zfE6oMPi`_XbDwuPeW|MtlnZvz48Ss9?`$R*)qD-g7lZUS-o=G z>X4`>%>CSax38{-X$qB&)uDqax3GDKj2YeOK@X&y@(UBjR;u3QV)f)Mf!0cZ`_$vR ztxUc2MTx&?Jj+>qq06dXXN~!LTvoR3sS3PH;oj9gEZ&6otqv9SCTpxLa+X=04gK}| zy%l{D;@Fo=_$5ce7K_^B#S&wKb?x;puMT5=>Bzn!e%8;Tdj3HPs8^~Axqbl{v0k$i z2E-59TJ_=*iLk~xQ|{K^S}HO1xYK+8E8~`#mA=XUn9%+TW6yXtN1f|BfG616KM2 zN2EV}RQ+Xl;u#4Hc>il7E}H?RT_zax;7eXVmVRZ$Oxc?~@UlzB+^df46%+0DgNeo8 zNSLkPt`3D)?a1$}kkKF9_N=~lb(p-{ZU2*<-XJc=vBA=Ys=$AC$u#6r2@J`Uv)Eue z^M4VLW%jbp1zEse3VpN^IlPGy57miBv_s>1>(w6o5IY_W&A z|2i5LxQ%7*Vx9Z4{{NX^lR9@usQB8%-+Y;vTNsT=!VZ?Wn=MAa_FP-yZ^6W6wWLs1 zn9CX$WR6Y3HpclR&3l?)|5-9q4vN$6*dTiD}1yexOm#* zCzG(9#ix=m%IIkeJiINJt3G2T2F9GNq4I1JhM9lPR%eah|XLS_GJUkS`+50r<{I- zf#<9Vi&%Kan$WAg!CmUL3)Y0fcq_PQO<2hMd)I`mOm18grW~dJrZpjE?t5#(jAQiw zU`^P}=tpb(@~KV2Yr?i;+p_mxpyLeqg^5^sX-(L{#>)mCFVHJ%LOFAf0Icj=6WS(9 z^j~Yj9M;;_hDNr4*RKtA_41q6hA}5deB9bFhxudHhKZ>oWnH~+^4c&>y?BaoCsy11 zqF`;9ePWw03SaAYGBP`NZCGqT$_A5ntquE`pSCtk_=`Z9Ct2BrYeR+k_pbG=7H$6S ze{C2)Nxa!>eR7H;;0!i6S9|f=wP6b@?Q6p*YqzZpGpi?iptd#)GFf4w%!k*8$)~W_ z3Rw8I%rn0y<5MO2lePX_$C*DSarMUbwV{V8w=jBqZ5UyRqfA)(tMQ!6+!Jd<2TQDW zD#QxIY;s#R;K{XN7Yj_YezyHh`wkPc#SRvpS{phUbC`8Dn0s0RSwHt?{T#E;juOIXk-n|wP7cl+{@gvYeVkuGURwBEHMAmwV|D5E@Yj(Y_ZP5b8CH6i+F6Y z$x-HZt_@@Vp`Q_BPGxgv)z&EFo?jd0F=7Wx?96;YVoaI)r~aR<4dYnkBvx2tgR_~k z!rX`inP(5ntY`fkH!9B0JEG?OQ?GLoTby&6_rLsWTVz1v_qO=$-rv0jGM5U> zl%s6@#pOHQxWBCpn=|*hlm+d7w<4DR;S#dJJuLpydw+&H%PftG$LL=YWNW|I?@aH1 z<-amI(?D)xDXb0qSj_c>X=fRDKwntE=4<-G4koYd3*)AE9beZM=42k!7kZg+gek|J zEnZt+C^7f?zOXo}b2|%f=nG@c@&2<|RmhJOz?PKQk#)SOFEm*>q%TZ-hlyEc`Ov!;U-{mWM62paa3QZi?BJpoFrk^PU@@rgd(?iQePO(26DTO(#aA~uW=`%Q%wABi81=G2~X_{J?e$i zY@vFEx$~@?W%cOoj!r#)dS9qzPU#DAHjWANXZMBa?=k-Ds);n@>`KbzTeh=%~D- zFN~^}rwUxOL!8FeI~`G0KUYHk6YyPD#L_fJ$QJ7?zPm5%HZEmTJvq<#ApU#o-1&}* z9qPI2`6g7TU*K$*pY9A9U*wYHOn7l$n8f;wzA%f$_ghKU{sBA2(g#hzGIz7W`Pl@Q zxU8&S>JD5Wk&<>6KCGSP%iOIC+x+i;v#c}=^f4J}Xnw)~R<5ws(+&J|U#PG#*8>OW z=Tufc>oPLBN&<}M^@S;~F)?Sb!8vSRZGkLa<0!K_8{!qO?F;F2?|-A+8D8X!u6K!8 zxWP(Tuh`1hndn9Jj+$R`76NSj6&5XV1cFuNxbQ z1m2+Dr`>anewUfK_2SKt@PLW*m)OCWMeU_Q?|-L;L}57V*l2}W{i{|m)*02^YL>p? zGQQEo-*O3A`Hr1p{(F64U*`9{W&-Aa5@ z^oLnYU(+A@*&NgF(=vEqf7qv9Z|nCtAQCya+8@dajf4ArNQ5nXLx0%CWNd$kJy6Q` z`;Z8Mxl=uNXuprw5cshEP-5-y{?N<9(fvL%!j3Uw%3elq>kp~^78iWbxMTW5jV+G7 z#12&>4=9v4g)R25aBP35Gv;pG?ODfs^*d#Fn}oC{9sOaRx<8EwTN&Nk9~Nql?z2)h7a1>3+-Zwh z>UC$d=T@0mJx%(<#8~_dc6OHeHri1pk636`M{P@g*sUS@UVqr3p8n9CxXYG5DuIs( zwB1&-#7frwv;MG+jbB*N-4b|7LQGz@BG&)WA0~fM`#)W7rlTfg@*n-o9lS0~Ug!?J zab2i(C=}nc&PO2|c*MG}&_s>#>q7n>M(e_!EP>-Z@X_qDtqbkii>Iy&4aTRh3*+u} zbnjjl=4GC@F3dEp$wBqfjCEl@^Rw3ZE_ge8`MR*1ad}p z*9y!sce2L4Y%upRf!f!F@vO6hx$D-2PL?>#nA;d#zb;Ig?K$?de8W0lP9uSeg)o1k zgxI*Tx-N|Ugo$nvh`G zN7&Bj4qML(8*Ffdg*zS9r;W4V5=*f-ti}pE6!Lei3x&^EA*Zv#*-Y5ZCS&IAwsnpy z<_L>lv~${HZqCLpG|`nNyl0(1=aC?b4|tv(OzyQqOu6p??|=P1fep+rS{LSg$$vK4VuJ??f#YIdN<(Xh@PEH9VnLlWe4 zHdmOCwTI1P>-;WQoqL%} z-1ep7a4wTIE-h2;WPPoj%HnWZrycB*NEVOP1salmTf}Ic2XvIUhhP^;|3<|``1_^vtozqwua`tR6W`3hP(Ip;}te=}1Z}k3`bQFfY1#Es*A}oH*#N9II zY}V>l#FRT(`TDxBU4Yypb|4GHe2iwiYGKe5&7F(-V^7IL%p#-kEiX`;tmIyPC*A8j{5=Hu=J%WSgF zUgHW+NJzcJG4mwG-C3NcT)tJ_|J>77rjUQeM2w#m(7-w;tQPR6c8CoQGkQ+Ktg~WV zai_N<3(N^ud;WQE4QuRR!WxS&c;6ZQ%+6e+&WYD#|NpfGUfO+68WX0Vy)$pvi!2=*YXw5v&Cd>Rl{zDED-l( z9lsX1kH7Vx_WT|zRImI_#{G8U_g+U<{$R)0V#?efO|VWs=d%1KaT)#D-4Lh5UFs?K zs7I+ptLvT7U;Kz=!a?T$>WmmO8nD%WbIF+Ovm=cD;SLP)pUyaQ)SbyD;Ft~K{YN~O z_gesq|JBcwQ->_{e|DOc+tsZc&(eaLOJrJTn2HS0r1R)6jKFv8lw>qBu^Vz1ZE zm|IwQ!+O7nkRS`21RT3Qv@`d{^ z5*oigOkm6@Y}$Wc3}nK$%8(Uyu*Mn-M_M7v9D9S6aw2m_tq)UK;7pcTW{vaN;$r3} zSTPGnTXDrWPGF5w*r+PZP)J#3E?V#Ve5{Py7;_iP$4Z1Xw%zDKPGJ5xffya{c{aI= zxrysTn$@}BCW)W0-q-L*jDyUdXs1|hDC||JoFw4q1)5|pCY08;+-lXHYVE%=HG5%U$YZuxI5})Hs^c)n+juZHsCCmjLoxM#yY2Z zP`z;O`cP7@Tw`jl0-Fn3Hx4JWo zZqE>YJDEOd<=Jyj*%9>u zx3SC-*0`4q<`x*waV$Q)K1|Mh#=@!!rRMq&Z8iaCvcWQoyIdy5ocWT8f934dTQ3Wo z^}o74O!}q-b{o(5cgC~H#Vq~ajxqNK@xLWOPGN;J7_&M@AyKHX!G$dBwIbHJo4G&Q za^{&xr1dA4G4sy?{ZbFWpl z|Njc{*nv=Z*@TA-goP{}IuJ&fA2$#tzhXs)4}_S>_<^vKjkgYjiLV-e)IeCk+}j4i z4z@UMxBlY>{L@R%pEwYcpwZif4`m4UV304472v- zfsor{!mkX363Y(`gihv`4}`sJF#4VLzJV~G&2J2Z?JR5^2>Y`*%y0GnR}>~H)Hs!m z?|Xp7A6f}>KejW!m(XJ#RBvu~cIw3^tRQoTiM}uJGgh3{e>xDR|G@;$5BOkn3mdU> z>aAZ5gng|4Z6M6p>(cJGV|%^-aqwW)@S4Fe{f{O%dNA}bI$<#E&73qCihmOD^uf@{ z!dZi1MBpO#vNUBdwEe(J&mIgD*gJA~C=MRP^a~BMTnLieXI~iXn z@HR&_eK7Ph;ohu%(O?+!6Nz&?E1Xz64D%SxkPz#v z=+D1zFbuQBagPf4ex}+#AOY6c%ampPrI~{v&c<;>dyCcRFIMtFTdO1C9QFJqgJCgS zY_e1u41@a1%>PxQEM|UaFl^PH|FCf^G0|SQ%+|BU!r!#dvh~b=WH6-0MI7^(g?wbt z-~Z`IKQw2HjrsH(Y1qN zzIv(MK(?+E=szB~-cCI(5KAoFFc=oH#IpXVB60OPx2xB0w1es?$2_6`CYO(8j@h66 z_g|r?P?|p&re+?!Q*Pz|Jtb)y}bS z+hCZjzrlW1Zns1K_5N2n-17g~5{}s+&>dFB3g&gJj3RRYHx^OV4gB*5bRE=~5}mjqO= zFSfD+4)zJD0d5It>S-?D?+8{hVNGx?z%f2{<5 zWJjt7(SO^K7yBtnp8J|7R=23KcfFh|vzWlnsvgsRW;LL=q}J?d(~8X3$?Y3dB+M`m+*w zo%ZMK6k9v3l=T-})&sTwT!JjUXd$e1lt!%S}oMnQ-Zybes zi#67MD>3cmJ%eEn8yxqX1b=7C^*32mkA81!*KWlH>5GKE1+_4)%jrrp?gh3YB zV4eH3evbQ@J9E55GEdqN+TP&OoxCB;VezaDp{~6eoxLICMocu-giPMKA?#r3Tr2sx zM5b*Bi&H`gyG+Cx9xPq7A@nf5cthBm1)8xT^y-h_w;@DtbVp`x2=iIE#LAgoYD-!F(1wtI zlm5##_+64C`iMA8J|;nyKW@T9B>c$@VUKtf?%!3F;pMjKB^k1Qnm|`L8x|kf5GK7{ zLW@nvLR|uEK4K+jdSJ6U^WU+R0=B+ur_Pe-5A6)&ZMK$;$Bmz2+|v@x z#yw*P)YE4rlsE1<{meaYXSFw8*bu74vpq1f!G};-!HXNhPF7kQLZ|lP%P!@ic7Riv zu*AYE&OWO%Ws_sx?73Gr`057F?RE#wF#%)ktzWwfS^sY~gjw2C))@bGL)Bk8m|%|y z-eKT>T{1Qf81mf>+Fvu|I~z>I+04IoD0DJ6W+?1o%!%*x9Lp>oI24B2QG2Dln);A9Ss7%ekhE8m%yCO%9{mb$~~Ef4~6;JgKrt~ z6%7KjJ@bemU(q1p@k3!hTb%xGaV89fUbZ;G^3g+K+L zZ?{sW1rxJz#!y(4O?;-66a`>A%V$YYdpu<*3}*GSheFDflh3z+bB4ma%y$g=N(Ogk z>QHFAfbSd%GgvL2D?^3cyJX0iZ5NtongL9>kkPxXkfrm6LT^KQBcaelHuv1Lg!ODe0VJmafhr*bP5BB$e3NtS@;YC)++$D~JDaXIpnO-Up zHn}jXm+V+pXKsdoAJ)&5ix^)v6q?L^#NBzH#6Rk++5DIUS)T2P*kUxUD&WU$)%#tJ zPgn_~Pg*JKZ2N%voFN~-Z=y`~+~qEjdY(P%O^&efDRE|scZDs_EL$ndpBC5nI`bct z;Ah+o=C2&`6|V|4g&i!+wRM-+a?WJsvqPbldDT!DW&U#}xK!p>4~3Y;YfQj87n`8T z(X9PiM^jSgB9`0j2vd&#kOZ!C>5Z?kI$J|>y-UQx4MYBYzX#__;KR=H76Tc7VJPfn zi<2%B=yqqxq+`feElBVVM={H|J3Ysgi&%(lxrq{PSFhbAfsbgv+YU1N;!rhgR%m_E z#4Ifw3WblVa{){D2*3vSvv}`NnEEk+IG_3ZhC-bc?q#&d^RrFJb{6jURM<^Ob1U2pwisPu#l2R} zm~}=g1!l6!5gcwDCzi!o?bfrLc)eLz>yom;wogl-&n0BF-fsu8hINjBwe@!3Gcsi) zV0pk+Wpx(Sqd{k`UfdvICY*Am#DQeY2kzOxR$`{fxiq z4t-9%Z%ODaRV!4O;lYIMI?CU6Buu{RJ=R|Qo?!UikfSJ&R){;d560$%O8A37Qq z8$+RAf6VP!{YQQfT_XWDvUvaJF0syiRfWor{l~_D7CTw|iPz)^KI&(`dcuj<8uysD zg7qf^VDzNG?GoVZ%pGn!>reSXbDbl3#t$qup7oq~EpAbdf9hzM?)3gI)=_@m9mpnp zK?mzBUvI*n*$Fnei-i$CpvD`|@iz#-S#18?UC|!>!qKtG9__6c?Sy(|m!ncIzvK>8 zwExn7q_n5M^!_i_kp9Zqzt!bv3Cui4v=?61ext-*ai%Q2>L;N7XtzL2Ig9bHU8b!4 zH~!ne2KTf0TRU;2=QxoSPG!vb;+6m8{ok(O+J?591lZ@jWp30~vivWJWbMJqKJO@A zyD`*Q8?!Mq8MSTnk?O|1exnZ}uyb$N7!pQr+!%Ic?T2g(g_|XM=tiG-Zb9QV`hatZ zyk%pUe2ekb@f$;|kRG`)>|{J)W0?2_TlBV#VF3%rZVWqEJbq)Cus{M6H-;I^owzZ~ zXZa)(vNg%LtbWSIFq+j*73Wr-wlTD`P}t~m26*O1pEYeqrfdw;Zu9<^&e<3`6e?2< zV0`XIf5&5@X)?T>=WPr#kCZ9PY;ZoCT*MZ8nX=B@dp3q`%yWbh_p-p;Q5M2+EOF9N z-v6?~Gz}G&7;`RbT)>2jS!coqH?zs@Y;hM;ru6qUVax;xa6BVUW`RW(Ig2IEn~=T# z3LP3MtTARkYuv(wJ6LCn4en!;ZAVLh6PP>SLKtxli|k;Ty^Oh)33su<{Z)mQ!i2X8 zaDf1fIEO`cu*_b@+{%Qz*x-J)IN=!2U+8&8oWmkJSY|I{Ze_wkq_`$SEvw2Fsko3M-7ckky((k3zy>*4bc#JK5wOwz!`u^CwE+ zeSW|&^;|!bkP9_A&i;RIO;X0e8yu69%yLNds8C z+yEw@(w~jHLO+{jD`DX?E){E6I@?(PTwBc2Rr*=~oPOr7)_<2oudzc+*}+n~Bdsdb zud}tx-{6+tE#ry-Y~E-93!m4|+I;a}3R=`3(Ii)?3!G0W^^g@cT_l{Ge*a5w85WrJf+kpLsMIE5)^uy&jGe}O{b zb^+PsR$E)^up`+P-{F=ol*pYDVr2Yc`af?&gH4WjE_au^lEq=}REcq){?^^zj(a@6 z(2i=aa4PHU&>mOsu|*1ndu4d972Ibc=I{4fGJe2{SpJek?(^Vc?=OpAktmzoo3+;* z(IOKpaTLsTx_nGI`F<`lA#>g0OCZ-{Cs|Dub}1w)44iDs9=0P)dL`z8;wqUxAfeT6 zFDq-@Zbtofh_&@5{*nc3aH%|3VyAk_ZA>=#d9m0+zU6YV_BTIIjH~_K9a-%CZ~Vh$ z__CG!Q)X<9ItteQ?F^aUZ{n|*_Hy+^aqRn&B|vL5aO~*w^t` z$e7{K%lv`EK9a=_9yILF_3TvJurH(0{`z5muIK$NzhT%v1Qz&>!(seGI`YF|E}MrA z`$!f64>JKPhlR|I9}Z2H-fH5dR(j;Hk7BW76NW=SYex@wst`EnD7{r~@2hr&(`=|#g~(vSx~WMwSQ8unQ&CS+4RzG65`+^GH20x|cQ zVP7s|{8htYP(7Vzh3d_#hr@35_<9S=`Z<>g7qHI7Y_OVS4L8`LtbzO4WWLK$a3YI0 z4To*4eBOlJ`fs*Ewz!4KEhfy`Im+A@hJ8tmo#dop&v7oJ1y;^FcV+Fj4OheXO)|f2 zILu;v`*5hS!AO8shqGekj^R+(UcS>&uuvTilfPkg%KgKklMOame87so zVH{_$@FiQFx!5IRi*1{Y|FY*$Vgc%vcP@)dC-p z0Bfvm_5PQ>AwvzhZ#vWO3&3`kzoow1gY3=PpLF?tU`5Y3Ll&QP2{V5xVdH8XRga$Y z7W~ljJKY@?b~$1;IjP}}z2q`7Wzz8e7h8@%L&Cz3tmtJ4u);w`uL!_8C;gvsf3P#G z?REQE{F9acSYm&Z7z=-w7%Ts9S+jOd+9uAZ%gXp)&YrD*o42Zv|Bo~Ni3~Z5rTw-h zt8)jV|Ju4owI8r4%wdZ?S^c$}!U!v4Hihwz*}>Os3bWYAv?DDp%GwXw6y~W%+^*ha z+jfbzZSwhF3b8`W6Zwl>fu_H_5&`n`by>{rPYS^t%c=M(Z?ciHv%#=L_7LM2y zwyBrKZwk4mJb2_L-v{C-*v{fn0x_AeDdeBFvZFWo3>f2%*%WG-$8GW(Qwea&GbTLV zLRp+BQSs{&tDC}B4TTeB%;qFpsv~#uCSSv0VlH6i6c4b;eOdifD|^ntA@koz^Hocw}; z=SfI=?f)sd`v9q`vH{>@Qlg@bg+)p=6(ttdXjG_Z^C}i5*;J^QSW}`=kxfZSMa@)L zXk=4iQjv~EMTKyIW!YU8n1$VCcU@~rGAhzZNl~drBPB(j_jmvL-ShpN=bXEJEIY&O zpX}_Ncf}0lGH0db!d+2k?*HzJy==0iJ$IfIr{lPs#q(XxJp$xxmS;E`W-hqP?-|qg z-$Pg0@m*4+A@^>V>dz)%IrSn(!py9@V*Fp6HH&P#*JVt-Scd-UEZ^srGxz?xVig$ygK z=0h@gzwuYx6?52No%y-W_@~O;o0hNi+C9LJ=%>EG1r-lP4^@`9oMoE_YPsNp6v0 z)^3#{^|ck=|CzU&c!i&AOxV&;{*kj+u5t-$T)`G|`}A8W^~&|z+?ljr{VxADT=`CS zfQ?l$nEH#mVt?vt?ROaWYwc{V(azRd5%2fVPIS1F8+1tR&>^+cPd*E_y1b6eY;g(y z!L4?dy4~GL?Q;hn=1wVRcEBY}-DQ6Bw1(_lxiunVk8spcvswAAGxgAJ`U&+jJNSdU zz~XLa$;^Fj?JAM~$$~8XSt^$tVPv(1iLUvoWd3-9&?O;hO;(` zY>uq;%?Segt%aFyu8ql+c6#P(VzC^Z>_%r<}(Je_M8kHcT6V#yq%>UyUyPOALFA})q``k{4k(7=RaUV4nrY+Dy|n7eXaEN7deY<^^&Umk1!*t%Gl zdX<3K=GgxV@S1hLO~ZoMuZx+=?M3T+bNVs<2aQ13wC)}jDqmk0Q(k7^x7Ni2^-9QF^SAX3x6f?f3F)~O=8^BcFsvGd@b=wDFXU>5>*zL827aIKYK$GyVDLl zz=V?zIdc}6{iZ-zV3}nuWu0|4*~Jz|nf+GclTq~NVU{`mf7)4Oc4-pxSzz^l-v7iy zZ`y&o(+)QZgn4G3u~XL5o!ykg5HsJFp;sQ0$u1Khn;f6^`;Lq#w^&lH-Yj#>epf*1 z%RHo9s3nnml}vMP#Y6FXNvvS@`xZ_cmP_HQd5geU{h<`*+y$0c|B;EA{5bLT+ivqu zl9=`y{kf32m5!1%9!ULZ5)+@5Db9Ya^=?a|#yTsb9x}HlG4^$K!Wk^orG||=6aVPc z51OAjE9EK=v&EwN;;JMTvBhbV%<~K5SY|JCzqDgkIra5ioy1DE*l%3^SBd}sUq$U# zQuqcL__YXGW-awMCSYkz68jBEIO`Ps?s5lMSm%-*miqNl$tw4%FKra~WC3)zGwKUm zq1@(@w7f}Xl(U@`XR9LL=`2qbAv=^C+|Al%3q0r6cO|h{dz<@M?oNC}lOyPHIkgwJ z*tv46H;Gls)vb<(*=fr-ZSS`M<;Fk~%b6ccqRGN88PQ&3n}uN+&KP&Mw}zEm)8#nArTBv# zu*~JGa}ASw1;*TNm+%G3T*&qxW#BYBzTY?&9`yP#^RNxQ*#i3=725}7nDr;zA>*n~ zCy_nUxMy7EBaiX#f1k6E3Lmr;_x#DvS(;-oVy^ndH4u3S2QeJoV2Uua?F z%th;CNI8G?`k44ume)s_hLKEJnkz-Jtp|q`dGm7zt_hKwx3)dEgcL05vg+R;QAQ%HvKsHB0GN32A>UWqN6s% zV&&!u8=}e5OE$z|W?r$u$8#9R#VqHvGxHklY)sPrUK@QwWkbw1QT+`Yd@hHE4^p`> zdqZ@w#L={T$p&A|!b>;!>?RY<*$^{W=Cq3iaK#2+;UsV_OWUuc`tpY@%xq~xjC-Gq zls80)txof^S$TFtWQzhgydmbYb?(OKVC}q(G4}oG8E=f4Y^5S+psZayhFqrH^x#Xof~76waq4Gxocxgnx~JOVqt-S zjWO*KfevkqWz3IkjJ<5!v(Z28GVdQY#uAq9HSeX~|Hkf(G5#_Q_X&iJzX*hxzi*5& zb1b}XW6WXo(T%YtE&qFCWG=Vxa~oqe+s|)|m28C!F*CL!CVxoz*p67t`UxFA(m~)S zb;P7Aj6b;}=CS;`j_A6=`=39pBgW0Oz?(b#n=KRPJ0fB2tsRlMQb1EXVm8}v>xkvd zzoR2|GdHax#(Y@$?2eej>Ny>8P$p{c?1(96Di=Cpjr!tw9dVeAnH{k}ef`3YD1Jow zq7J|R^HBYO0VNAx-Vs&iKWYJ%KGqSd3@EcJ9mr8;uj+`gX9<84S!AA7&R~9?g;?Se zwz;46t2-ilc6wK2f(=%td1!i=#mqGwQDUBpK59a)W`2H0>}B~A9lpy&`BNRSP`?6~ zvdEPzGhuasjOkbYbVt;fxz>2~d5$XQK4Sw{3FI>!{`bF!dRe5*e6}OnIyTryJAAGq zCQP@$b#LP7|%;{`=vEq_= zD1OOVr4?Le;_R2DOgZ6%k85At5i^-^3G-hOAe%hQ@>eZ9pXOV{Qq_^M`89Wf#cw#G zPjHD0nZM4ma-niVNA#yVsJ#7Eb<-Jw_w|YCYH&c~ME4+4W{HP;3)MtNe1D_EHODz1P!(T>w|C=6~DzZOy zo68pF95%U}#oM$q;keIA{q2r|buM6|E|7GAJG?b%J;#5}xI1M|eTkWK-35+kjWe`o ze`Z6U^Zq9u5*6iD2C((>j+lBKf9Yp(8V!EOfnk&efjn)K9s}Ma*xO z+O(Z**1H_VBK^9ZEz4ZRT#w6^Zh$T2q}Ne=QU9&p|M?zT+eFU7c9-W%IyR(;**+;^ zYlojy%OCE?kNMyFx$zbAaBk}FT}lBJ|KR=a zP|?1(BMM(N@IDc1$p6WX(ulcSeSVK0wePebo64C#OQEA{aTfD`kvZ1?+7Ux+>=np6 z_4}I*RqgnG^D7q~kO}2F*QB;8-ggbHmI~(o?zPj<zV2CS0w5=HGrmEis-=^-T-?*Mh9F&hk?hX6b4FA@VH?a?E-9ACeK~Ih`dIS>`-eIZOZcGv;CW zIT=%5N|HIAr3mQAsrrTnIt^gRKdz9~wqpRp-c zGI{H!*u(PMW$^m~J9AUaX8o*9u~)_#Y_l|dQ>T5SfQEGv|nidG2AAD-BG}bu{$9 zo8vGG=WU9`KhST6iS#S+uyUJYFVOGZ7G#Hbn>X7nz^!S(_?x*hA}L zsd<+j7B~5BM;UnkCjV5zfDbrh7CvalY;(dbb~1ZY%w+45O|g{iOJ&Zu%w+;&GRIEU z=dX~#AKFM+M%C9jU%7mpK$!bNWm6pT(EfsjZx!kFB4urn30V5#CSM|B;FmVVLYBWQ zLuq;OCf^yO{FO~Hi-oUl@(W8FFyB5_t9Jfl8~K`mnESd6vd!^7vCcOf8Ecg#n_`WJ z(hUM({hI<=so`4!VQHyAn7>gVKefY~1i~g8tbcn`jJr+$Wt(CSt2b|oRZQ5=2KTVZ z18gyKyTHFIgRE3N%=J)bnF*Jq9cs>=RVJ*lpLOnG!UJqDQ#UckGxI%xvhV|evbsWl z)_&}=-XR0^O}+y{Mt&w!cXY``V@wTVYeq@i^8rkM6~ z3v&+Z_qv44{c%$qWZ_SnqVNkx@@M^7{Hy-IRQ{XHvBXuZv7Zg@W1C}E3+R5An0ZdA zcqn=(u*})4b3U^V*lF7ScROY2Ap`BK^bdDJz@%<#E1+XL z{TmJoy`-|mcQ%ySltEV0Uk zOgObqzh#}VRJqKua`ii%(a+4yHnKxNH&;4izK8sGMa*1H#H@3Tfo)FRY2f!dqp93v zS-JFmJ5a83jdJ@30%vo%!21RC!_F9cmv$~wF5KD~6P0V+t=wK=BLn8G{75Q2xR`}snwU-QXZ}~t{%(PA8CzVK z&im`m7*a0r5F4C2YW#1sk9z-G9+svZ*Vu`MG7m7fwlgN*V*ux|ysk64m`gfirT!%z zOv~%lD_1%5w|2I{rDV3F(_hUS-`VL~Fl2`L-wAZHou_tL?|0t+#6wGm1`o2{;|$k| zaGRYl+1?p@SlZDUlh)bUu+*}4PiOR|<=;8$#HIRur+-{#;y-l80@m-fV+$pJ7Fbh2 z4+@<1M?0g<)(bYrjLPq&cyg8<`!9{GpYI9`o)t=iNy~@?sY>u%T%)^OHm}i5PnL1X_+#D;@0cUNF7ISBB zj@)jZzu6ZKiFAgAS)FNuKgz_#o1@HJ(GE=l zn9MwQtU~|l6^;!Y2UY40Z zDSu9YY+onCEPsA;jOh@-7X-r67b+t0P*pLHbuMCq%h+O_nd=3@9EVuoUY6Kqm18y; z&k1aB3R^5NvuJb7W{&e&;9{049%>${T*W%O*x)EzY%%l2&2f-9j_ou7C$hvmtDM0) z=di&AY_ZDBmo~?8=D3;#_Oep)(DYE{fiy*5-t04~h zT*v~Kvc#3FGGU$lY;X@-JiyFX9gY7G%5mZz?|=4dF4GX}gRt*C&G&9m)d&xZloqxut9lZH_}MkJ!-z-tT*y9TO(0 zzmvk2w`I4>Xnb`V%;h3&CoVGLjkfY-aW{>TP z5*uu=G_EVAWgQ{+ru~lVis}2*A8$jfzqryB2RyX0cA9oP!Ooa}iFzh1{=x?+WL_2jN-vB5>^GnI)_ zp`y&mkH`R5Ye-%xh03{CNjdYcb|kEE%zit~*)j8+!!q|8S9p#3mkQ{$7EoX03bwe9 zh1VJXs0?rdD@_k;45*#b730Ud6qBW1L-kZ=r`%#WEx)NNma{meD>_n7)BiDN$f?Y~ z+1WF5hK1Ae+qaP>8#kkzy#{sv$|rpa`V!z$Q{srr8~m>JPW4fPubx=W$GIOV*A@J9h2|NG@Cz? zp?}H5Y8(2O|NPHykQx;Y&iuCtIy5lL)y%V(1-1oH*yK{ZjGbLkP2JoTL#bUZkc=`nETAW3cEsgoa(7qkVT)z+m4DY2l>=#mhs=`(HoJU55P$Ez zX69bE_dm*9lDb=_SiMiC4$9CTcZZEXJ4+K*|7yYiN1j5 z+uv+@Eys4p%vb4ubhm$e;%*$%9hv{h#IfB`Q(rs2+n;3egzhN5+PD+DV-;(!==S+v z0zIia8q7@Wjzj9Jl~;Dhq-UJrtGZ(eTd(ep{mj3nJ7zuWy?$-C?{d-px^7>=BGr?+ z{fh?uUT?yjKu!^`a+O1A`Lu3-is@|6=#IAfWUBtk$+T{Naw(v*EX?}ZHu#+PKRdnK z=X6OWC%@Lt&sAojU}6@}vor0<`F6(g3<1B+1n=&SMXX)a?Jpmt^5X8uO=8i4tbfpg zY5B75nDBc2F7J-1&)e7)-7#M|e`R-6pZESJAMTDW74=egjD3R$uj-DusaJRVIxast z=S%S^QuV3sSit?xW_y`bv+*5gDWLkz-EmMk zR}<(I{cbVwQRcl>J&Qk**|B~C{@9VSyi$f(yv+tH9-6lsz|tKCuzjbL9WByT-9B_m z>VEDHu=NW^!2D{L(0`+;{>r6gi%Tvw&#&!J0EOR}Sh>7bdm0d%sT;d}HIuiY%UwFn z2DWwk@Bbc(JEWXdmeYov-9C1o{U%V(40Ok8=GmK;2L;L|$G%wxcDW-g4$0JI>W5uU z7Vnn&w^;BV^C;JT>#b03u$8v|wYw5i=V*Aq!W!ya!ldO=r5zvajxl)?JlyTyawtFI z(lGOAcPuro!CqD$vt#wS19q6&cG*ssf&X|5wCA6anai#7KS##o8JT4Da7BtgWZ~zf zh=n71e7=VTj_ipgCMdkH$CpLvcvO#%VzS`TJ+WGQ>%~2>O1XYQkM9N0|HPgs&UJ(n z)U*1^o;bv8uE$3=DZj2K3U3w2DLqkRa%xZXvR0YWeQadzs*E%>xp?RzFj~pzoRD(ur{qHW?soNZGesGJ<()xZcj}5u=+wz zEMjtAPxP}=Ki`CJm$G;D#MqCR@ZCMWfI!C!P0U=;4q3jm$CpzX$YROF*Yv~+tSGmCm+ISXIziT$j8r6)%9%YL;drhLo>mh|`@0rP&d$M*#s>-T@(k}4gl zOM7DcJ9NCUC#EyUwvMfvM1Ga>GMQ0dW0`d>VUu&US8wi#rOf}hCswBIKe2&%0=``! z%H=z3M7jO*o|rbx27YNHS65W57V*_8eysyrYkFe-H3qEfi7w{Xo7jLlSFyIC$JcD> z$HUBT)c@lG@9v2SXR=2C%EfImsoY{yxzw?92`e`>C9NQ~)fp#wu5(J|<&q@h~%w%iMX!G0!H;Y59P+hzV=v&Hqba z%2oEW{;x_;?Df!4u}_EM6Ly+*VD@|+IPFtX{A5ooWR(ev|8W!xEbw2KQ@=8+$}RS? z`jj1}WlsIHoj>jEVT)ZX9C9g{ul&y$UaP~iB4qKf1x;AvA>}rwe#QdN^~5ao4K7yB zJ>L^+m~cPyA&|0pGFxIEn_SM?5nJLgi!ay`(>`lF7qW2VmMELAQu46GLw3xTNHmn$ zRIc-Ya^{6wV)EzsqAgKlnWHQmwI#-0r+(}fpNwM1tfu9ox5Pf<3p~UUd({_@*%ISs zC^N@84_)W|FCHthg$9n>;)B9P$RXyB(}8Wy`Me2_-x5;|EOV)Hll^J^i?>AP3nt8N ziTTW*uq9Tp@e<=%ed(5%XI$=xfXOk1YsC?3vn9cIZ0@gp_>a;vj%2{}&@n5omSIda@Y)(LFAWYQfUSpoh z1u8sDWu0ve)z{gva*Yd^u*wFPv&q$Lv6pQ&nVBR&W_g%7X5VE)oWugBvBX&{vr_U< z^{|jNE@ho7nJ{64{cLg%TRgxvGw-(W>$k*sW;vNTPG_D)7C4VZE@FwxSbqJMO4L16 zRdle%A=bH<3EOON%uE4r0$ZHIHVe$W!BH^F`OI-K^Q^JJRcteNp?;^xI7_Egq{2g0 zMTxb^cFxSHcFG(NFyZnqTlkIc3iDI!bg}-Yd5u_p^Ooph=`Awy6+6w#zVP&?a%UlqtXB4?qnC3fpr;(pe6nECVU_#*Y3&CCVv z0`qLJ$~|nd&GNhSo28!fS>s|hxSW-yht(ch>}8uxX5Q`AGRs5Eaol??#2gEp$|4g1 zH`rovrc39oYO=uGg)+n%>&(8#{H$~4d%gdOhq)$du*@cxu*DT@a}6^W*&(ys%^deL z&%-P+d$EN$i49I;o3ogk<%n74!nB=BFBVDDgFi>|>DOB#&*H^8re)UHW`l+INhxd0 zeNBK|X`*b=EmzLIUw^i_o6Qfnv|o33K4_<`&h{F!e2Mv3y42BEJQOZ-_TR9>IZ~KT z$b+nN();Z2a%ac}m$1bZ%zQ{@m}7%^?q-1pSmM~C0GMOu3K?OYWj0FQ|HB^I9v0mo z;*WZd->>7xyk5+*zycHP#jE^aQm(ViHkYz7PwGEl!K>}~oBCbj2Nzo(mumINd;v1| z2}i{uvmca^Pk8@#>sbAyovLVY2D6_M$hRzTt%;bu&cf=OpZ9}Ex%$N|F>$H(#TH=g zt1_ZJUv($ac{p#j`mf1o>ep@P5`nY8CL6|;mw5kYtH|Hr2M*hucc}=!=?Be?GVv|# zOju)Sskh)J6Eepp_uOIP8|~;$nYzgWY_ZJj4+P9&-RrlCcepFR(f?nXUtr~nX=XAHm|X8zt@SiT`unrOgQY$C>QURIpyMS1;Y04 zTsjv1;1b?tzTMt?*6(w9)mQR=F>yNJZ&IZpxnHW*iu^$XQy+GzSboHg*BSV@l(YG7 zKdRaOkDmj}^?OP^>xTr)(zA{zG4ElSxkZ_i*yIBB$#dSaTfG16=S8BS5K_W~ZDumP zG4_Wh=0p~lXPawSJEAux-)cclXPdKGeS!A0%>B$A*&CS^%ACm3nBJJf>k?{d6-pZe=KlL zVx7|}9ug0;*kFlGE@X>K+2)k>1|HoTE0ya^n6RHs?qQ1u*kEAu>*JS<|F%UETdHFmJhAvU>}xp6Wgpf*>qdAtQyn)t=NQDBt^)EBeL8wAS5 zY@A@6_TozfuH1Y{ZzWc%NM0)9jRv0R%zvtZIkve#ed}ccV&mn#zWvHVuW$rRPLgUC zUrFuR*GO%L@snhbwaFG@af?AfJk4EU=FOGfXnM%LrPp633xN6CO~9GVjT`aPe_zN!e%{5lJ;vC;fn zv~M#HOFPWZ%suAsP5=A<9y|1q`>V5N^$|y~)xiHcD`pQlnmV6x%awC4+8UW{`W?MB zW;1i*)>zH}J`>O08Y|iS(AH?P{jsevV}}W^*%~WY`oz{az|5z%MsBBx7YKxnFA0S8 z8wJAbPXy9$zF!N3`7HurWtoWuNmTOAM?Y(0w#S$Utn>Emm6+q9^@Z)RCiRQk{bo~#uWt9r1p@fm_E^pQ4cp@|vo~#z z;@>SWvfVEdW$eN2ksHzfk?nCvIs4dlzc;kdf$dRNpZsfkG?;B~kL=y%<0O_joz-^5 zgdUnI=Cky~_E^d~SF-iw_BhDwf40ZiQ7Pj@mYHXrGgv*i-7hEw`qXw`P~?c7*8d^> z4w;{&|84iLT?E8s%7tgP#}FG856d;Qp0yCmhoxqp9X+=_=CJy__SD!O``BXP9t&j} zk^4uQ+D6P};RveFyr2;)m75&%uzp82qQK0UMwD5f(1<;$CpBXHBi{eEhb8HRCpUb{ zg@{{+A)6UFm1omip=^C*=osV;s zv#&Kj>)g%U>jdza_rKxcaJs;xhR<-3I!a3mCh`p@7r4ji9`sW+5h^^Bb(PZ_EMr8ge(5a1>{!j0J)x)B+;%$v+u+GD5 zzTHCqvV(VMXL6>AnLE1?6aKB=^hV5P=A8|{Co~WDr50?UZTxwSNCa9q-+1NH3>#qn z0)aolcQ^e0-$Q0*BYIioAr>#RqbE(krOaN`h<+30X9+;L#fkqBzQhETK^9+un@qPT~1~f3oI>jl=-j9TxOil z2b6lYz9C?im#9BN{SA$n$13Y=Ry;I4-~UP}tKZUrnHxo(mO14}12~tZ zo9v94Z(D$Mju~UYWsZ!wn;WqvwbqD(EPclz}Tm%)*Za#OhC6A~se!g0TX)tr3e^xZOrrt;^`q=D9-#nERQdVQH14ImS9a zce!P@&H2ZS^S}Rp;dW|h|I%y6{I8_;SUdf-9WuMdTfyR829DEjtw2~^ClKZn3mzxM z>zyf+4eo>mG8-LWiDfjLu~xbIw#ra{n}Z--}^t)1my>GRMFrNYk#)`^|=TAhsnuO{g9sztnSm! z(m%XT69x9LvrK)&S+cy}C3~d+9(5$f7uZVY=RqbM|9d|N9+L_EN{?5Zk%#u<7SNDC z;AgmUgSl6k=$~FU*13Yse>HqW1OIJ;SDWAoM_^o?E0vp1I#cGJl98O9KJ6`ejidRW zw}^Fi=-*;JEmxiqnTOi5e(=23P7ix+n0?Nf>R9DI7M?eu`h;WuU?(Bfue0+^U(8|V zh`v~p`og{#KS?H7WcEdUu`KndzSzsm*uI$Ydh;C97d2Lj$M!|jLvCE3&+!$=@qIDh z0+|>0#Zu-uF*Fd>VaaEb{zo7tC`m~|f3zxdL=n0v1sb5wnCd|#|q zF1@VJH!k_l|FVa%yG_iAtTE4oGuY%DwqD*B%UPTtU{<-GH6CWd>>vGy6c1S__e$d@ z%fzc}gpJn1|i(ckt%NVPdII_3scWIx`|MO72Op2JBBhs|taz~O^|DnE^#rzdg&o=k6 zHdkg&x4@NsF^{zm+bQ!Okr6gI=?npv+$H8dDr0Q0oz{P>FQ&d#{Z)OHSmdF3mDIB} zuP??-HPJN|PW`xrS(|TR<~|`KZ{sKJkO`MFyFh#Dr!D+;Uh4=_KhqZ-%$21+^|Lbh z4t`E%Qm?B>VfwJp<(tOO+fnKlyiP1#@0K$8qPOErDPG(ci&^`sfY~;Fl1rDZYG;)T znQ$qKUzgFeo-HHxps70U(96v zcDFq3z~#){(dUmxW#Ue$RBr#wu$`J`t2?q zlRkGreRGEi)Aj-7ON}3L=~y0dr!LbzDih5APR3aKz4hj#@Bh6Poa1coGXb-Ik#d&z zO5u5K`QQ9}VD5f9x!gn#ID6%!~NklBB@1E~-DNy*ZF8drQw29;Zn z3uuP=1Ky&Fhn9!wY;(7cnI}y6A+O7mE+gCjv9R{cQzlZ*9kMW+&pPufv_IG9OK8+b zUmRc~vm**~1#r}kSkBxrJ7Tf%dG1#(9=9W=Uupa+c0{G-p?>m?*vIz79WnL8I=psA z)C@?tR5>?kN32pVaWtLilpV3=0x9GuGpFu|iSN>nc@{Z?jW-H_ZLVhaO*{MiDd4>EA5qUT%ct*%uGBLs26||oA@Y)rZ`~0KSYzJ67FR3Rr|yVZ$_?&K+ux@B zqw3$j!zU$Jh^4gs9Xn!0I*uLclW8)gTsTvPJ|@7kcEl3a*hsCMy(12L$em;7I#xO1 zLIciqMyzt)RU&=oj+m=lXPHedN!tsKKzsH7c0}eqHgMjKn8_mNvdoF|%y+&rv+vmv z35&%YzHP_*pS#3_Iu^KuEzZ%H2Ml?(HoW!nA;cjn`cf+Z%O6bP%Il3D$73oKkTo;4Of?I?>C13ZkKui;ud zV)HXQV)Fa#q`V^*vc*-*epc$V=NC%dCzQV+Q!IT+AZ#p_sZUy{vLj}*`ZXJ2?FM&@ z^&7pGpVIF;-U9PA*{pcT-0Ze8&m}r!f4C#|FjsfU78tnBZD+Md3fbJ^Hha9LS9v?F%2ec1ayp{&F6cFx+7JEJ2lzi6i~ znb+YZJ7X^EC-3xcLoD>Voss>V)Sj_3=COJ1&gf$1V)fTq@FVJ3Eboj4%gc7g#D&KH zbZ0DP?l(Jq=evz=-x-rWZ~X6fR-)>mcK^=U&CJs~WAYd5K6&O21D$u+y9SV?L|j?T`(tv|M4ZR`Z~CLo+?xJ4 z$m(7FQTUp1T+Gs13$wVcKMpbB)UVq>(jR43D;^RL<*xo1^9_Npz-n)QEN6CWfAptr z6VMV1b2f|H?SSna7G`;8e@wr@g1_ze=lmA>g9Vwt*Mi^V?tXvHZ{GX*V~E8+S?^ov z`@g5(-{(6ccE~{E&;7A9E${7*7W04W_p4S5+}|H_*?hplsjYrrFrfWG?KcX9b69@J z__WM^Cj0s$bCV_*UsV_2BOX6l!2(^Zx!jOcE%Fdu<^!$IKbSL zfta$wLZ=PH0=C|)orS!1)=$^|BS&+F1(W(xx` z_ovES#mspFJ}KEk%-v=l&SiB5&DZ8i<<_gk3N4-CX! z7AhZfdF~Vm%Pd?XfW;=@WY#&IEhgH_mkz`sW-c3u!p{WC#cZ*QRxV#7 zBg%!34@B{o{FFeL@F0r|%)6SO9`MKP+OKsv+2Z71dH;)_9f+x4ap^dl_0J7No!RR| z{3{D^lueHPwbU;ZdD{MYnfj{!oT0w`1^roAB(-dO(E`7*(=U51SzheUu=y3^))?>T z=dP)kpz5_y(f*o|pYJnX7oH{=kCkrD(YnF@KB8!^{s&yukn#ncO-MD_C3M z^ z@G~juG{LF?e@tp8T$z@CA+>3l6E{ooFTJ*`t(HNSe&y!^^S^fHT>|=z%f=?VSYKnu zY56Xfx?6kV{a@svxItvBcZjS z*nZps+okkh7GSyUOj&B23`c;k?jFN}kn88@Z z@{0z2*@O;b2V>F>0UbRU^Vm2>JM-fPV=oKG4aUTsJbuuZPVmKpu{*d z-1Na1Wt-!F=MJ4S7_(V8*HN&=-7FSlsA>NH8;rSZauv(x4aUBThr;=G_Ind?0ZSLy zIWzAX^kouu^lq8?gCm(a7*)2|U~=JLjJ;R;d!&~6iw2{{%&b9QYA;|;*sc6t~f!l_ee;mkj!{2n$~(^*WR%OR$wN_PcH&TUu+9B!zH%rg{+F*B zin*z;9*UKzxgozr=WDb-#n+n8f~`qIz8Ao}ueTm^oL%uy@GzfECTWK^48>5|fqPlx zVYWE4Efc2<#d2mQo0v6Dc|!kF1!BQA`@jRJQ z-#ULN_9!P82=K7}?;eWD&zOIfohuhUION~|d1zlU6bD$oREOu3xlqUaWka!)HI~)q zFE=rBACf8c1x|e40-VFr6+^L#O}5hVTD*P%KcN`GEkG^K2+5%ZFlh+J1`(Sz`8x<9x`31(j=@r(C;rD7si&G33|! z$N9hEhoZ#Nk8L1zrFD;F<)?P$A%B~R+2SZ`x4WHbhx$;AA7g<#q>NQAVe3wp@R^#6~g{6UH8wsc%wF$90?Uh1@D2R@ysY$r!^#3j^T=3M2*-Nv&y>JFveGZeFqInF;k_BOEfdzbK7^WAGc z;~K0fH+B#Cwf=E_|Nlp4KF-AVNgbPiG9jyf9*Tp^|8*#)AE*5RN5IB|F5&S~`|yzO zdf=mWrd(q?^>LT+#RB}NOtH~+so8wO(Vn3GKl&+GIVM|irXCh*$Q`tE6E>MB7yj#L zluJCI+~nk!sDDbJOju|2X>Z3%)gQ8;{x!}~PM)<9ww}{ZefxQLWxS(!(QwRT=EULX zs(7frVmQW~$kz`0}}E49C8-%stAP{BVqag#|dDjnju? z%*$-#t;3OHb?R_TXXfq0QD*5K!?BEoGlwH#F!ge?Ex zaP*ouf5EV?(bhgwJ=?Pc#(HtsCmdMl1H-7qVkr@^^=2gm98^_$IhGPv2pB;|O ztL^mqVZWXiz*mN2HS6CPj>Bx+I2^^CjD2@FR4H$OtEz5 zaO7X-@>W(2#}W?-8_fP(q^xn;B;{X7A$KR zAwx_!#1{85vuQZmEO6|p0^vkfnP-hNPWApbJj_wi<^twAhkd@kj;t!zIVrDw^RVxJ zwNRG@(*9hgzTQ0?qb&4TP<@eO-l(2qPq*`4mJ4-{uQDbe`?Plg~0Wdr2wLHyy_c)q&Snzi)G4sC{ zI2*gYp3}^GpLr@CvVU>eSij!{tnQPVGe!KkNSXbY_x%hL@c;|Vyww6}S$mV?m9zhL z+0HV)?QSS%o^adKeoqd^Vm7&oxr5fzukl~+|KzhR{FJlPP<`6#r=0trGiAaytIvpZ zx|DM{8_&9=tRA+*bBuppe-^{hnJ3}6sdk(hiK$FDH!UAA5=+uD*RcA65x@U4uyN!_ z%sN+uV@9Hb#TSjl#CJ;VQ6tgRv2e73%EfUb{+OJ{kHiG2EM`Z1?5-m`VI+35@X`@~ zH|%Im9P#P6GB9Bz4zclykr;oz`A;5+dCa_aB)Zb_sg)6bl`5jsN20{snF2^HjQAu| z_3sur>lcZb?e~pD=3N$=Jrc87n`0rCuN;ZPEPiYxh6I|MH{vfJEpYWn)Y$sC0Gauu zzy(_5bk-|r#Y_V}B>)u(XDjCy7|7zacCNn0mU6Q^5|b_zz-LF|;4J0OjrcP<6E7Tz zl`JeWkM<<>V)b9LA!e5d?0quvO&cys{ZB`tu3x3*p`@b0Dhs!bM8eGNBhhBPKH_h_ z)ZaN0liy=OE@X>Knf=*FG_+UQW{Xokp#Q3on9n*_vGj8bf6%ePBe}1iw zvvuSu7S}m5wiBsM7g#UAOSoYqdX-D;P;Ro#!bS^TYQm0@*sDFyHp|RjWL{2Ui&g!K zn?_=Wa+Px~^8VL7^lHd;jl=>C1y)(&^0XsYv(8>N*kp_QnCTWUa~$VL3e2&@sjPA) zYn;o3i`eAyiifs`gxMaqn`JKgkO_P3;4&RKlbLPq0u%PK-LNooJB-u6xy!;=Sa8%4 zG5-f=&h{Q}(_9<)+enmC9~_DP)JI1A{_jcy9lkSd$)eG;A@$=H#dv`3l#*S{gJ66xPli|DLz$XRppSyi1efmC+`Ve^& zT{If|KPz+Z9gQiUGw$NiD6@L$X!NuBq0yLdoj^V^8Vi_wbkr{<1v+mu#xE4W{K{y| z_mIDKGiMh9y*jmFsPjr;a!%w_gF zqmi(5v-(8>{;qnqYU)}1-e?TTROb5vxLiOL4cYuj{?HUWQVEqz1zF{!*v&|i>-YCE|-v3l#u|m#OjBm0t zc6pSIO(yuX3BPM%M%;R-$a$2ln+L;^FBtc|!7#v#tBk8|9t`cz7|(5Na7QX2)<3KN z`_}!e_rLgoBPbhg8T41CGQd_@?+k`96UMg=hN5i0Z7{^2)BZ!LWVB^4ELtmo+Xurs z=06$?L#%Hd3^jqJcQ|uqKe6za%yZ{pnDJ$G_A=Tw7^2I(|Ea>#%RG3Oh?(;UTX&n- zz~rX_V3$4X?4;|mtvBJ%2E$tQf*aJc?StVsJNFKTOndxGcj$7N+cD^GNX^4R_0G=0 zu<$G9-(>?$9UX;r8Y;sUVrN8TS9oC5j`bH@ubz(C3FC1oY{|raXUdF~EA>xkXX^oh zv2s`j%Q|O$RUp4JFFRbt==X#E|Gz?4VZcK19|pr@Iq;7r`kG8|6_Y=?6RiK)nKLV# z`33>}RRHY#O~%;xyVQSO{U2UK){c1%ng7e>W&1ya;gEGI|24lON&Yw33=6I@u(C5G z%pbBdtkDrYY-i|KPq?LQ=V7KZc82OV?1=N&W)E}5te&tlEN9F$OxR+B8`rdP1AB$SJwli#F{pkYurv7JWXXBX`V9Je*=k4@2 zpBCVpZwc^OJHsN@pS{yR>9jGfXUvUEnhM(#+MHzdIXlB~rd;=JspQIQEXb4vH?TT? zXV}C#w=rhM1`n~tV`cmQ?F_T7wa|i{p~jR8+2#^9+byecfDt1mT*{OyuJitP6c*p0;bqR88P}8pUv7bN zAScUuj~y}N!tZE*#ZG@CYNxN<8HU(dWZ~;A{OX-yE@Lia<2CLCJFk~H))sq?^*5UL z`lg8#j+O&BbE65~ELDuz!`f-ijP=u{x@=!2urlCt1f*U~c80oo#M$4q;CU`Hv-91R z8$G{#XPD278_W9p%)^9PQz2D2#OehizR5yd!h{K1T+N&<7TnCr`vt-(53$C|CeL#= z+pM#?VrS@Ojhh9Qe89YA{ewG0b3h?iII5$%a%UJ*&)9Rb1wP^^N7ohRoOC8}4)h`oRM~c_EcYsM#Aya5^lYzC%y>`sFXp2a{;wKwZu4lm=Os;U-Z#Rw+qn4v$hg;d@Amb|? z)sH;)RrCGS2Ksk~KK1Nd?h>1Y!bXMaw>`)j2U!`gBi32@v9seERwd=fwKQR#(Gy9I8e2lJ_GB%ho z=d3#gx={eEb0HHhVT*l?Zg6B}ogL=f!N!e_dYkvZtq^Uq5SOxYlQUooYSh>xPnX|=ci_6H`?S2k)?QE+%q~79CIgUqIxx-QFul~ecV9Mrdg|BN43$SvJ)N8N(ObXSbpWDgL1j@P0xQx+uKWbU|g+SQlk+OcT z0Df+RoWuNH@Bd95kJ9xDe_U5g)OdSeaudF zn1G8Ik2^A^9At-wnDaR6`vvkV0dWBfMvR&hZmB|R(vH~WR#v8*9Sc_OliC9^!RQY% z#pJIRV&k}-|JuTj*cDc@_QYLbh>a)h3iAhzfA+4hhVct_g-O=xyFzUzdyHqZt}u6( zNMErlEMxkXU7@wx18?2s-+*c7F{W=bVdlYJ zF){1s?h0!evofNcbJ*qrw$9t-FQo-^zV=BOx?opW$@T|!g>G42xy!$R5GdEN%Ymjs zrqE%|?JPLP%7>+hRaVALz}Zs*`G{1j=j>DOeAM&oeoS3^e4+jW=H({!g4h(fuCKu$uL?Zm*7*hZ$XJ!Lt7{6F(s3Uvvblec5F^sQ>a^VHF!! zNHN=-dq}+{)vRABaO1liQ?Gu_o%)S=26lyhcE4kXM-+;iclldz5pCHOHn4k_09gFO z<$2JAyIeYUMg+vunWqxrGjVbdR+$;Wqx<7|CucZiQz_@domBjYu@{nmO5e`a^+{i6jwYa-(k zw$4hoyfp;a>&F=pk7+&iV;ii2rJ$$7Eq6^Jiq?7^`*de-jATv)~RUFUrD@3Z~X6D?^>gidSWWu9tvHEZ0-Yo!j*~g3xwwK9F@O+<*H5JnHM5v?1 zp2|snZARvAw+;M27ApS{*atJ;SbUOStC{)6;*V;0=P?kBY$ zS7*%XMOj#Fe1lt7Y>Lu~U1qt9CBe>Tb$j6aw8{J%o&^I7O;m&ci}HBe^aOHEv6i0v|E zOa&T$!2+yZmW44UJW{r=%fjr3o#a=#yGyKo#dzi%V0?v*vCD$l6(XK7<0P*`7UrV_;VXT;S^xSlPx*=;IpQ7E{B z^{=~3We1~&Yv(f7u5x)8a~)H*nQ<#~4zgg*$~Rm_Ryp%T&$Gq`dszLZ*O1LfVS_@O zowDOwQpt$3W_sY;QppbcSPV!hD_47t@ikePdy@9+1X7N>!Gezv80WHklMS$Ovm<7_ z*_~j)6(^nK{lCTQ@<96f{pD`XkeE$#`j9)<2=Y-wti`x z_S&!QzwmM^<&=uH45o5x4CTim!IuS*kywQ0_t#(1&6d({w;;9@pw6ov!CS1xPZxj{8_>3 zaes)Fb#~d}5OW@3-2AVUKiPv^&ienPjw!b?W5&3$$8RhU2rExff7l-1U?7l(?+KgO z;34L$JyrjSdwg+$fM@RU$p{NSa*tn3AdpAx33HyNoom?a&NAUMOmNbk5V2O>6H+FR z*%SH=s6K8_$k?8}C(Nvw_!Q%qaw(H1>XY__ zfv0=_+X`I^7Toeo6V9~&8&9>9c@~^!;Xm01$Bb?51!p|VxCItqR^Jo0mGzg{ z*s}%p(mlS|zy^9e&-|5p!d6yZwI^(NPSXSmL(kE%Xipf_QM}qt)sxrk@lgp2zjjYp z%@$|Q=i)tK-TztO?R&x`J6xtcI#p_)XJ_x&6E>>1xl+9o%ZPgXPJyepPTLa>v%OSc z%>^QP_nt8Cxl+Z1@fjjxZJErl;1PD;V*v}c&XiInX9@86`q?s1wa>z=b1P#GGI_7S zjmx->$=No{$~k*NbL9&?nCuA)Utl6`VCP(sYVWM@VBOAE?FmP)H`eUgbuT- z1Ylg{8;;;bp63!~{Q_d;n~v}$7UX92>bLfUSueH$_Gxc_dynt`(vW>ygjC zcciXtXYWD}Zgg3g-moX+?A~Z6`qNEz!p?VP=B37S0SiW~-n=KweVI&dma(#(4fV7m zK=pQ~X<>!VttMvewmo6H0i7S2@Z~1_iA&VuZfx_Qdh4z|VZM6uQyEb2-Xmk`=`Xx~ zY~SlOeT6&oOLvAXu4jjBc6YcltpCdVuaw!Q!UBcbeNxF5S1|dt*N+WuF5B5IM5= zYk?`5V*M|6RF3<*oiP2k1+^z9?hOmdagW*?;>f~W&SchJ-wCh%(R+O-yd9skHxz80 zyf-X+o%cU_>|WpLZowz*4YOYF!DsCal{a|sIVNE1xqHJPYcJm$dfq6YSL_XK=C3hP z>1+3f)|-rf-QEzf)4Mn1Y@E6`%z3kb-?2CJvK{XY{j9xnZ|Jbg9dB+*p~9qw;$3^g z{3RA#x;Lz5bo$<~jR`ZRJj6DSvCCO+5ddqfynC-Nm9_wvFk&AIwpl%6Z`i^*cQEE; zQ=y?yu*Df~wFAy!#sw@GFdkCwqM(vgbL* z>bZ{g9RlN47R=aQzBkN{&3D1xrVpQ3;DaV+yiz9EUMofK^uXnI@-7Qrxz~qDxIth{ zu5zZQS>S35vep(5lk44)rH%w_ty z?kxSy5h>Kr8rvJTYe)~e^<|x_S-amQVa$RlD}7SO8SioVIEMunu=;?2nQ{#?ZeZ<@ z471DXna2IrWoI*b&_W6YH?s35XT|8xd&67-wYZS=Ldw}@T>!1W$pE8&I)bv!E$ng! zb562)OyEp7^Sv_6x$JV`d%gdSe+xiE#~GiP*MY8i9Z*>=VnJ6y=he+9-m zmow&Srd-cx#=g*Ihm)+FurC~Am9x(A{?`<0=a_&C8F2|?_ObEsePLr+pSjO>Md*LT zz7QpL^yGb^#f*bYpR&)VT8w+@zOa-nu3*lztUqmE7+{wj7Tn%csMSQqm`7Q8`o7RO z&xFs|7q+p*jE!gR3p36)0q3&dLRRJpm^JpX&ITi{Wz2pi+{_lYv-+%kp*eTC2Ndc| zxR_n0%(;P$XYcc?RE&GhzA(gyhuMAZzOeoS0(hYeu==`vVfOn3{ssZD#Xh#Vnw2;1 z3p*IU*|-a=_vU@gFkhjeVG;AUh`6l3U5Z$Fr_8XuRBGSv3^|v{>2}V>yZ42d)ib1; zU8ane*)a6w;SbK|WnR9@ROJziV!G7jn*cU3Et6U}% ztaAaIiNa!q4*SXh>-L3Jj9E0K^vec*O#784Wc+oRVB>m6av{I#xza5Hvrx)ItljPi zwYPYL1($r(#(rcx6R!HG_rLOEDb>)p!wxN2Fk$&;888>d`M`QoVMsfYf6iV}rA_XB=GBl;U4|@DnLRP|BpZ~5ipM!-(}^KCjRffFo!MHS*r|%ZESFe1&=U( z$WWLe@XAAn!d%uKHst$164TqGxo@Q<*`G}uvQ^?oQca0Ze?xuP{`QeVYYdk zowD8d;_*Xa9;>I=Now4aheGA^>Q5Cov)WKtroHlX3$o6B#?Le#tIrVmO zjput{tp{Hy6FLeGsMlWX0j4h*3LDFI=Bz9n3P%}p*5^#b8e3e*oV~2PbSNaOaTVL# zR`zqKY;V3?$`tDCxzqy8zht6Undr*~E*c6;wO3v}>~N4db5>&+W5k*3Jjc1~y#J}fQVX=+ITY$T+FZ;Imoa^p30OT%KwmTg z7qP{q%(;@)r9)vYvomdom9vIIhjs2K>wWHq%+|S_30Hr~C91tw9jZlS83;rTMsk zjZZl`MytL50}9zCLt(NUu*Q2^c6{2|eAPhqu=5!yW5(4?yfu?$KMSUu@ipT(mpSV! zxR|w6pk+U|mHo_E|E%}_utNM<@9zcytdmM+jLP~Khr*n1s9$aZ^~zU7&ZOlB5F6aa zoX1$d(oVl_JXbOOssLI2n!9q9K)8b44c-tY3hv zvB8CGaS1zIRrdG0Lrez*!sKdqq^z^&n-=0KCfB%>%s5%LHx)L0%f#1-R6~n1)H^)R z_<9*&i#=sKds%Qfqm4sh4HLH5X3w`}>IMrk=cclLqfD`}$?G>DBj0s2Y_=6rg`EA2 zZfdYE8AH$uHNywGGdD{H?qO4OqpHd{ckHA zDhK?^g4fy!d)Z*Zl&e_3&n;)fEsVK?2`AZL!IU%F0^=M;zqV7xT*ibe*NSk&RLsehBdYh$`IrG1(4M&+i;0(WO;2{gK{s*^Jd&EJ;%$ab9{ucXg_WTid=ZBvElN77xf0j{J3mN^M zfd1wv_17xHVYYh0Xp0RsPZ$op8lr~}hmqr(3hb`*a%Z5Y2%FBoSCKD5%IUHte zRzGVv%whHH;jokuS1>zgIBaA$84g2C&Ncq~o-4gwhE@)T#p>~ghkXRo`(J!?I1DHx zjp49^1uH+WvkQkq4?FBFT{RrmF=wBN;;(p4J!OZLD~7`%Hm)4@dx9*)h3sq?4og`3 zy5|_N!OB%OdW-kJ_6-wgXfR{^&EasA$+w0>wWI#+;ZSFry=)BFY1w}Da9GQfZRXs@ z-QQ3aeaF}_U z2{sLf`K*1{j@Z6=IILv#dv?N@o0)Nt$>!m3r1Tcgmv^Hx92T&9>u`wKxy|!Uh4_b3 zTe@X9^p~mqk%d|O*n>Z^v#l-*Yj=vA$uiq>zw}!8+p=5SizhFWqq#s+2vtYo?=7y>gQ568&8!Ah1%2XoYmTh zPePiQhuPxHUyAtYBVis}&m0L6EAvJ|!h~tr&Q0ua8#88Q|FcHIj2!}e_J~hL+R*%w zu$T!ezbgO#{|iULva+E*5;l|rUSxq^iJS?Og?7NoO9jM;bMMp7nDrhzW#<+8*?!$f z==n9@G!oV_S|Si8Z}r@uac^@6*f>?dgH0W=2Q{?bX@@&?oF>(5ona@eo#`lc8P_)w zma~2KNZ85_2iZMG%6ALo+>vlhy?&m6)Z3iP4(p}o8_#07_RP2o96?hZl9z4|7La;_v(&4faipxV zHe%k?{H%P|{LDGT_UA^LVcw|Je%=CXU+Pw~a@j~Y!h#FN^ncM=vC(e_rQaF}i^c`c z)r`OGIkpBy!tDJ5yV{Ykb&bnue3$*|^=mE64yzM3+HOjXLi;+YX61S*V~0iQMwikA z8G9z}>;^ky#&%i1aU^VEbd!arxM?J;V)5OPFz0}AH#=jdKd=F|Zy5IWn0~Lws?fu9ez--V06#|caHeYNBWtwbC(p~FC%vwr`~3)UjM07m)_%b zX0+Y72h7KnjP5m_&Dst-P{{9d`+vhhx19BzcE~OdGu`Fqz#$8A&Tj>}+s@eGTON;w4&-6RJkEqwfiyVpK@MAhUA7sI z7|+hAx96~V#@zvCtZJ|97l3+$L##|_|DE?gp7aCZcOslJ5eptF>$#NuUjP02OCK;n z=^+!a@*8LV2Mcl;yIgog`-5IDX1|kJ)(R=t-{7&b{&$)Bqv!r1Gff?Z!T_Ux`hmmj zn1v0@nHX67Pe0S(=L6%1jE4DtGU3BU!zyMcjD{|wnWLflXYHKFHhWol~ITfRS*2dL|nu&p6@a5-vq*5c6&yfVU>>7D@Ma4<5!M`%{m(FGJVx( zIL?ASM~z!F8rHGH0oGqD0A{bZBMT-=MnnCd#`TVdHO$^Q8gdrz9t{hQdG1W}vfVct zj{Muk&uNi;JArCJQ^DRGQmei!w|b4wG$6^8lz!pIl;$9L%Xaq zH9q487F_i|8@h1R7aZ9Tw=reL77wxAR5+&4;jI5!fHh`Z$ec@9e0(&lWwOc{nz-{x zM-tR8wj=Eg4l(6nws@RfZZ)p5#@+B-#>GrNJsRdbHb7E7+4Ia?Y;83{`HyhZv(d|`laZlbBNi9yK}PfW8VLz z3axRM?$H+7@4aT7D_O9=Y@cwejq5ODds0fPCgc*PQ{EnS4!9d-eOd-R*Wxktf(svG z-h-oIHKY5z4QxN){h#$%8TgIJ8MB|!gD%bEczD!rLNWonChYv)gX;00-R9XY(O*V= zm68De>j;_i7~B7IRAq*O%st+YA2JsDn9djr8%s|Z3-inV6PjaTkwT&2P&x3#v9RzI zxAhTYVKocxU}M%;s6Rpdq_MD;^~a2bBWyfw%x^NX@N5$^d%{@gd9wC7o@c=>J5L-7 z$Ju_;SXew)W}ZA2Rx)oYtXJqfWh~5iik&=l%=hwmko~MYZ7ggq+u3FN=>mDW1)ez; z61L`z`52u{JlpfnF#fq?Va`)!=y?KQ>-l40jI|eyg?UdC;KH%6)VNxYfZ1%nYAhU6 zXuVqG&lJdO$HE#Gud^WI#U`F-VJ>9!#<9>aQCg~=zR3b?ym>6Nw09Xji%Z7BCKhjz zStf5C3$SX(+4 zCXG+HS-s1{W&7z;uD#89&*i&igxxd7!jhUyEpsPoO*>cEq#@@Z<1@#?b^~kgmCFAU z*g4LM#d$JPdcjzj{X9EaVFETjAeHQV(4AnqQU(^7?-OHT1FIMLs=4Ru4~~qLhmD6V ztUr7_%xJ#AfSKcADQk}$_whRcJYhWSc%cX8jE6aO6FzM`tYr4Q@z7=b;_)!cnb#MN zhuJT(0WN0srQ=~MJ1-j#t66{fc$oQO{cNk(dd9;N^_YESJDWRRBBED_WTBm~mpL2d zfLD$Cc%6m0L3_MtJZxvd%1hN>JsuXZ!_`b*BLGIP9S?`g=XgZD`Z@u=Oh9iK59?T6 zY=dks9&h?ZKn7}<`Er50MTF{g_Az0D?Na^qw~dFv(q0+p@f=(FD{mLLdi~UKpChzD zERa`to^9>P8RNcLsXTjuX^-AxJ?8Iej)(Y_COXptZ1q`akq*vyRe1+YP}Vu~)yAEz zpT#+jg56|1%zurYpF1Ar8DBY1KNGgJ7w3CkJzhQ@GUhy{y>h{Lh+Zq;<_D!#q01eN zJ~SSVGvizf*H(^)dZeGLSo??!X^+{*lv}k&7s|-%O!#qkiODLNDE-8EI9j^ebFViq z*Rpcac<5&{QrKEHTE=Mi%qMb5(?J^m9n*g}I9KTNcV()*faI9?j;&@nZK=n)GA!q%|QuIa(aY3(z)?1LB z%g234%>q~0@!Qq=1;omL=Z&vkJs!qbyT*cVGS9VMH~o3rk)A4m?~aFMZ2fRNY(BLq zh1;B&fsMPJDUsam-yS{g3y5?r8=FJ6UQ$)|qk% zTb2DjMrTJ4*&pI}3-A&9!zT5dN7Xxz+#j~7XUtge5G%9xhuY~D=8`i!_vrnhPd(=< z#wYC$$JnXv_vgQfvd8TAu{wb~c7NE&#%vQT^WZ7k-y@JG>gV zHnyH2V&?Pqhpoo9pSwRS?lZxH{h`Im^Y{DIn|97T$MY{zXZPj%!}{0adtx6T>X zDP86{)|&6xALb->#^r3Cxj%H+IBS3CmIM0shvUpjwb$RfKUB{ZDCe0i@88BgG#r}|}CtT0y zgHowI`jESDft{{&7v3+hRTg4&vGx@vzGQ#c!06KgF|NgKIbNn08dv?S0GP1yA@6_t zbI$GqCgLJ?KJU`8wN_wd`=uWIpa(D0{~;5tmpVpYb=g?ym%)`XaJ7YvE4Z1R?>GWB zt~ZYLjRG_-;R?36W~KMPtFS>sbc0L5m<3bL_^^pMmpSXK-019?vQySK35a!8K4PBD z&X{pWhS<7we^}74@NE_>{h@$ZyIsBcQ4jveKo%Tg`ePFrkg?}u9@y$FV8I=1+~KG$ zwD3>%hhC{(T&O+%ncKh0eA{J!jeGa|{O>13vctj}B5qJ` za5gh;Vfrh#`jawnpA<6wwF%hZ8n)PCha1@)+#hn*cgozS%)@1DWj4z8K1W%$4}1TQ zDdfZZ!>rW?jJVaTjk*JjIl#*J{&1KnmtN#9?6)AJ39ltHF1*;dsr?};`#GTA<{(?s z`Y&Pb60>&D(XNrvgKlL_A-&(NWb%LkY;g;_+`)pAtQ~SUm~zIaE%+N5Vf(PRr1W<( zz>M3<{@=?i(?2^3HvS@$pE1v0Wsue8i4(pa%YY|OgsRI}JbNN6XY0iip{6~1$wcU3 zW#L4KS?AXB(sFJpLob~ODRUlT<7E?J$!Cp!`9#>v7OS5V80WFW9(LKwX0DJZRC^|T zLP<)wjtvg5;Ni0ViixoB^Xg35c;!SGWcsR!uwbo)7EOfp?6A#@TNuB3B2+F_XD{Q| zOoYW>GXAv!{F3)Siza-6NyLjM!Vy;AJmL2N31rDcSi#0yWQdj1>}0+EvnE3H1)1Pd zMtu{Z#SRCV^AOwTTKF>0oo_tTR@xDhk4%K)j2n(hKs%@Wj4vyXQlYy}BnDK!Xu&H?z?E!$$x$%*vV~b+Kj9Y=nfUUFFstP`&S$|ztbN7v ztX$#fnDa2>E1mh3=KHElGy9tPzs9R3LbI!oe^bggh_o%`tlu;dju}|rBz0dE0GF}$ zeRqV7A54S}ySF&9vj0{)H&5k<6FzQZBe#3*D)Zen5jL>;3xP1YS7yxL;vu$oO!)Ud z9w>H9gf&d=bB63N`G$plZ9ztZE*0DCvcA)8?iT@Sq73)0AgvZ%p^;;g`JVtvbLW2osT;sWY6Jf1-o&BXlj*7Km zNAzv;GiGN*CXFvfjZ?2S$Gip#_3?=?#%RBz7%-4A3$9=`;q_u=aw2SGjay5n?3C#N z8!>U5yY*L__@KMPjK{S%e(yQ;Hn*{L#QfKK|KmTpy$Tr@Unh`1NwIq8&r+$L6yAom z_PF@r>4!O{*Gjn#CJZCb@+NjPt8_$~zE7|5+CJXf6V7}*1 zhWU&cv3%~(%sIsBhRJZ45s$OM>i0d!Tmbd2OMO|tYBHqE*w5BCCc_pc{l=B; z-;x>QD_48|7V}=?%voa(|=)wcDa^0 z`l--*q!$w9oHz&g}1LK>e&cOQjCVeH{E64Tsu<^F*@i-?)Lr{3iZ21cE7V^`oLt!*eU&~l>gRQs<$3Ak$U&AjIsEg zTi#Xwy+GOeg8*1?kns@<+#|(*@*1-7XBpDo=9aSkFWd;inpQt@*g|MMEL`|znS zXS<0`oC?PbjAl;xb}JJ;aw@d6*B&($a<)157j`~tD)h2;l78b_Cr^bf>aD7A>N)4$ z>&PBA6$V($o(i>J3gGcmVPR9DrO?mnDN|u9BM!35c{@z}jH$4i=`%fepYijj!glrK z|E9vKvi>~JF?qiJUmN$rsj!~a7f*#rW-poYScFOuvcd6_@-O-JE?u;p)oDkTVGRbDDFgantvpk?7<#x6>R{GwluwcKPpJOLX zxN=g!$yAu{xyrdyVKM7W*k!-|_IUzPkIr`_>gjSDE&CZyneT$BaA?Z=UwgkZ(op9H zwpUDr`T;v&FY6z$Fe@MOdX??W*jXu4>~iL`)PC4oz?2#59}!q?98>1(XXT?d$~t%C z-v30Q(9qzFgE|@lV9dqLxT0+TxCPkaAttNs@!qg88)>vo!S%EP5oSiV^v9f=yTg*B$Mm)rro!`jJmn`&K z&t2ijSZ%reY;jV5o6Vves4zoE#@+`FxY9zUU$p?!uLmY%j=|` zb6Yv?+kOs|<9L`cE5;?9&6M-mW$O>t9gy-&p?0-}S!c|GYgoO;8M4d8N1Wxg&X7^t z0!(a zH%J{D+^jvlNuAYAc2vj&SFqqlR&EwJ8|?XucCKRMdya~=&HCAFDJ=M_0bIf877H-r zVb*Vzk-w?4pRL;j%*qeliKBMPKGwHLwT&cPuU@;|I97io^<_JI%1p5Kch7BgDgW;M zuik0L8tQl15oM zn3QuF8@v5{VLfx?Y;)GXy#L)jBKwzA@3mm*J`1oh`eb{fe`^PAN6yftaFg{ zF@ZDU?Ei3FCKz-1ae@EFPe%2G>)7G|JKWkdApNbB{MW?nWAva@v(1iyIfvBK!!FtX zr1baR26q2o0@jcCNyrxK!T3K3l#M@oo>?Iim8##QEaj~KRmRz7^N>RFcNus{wNm?s ziCO)p6k0g@w;c(v^M#j5&pnFGEBt6Ir8a}?SRqt@dqxC=A__CcV)l+U_&O?l! zb08%86Ru*5>)3883@CKiVVB#ParQ}7f3aYPj9zdcjA>7Jq#Vx~GcCY5ti14m52FaA zeju!1%8jKjI^eS;7G%y2kFv`x=51D9V#gcRrOwH z%lw@O!d6z6dhQWCT|nxMK1cN!&z~)$Y@91#cFsHCBOab#DFbYO!osY4>Offdh^qhp zuMnFk;|jJ{n}E?p2SUb#huGn9RxXwqXIkZ^$2r4G4upbTN4a>mh0+6IGYcMO$G~uy&apFkNS7PcV)%EmZyD0be?09Jez4(t%K! zqyNk9ivEK2a@=|WvBqVrb0s6DOt_(`&`>z^Bokb2Arlo`%F0({gjLRdvdnNPlPd(E zJ!Ok+uG3y^xjRgGl-(;2__izkUzdTo0v>Qjo~X`<9X6LLWD2WTa04q>OD(J1#u_u$ zxyD4*Yow3`50&Gt^*)#VoMj^sYmB+DtY0Uy>~PX^`F9S4B~MY`==~qik#DpR3udg| zaKNWuJjl&#aXWKPvS7i+jR!){Q|*Yo>@s2fCP&DG9k#fg9geZfBg}7VI=iP?aFa8t zX<(PpcU?BN+4FQ0-Yi3GvBPMy0NCMzXQ+SQQL+64M`gYaGxh2%Qm-Cy)-x^4C9K_g zAS}{eZz{y)04`_D)l9ga4Yrwb3tQa5HYb^}VEr~f2LzmO0XtmGF4tKw`;qsbIpcZO z`?2}itZsE#6smW)T+cFqn^?Ki*)rKCwa+#IkCqc~rt!&L?t=FGZaZb`9&gceY~W`y z!8X^i!;Q?jWxo2)y(Q1J-gX&(uJ=Frg|pUByVp-DrkweI2K>?v*x2C?FymGeRet5Y zRZltZc_zNkbJ`2$rGqY?g^FD=s=vtG3H8bz0jSr81YXvMWo|*!#0txvFNGs+KfBDB zj+$tJop8nr>~PF$!+6{T%(<1(gmEtv@Bx3yG0km=@gbLt_1}1|ZeFHr|JEI1`k;WD z3WdVl7a90F5i|L{l(F>(N5JgQ7I?7*j#_}}-v!FzA9l{`Oop~;u z4lz5;FHVPb3fY$hVqoX;=`g0=<)YU+lCPM61#>p8kjgg*sO1QZtFfXz;&SZ;H!``> zcy>8=v2h!weQZaa?Xv#$=`hJ=dX<#CQA)mHhs?Nxt$sUtlLAZ?}@Vo2ElUJ>gn5*k6w4X13U6n?vmKFzcIK!m^!1=1FcB(A$jvvAe*|Ph94= zdH<_-N~MPGHn+Uj4)1o0OS>KrY06%v$;v3p|Fi@X6*0~Gah5*pb1Yi0c(tzo^Jg8 z0#NUAt9s)BKR?vd-&lZ+2VFw8c$96ng7{s zW%n;KRC?5d7Rvwb^)WvBr}643*QnQz`8lEmJP%!Vnvc#ywNIgH0#+Vt0=9UV)!BKdz1NN&pNC#nPcZ?DIeC~V z@X8bO&?(zF`)rxv8b(jbeNajNlk>1$e~n{IIO81kxp`R3W=kPeD7cOB)ACSB1jI$G zK0OZ`neiBtXXIi2xpw+Y3$ewmOy}ic)_KN1OQ39V9iwOG;fRGB++Nn7BY^V-Fh38` z`Q`uqS6HJVdai{<+~8LA?EhqDxg9*ugsd*e!#u|9VTjE`5z1GUFI?9%1#h=3A-G2BXM$7OXTsEY+_QFcDRhuJ50!oo0!A`WWi%h-)V;*v(tCwVF@dz<)Ky9mztMd&biP!r%O3o z@0LL(XXO6-f7!6i!XLNrdrTy<4wtcYrn|w$Spw2u^vRHV{$8nOdbR+{ah&x*&v5~} zjF@p%Iqx|ZR*$%XF*jzt)t zS?LEy=||jwPYHnY8FNwTM+MF{2bnRapYfq_u>iQ4)sML|mw5j>3P;Ov>q18gNw}23Y@wGczFOn0kk+)w^8JjBV!J!h$6Zak zS+K?#pEe)oFyaEnjF@m~Q=y@-f+^Rq#o3>=@V5*o9guSEm8mBaGS0HkY%*+UM=C;Om(KP`(_n3h3&rMLa|I!Xw zXZ{>1*Sdzz00Vc|Izd6l|T8jW1arLI!fk$_5N>DC{8#S zmK#t#@nBfPh%Gi){i4X(%V_4ou#UAy91I)v$K1-4liCZ;`jUmJ2SdW>F$aApO<>H+ z`FNBq&JEjRjOqc~vIT+@B*#u8G7#hsDPJ8|w3$wf6 zpx+6}7uW#n3vIx-_@xKK7S?+X`c5bdMhAVpm-SwE(ARo-{~K>S7*;7{OAdzZ%-?Fj zJIe!Bpfo@yto#|Ojl(s$|qik)#8yPS6=mkN-L^A3j9+S^>ujN7%h&$sYb zjaz;&toW+;zw*9=pWQnP1mG;5qf;>Vv*>%KIN*b1?MjNUuE@=4>z#2g-Wegjach5nI>E1Uui6 zN>(@8iSZF(9khd180_Wx0K+~GsyT4=F%#hcX90A^IiLSZfG^nt zFz{~@g0BBCkl0XrfB-N}ILw*~zok8Nf6tmj*AHCSNFW4FjZ8=p7usMU^aVI5;~)q< zFbr#91U5iElSPG~3${c5_)eA1OcN72RXKDXf*<-Pb*g%E2n!#ElRH&2b~FVY zJCNF`;!sQLRL;M1{s+=K`Swc!9?_|`{hbchPSpopM|G-#odnM4Q~{_jq#caHw1)_= zs8eM@2P}YYnBI(?-KkvIE?5pd(2pL0Z7^Z);V@|y?%Jy6T*RCUm^ypzv{!ak-`x&J}`{7&Uyh9TI19ft8o@SjK}up=<* zQ6_S7r!xD*QAnl;LD&dAzv@&eA!c$44e`666I);1sWw9oY=sdx1f8dLsnoz_Eo* z1hwlZF%CCOe~KBxQf%Ax%p7`P5xS!m8zx{YblpH;82%HLXeHqrJJlW-uIp6xr|Ew) zODp~1Hf+}|ohkyuw~&$c3>num6BF#6X{KCp<2H7|VqxKj&bUe;dJrn$xc-Z6Ky06wdd&f0u_J-vR%pc@v#2=qhGi!2ok!gkT&ei((N44i-+FXDftlgIARp&#n6 zQhFGKwwH+0&K`P+^WX6r86kw=FpRw3sq*%a$QztyFxbJ&pzTd&Kmh++tSxlDLn)#5 zKG%bn;RjR_`afbRp=UppdW9wUtdmbVVj^8EEr|tS3G{Sxw!Gq_LoXTAz}e3Q0f%#d zO$A*r{wj%lNyl~qCAbj5(1b3&vXKD~=~8=OXmS_N^I;#_rShQ*roYZaU@3GS)}!D_em&+ zcG#Mu%csomagfUla72z{#@O!TnaMvHsDMg9r;{1M@TxAA_W=X0CIQ+-in@62kAYwx z)K8_f_&sn0I|%i?OyJj)9)@8BOu#y5TjT3eK@J>ix>O5v!FK3|`(Xs8lUM@UpE?5CQa5D_R01UxK7>4a66oLCCu`{UfKH`@!0T}k3-Nkcy9GpwW&{f7}`Iu5& zNd-Qnqo+$%Lt7PzLYKEob%U;sN% z!{&oN&(&S3UOK|GPnhX741}$1?o#`Nf9z5w0@g(a)4oV!Q z15Ae=XosOYDKQM+#X!(uFc5UYO8RLHBnX3WMErL%Q*eUyK0J`{~$AhCw<)2P}n7SP9+G4?{56PrDuLZqZ>o^uYbl4-+r|O?@N=(_skO zVHi4L1eU<)4$l7y4iX6a3GDeR9R^6?0Zu3M0IbALzy@r0Bby033Oiu%Z=AO15x7_4 zz&@xyL`9$t>cn-!EEs}L7=|TKYhu?{a^PsdB+zeg2nP`IZKg2-^2jMnK zj3WY@r6CMM?O93-gU?Zk0|X2+W9We)XnO%a{XH-NT`#hi{>98*qO#BfYlW|qi0~b* z{V?(&d+lq^|HNlx_BETQi}FNVqDpv8=8h_2dyv!9WV?Fp|hK_ z2fAS`48R8Q!)EB}XU`4!$SBTQ{hNkg(E<8l5JnRW3?l~^5IVl@Qrds$IK;~*3_}le z{F{ov$bVQ0vA^ME8hT&?y1ymSZ)gu4&^*rC&g3(Iu4B~ z=P(VY$5bPX9uZSfsLdw8w+sN=pxYW##owVH8RL6InK^8O3224xxiO`GPu!zosuYIi z#Z(Zw7Q~b-XGY!g3>zz7_I3D`(GhdrkDz$mmT zCbon`q1zEt=|8dr&wq~v@CQOMAwdssbOjF;~*iz@iD%! z)S`t?i1Cf3I0|BF8;nA;iG)rhK^QoRgwP{!NZPHSLg)#&7iue6!ig5m1D#MinTm>C zNM&H?SHwGniJcNt1< z>Lbu)9MB*NgV4F264M|Iv!-HKk|1`8Wu2Pyi#)1rxBE4jP-Y35NV^Hgww-W{$1j#C2jC?QZ6D zI-JDo@k7sTOhn?q7UV~=m(v*a~h@*=g%<}$M3v@^WTXO;-DP*w~-Mg^V}Iz zB`^#tpmrBC$FCV|I_PO&&xjuuO{d@8F+N_4i9inw!&;bt4N$))#v_*u48za`_rmZ! zod4k&Byb<4k%sqEnwiW9j$k{2R0KP+gT!d3|CLHX2MnTX4^Rp5!&31#GQ)KAzflov z8}vi%A#8N_P7;8&=9toE!GBQVjM*GK!i=H+Q7VBW2)APgL(CLA0Xwi=yBJvf&}>DA zd$664v8k}buo^}lCo$-3A)z_+dxGl$48eW0*Po)2(Bo^3sX83m)0}=V0246r3|Fcn z$aptv4E=3fAC832vYUm^kqFeo*!aUQP(f_xOH^tu@%FHEFbwzL559sQhTw>_hdLAT zML1}tq3tzFZ=>|E_9z0s&djlGun{`}M_}*`PA~KbbRA8?9r&?>uvK)}fF632nL_tl zR1Q4^)8~=++w_Bp2<_%^{)gV-bU_Hb%lQl=dpVslDA_)CDINW=9b5m1N@Oy#kC_>? zeM-e(;Bzj)^JyPrO-V2e(_s|aC2{D4S~p7!ZLku$VAFig{|E=|1kigJ5IUi@fPtY6 zhG5o0{JrcA7=}*t1Z>3)^^rJq_H)HtggwaKf&MRu2VGw=Fzww5Dhs2q4Mq;o&&PrG zH3MYP@IS02^nAm$A4Z1R?b+~qN)Bz~yVVE`Ozc(;JGQx7`JqSeR(plhyVV~0IcIe9 zg`*4zD;&h1*{vF&p5CpZFa)!5naHee<;z-3gCn}tW&{r`z>dIHZ1-#eV0++Z7>3)$ z4~Ovkt=%ebDFe>w=Ic7C2n^xZj_g*=*si%Ggzbj=pa;fb2x?1cKeyYb(l}sIR2I}> z0klCEbii`xgf-9w>!BOQW#FT_m30~V(cP*=bl46(a6fd+W1t)og;p4Xc`yQt>1WII zae&~Q->vGP8*YdG1!N4P&_v0cS>0+I9RdqUP)fO|TlGl*7|mk>i@R0Pa{9ws=vqR8 zFbJ*3FjH6xgE>?N1|0Na4ZdB4U8^h350pw%9c;S<=v_b24Owaj_Fo9 z1KVH*Ou%yJKCW8@VHmbR=kZj8_JI?+`NT8&pV+OO(7A#ML!a#oO2t8>q?<1yWo8$% zsi5PsZWVzE*mM$lC6zdV0iYFzU>?*ir-IN0%V7{kX`g`B6|}no9r``pssp+<(9cOf zFMH|)&VQ#IAS7T&92>h;fItb@4E0UjDlCEFeyCm5%{QEqAWSJhhgndo>E;_xnK^Vr z+tpMOI$%BYz!>qJo2d}C`w!hJe z%m6o&D2(31%<#K!C7`swjWvbN+c`a{K=jX?70`AE3DaKR#@-MemaHbBJDI4Dg9ry5 z(0Labt)f)WTtowd89}{)5~F*dAL@5Q@!!MlJ{8_eqA&r&_-)&nF?I+x6r#gc82$_6 zNV_1L6Wg|f^FQy`RN${v00yDK_$hF~q!J6ICvha*sXlO;Y2 zKdgsA-&4!G z^$Go8^iw9XmN-!ofwoQ(fzcRe3;p$OPIu^p@wJ@)t{yI}2tn8`j$Td|=z^uCY${lC zE;ECb*jgX$u_G`BJ^h>w=mBV7NB;qAs133wU>FWVN1O{!8SS74+P)x8Dd)d~gC+tv zVH`Nv z+YdLp@&AYRJ`S{R*i1BVz!B^q+$;fxxrW0Cv|mW+zbEhov>zc5biq6rfJHD2%b@=U zDgYC(5k`MxX`oB%QTfCVL6?j>zDM~gIIwZxVSw<29u$3?cfvi2MzJkC<_Ne_ZJhw+# zFU7X?DCZ^Eumn4NRF7(do})?pGWx+1{I+>MN`atd5D5CA2S*TgU){ztDhT(%0IWyX^LkVSCYJZ8jLTVqeBwc;@Aw|o!a<;* zM~%SfNtEac0yyai!!S-DZ6)on{m>*cg;r=gxknA5dtkg z!ggs_*rSG_PyY>T=V1+9J!(7D&!iy^2MjMFQ9X=-5D_&<#T+%%lpQO=Y0} zw>_%BOS@8*2!_w0g4M)b$ApCE5f|NdK1=51{CCR%4)+Djd?N$9dsMUV!XA~ji2$$! z27gDXVF-pqhY^^7G3dC6%3Q_FVFnDrLKuY=&|lu8{4fBw!60n9%E!U)34joS!!U6% zC9I+2B|WMXY8C7WXoGdo34_oN!!QA(;=h!@SFP48tZE zfo)K`fr>#lEZRc5I?n$F4nj9mQa^!UAGUrAn-OZa((pP0Z)Ik}+nE^*{+ZM0divdo zABGK<1}0!Lv^B7#wImMrU_FH4%K1Me9Uowm(82u>n-6+mJq*Ag z48j%|f$dOhVju!J9_H-0k#;-j|0ncj27nG&37ybcN54m@5Vj}8M4|05mK=umbN&x= z5ZT|OQV8Vulo>%MEQ4<7fgV^3L$DD>;U1`c#!R3MHZV{CX4O;LC<9@;;U4IL`=B4j zr5)66Vq!iH(l`jgEEt9bFaljL3d>;v)U<^F$&ff3wrKeYXa%x`62sNIG>Oy<~OSPJ!T zSz8z!;WYzBUmGVZL1~`> z^uuNtgkczkQK(26hOxVY_R4mGy6I&KuZ- z&|TN7%;*v5cu?;DZ(_}G_~CvSgbAqMOvi^95IUd>7D5j!g#lOzL(mT+a2rg(CaB*+ z0?+{?&;?`A1BYP%rZo9za4P|uNC4JC{&zJMhdR_ACNRu{30MU6+bKQtz((kYtiI zLl{1^PgTIsVSQ>lj2z#`2MJ=I(5E8UHfNtI#*RYM=TxAuPvt}Hls;91?t&HA!BgoE z9cv)E2e!ckjEP;`r_BF=r}g<%z8w69j>6OXcw~}5XZG=Blni)wpBjeY-}dn&B>uG| zLf}AYpVB%>?3_O3fRS_iR4IPjx<2K`c9!+201U%QbnQG6kaidJDL=OR!akmeB;JL- zJ|2lAv)>W$Q5s&BfXb^&a1lxu_)dC&fKEC~m0XFq1Yd15xwog^l zE&#W~C=9~{+zYkM1f*RQ_F;$q(5LFKLw_V5)S0Nhi?}cY2DUIR^f|9%U=E_N8S2*) z5JupL*tI0^7=do+;~7v&`X^>cK!07I@?g7e>ElDDu175(u(6_WNX zR6=YRg^nla-@-sJ20c%*q)!kJ+WV<+8+!!m&k?8J$3d6?2!7ZHBX2O{0WyrRc69W- zLus)S?@}qKcTrMdPaofeN=16p-`qf_On8rZ(6VUn;oZhdBVR%Nrs)o*){k;G81qZVTEIguLZO0LS4cI|zKabav z@tl6XK$HQX3kIME24O9X!bWI2vY*Fp85r(^*TXn*95(tr%_cpnU-_XE?uGuN`uYBE z4uS}_XW-Ff`X!Z^*RP7O6R-@1GWt~=bY%9c&G`LU{VIeV7GgUVQ8}pps$ZplMIxv4 ztNqd+rtD_m)yy2-bt-Y7Ud(vtwqjqu%HzO^;1c1qe$_?;kE>rLp#MxtE&h^zm62fP zXZNd87+T8!=uw#7X3>_EvbN|KokM>ZJ(vE{eqFyR$3LTtaSkx>`6PhtgxjIV$3cjL zAlw7Pa374qICNjY0M8N#+M(_y0ceAj&;k800-Iq1hN1hyeielQI0VDc{2YE*Mk2P0 zs5G`uFYo7h9y0ko2|(Aylpco%mcan@z!0p35!e6|uvvHs1H#~?3?zPNeV+E0^(!Zg zKsQW4Kh)M!QRsq02RQ$u9E8MC+0W;Fk{L`uC$#+wUf!?tFdd)+x?v&oz*6Xkl~B8a zC8T{2Zo`hiCeg2CNni*jU>KTSAR(Ckf{&7V$c&DDXvg8-Kw#*oVut7rFQpVeO!=Aw zs;LlkZloeG2tzO-HvQb2*c;f6s~BJi*7U0q7=(3DyPEd23&R#4g8v$JuMBuC9bRN+ zun#=}?bw0MBn16`ptS!+hxOR*KQd!%olV?|?SLK70~1j9)BYs}hJ`Q$OQB~AiNFB# z)e^vY9lKE)!VVaPLr}Y(O|yp%Fb@V`5e&gH7_4RQK*tS~m^e|m2ix^05`cjli6aR^ z>&wKe>sML-p&cxRuA4aj9XNtFAwb8?%nbTr3k<+^7=|$zg~KobQ(mFnEo?IAuIGv- zHmrmCtt144Fabl*^eS;+Jp;RM!w)@MDOEZS|5i#3L$D7=Fu?i#4H@6gg#+CMtDy(h z!7vQL1l%M1Gl@a{4kkiBeH#h369?L$?M^BOBLi(mql zLG4~nKd8f6XoC$f3irU^c4i3Of1$*$YW6{k!WTn(D4Wr`IZ?!%J~b!Au@*AV+=%le=7q)?Rf@*p_ds5dOFxc(D@!q zNBh7h{b~d{dO3Z+BhCS?h%op)6ZwwwKQVDY4bvfU$bd@efRhH44eBWad_OOl!VWsv zrVOYyYzK@$KOBN#nD!?A83U>iI$=2s!+IEn%}|?39H_%6bikoEIsaYh1Iqdq9bgfR zK<#@5SU8~apnLIvs(_B%0Y0~n0LuqdnY7Di0B9>9F&JGjpyI++#Cw~#MFXlB28v0T ze$kQvo~|Ro^9EEtjKWGE2mbR1R1hZMUg*AHKy9XD2sT1K5J+`MKv?}Q0WKQgu{_#e zj33*vftf&C)qu))k9gHo07mNuQ~)|}BLV2xHo(K}#5ZUUBhY7lp9T$N3Sfn4g)JD}1(V1j)EJ{6Jy`&kp{j1%}rX7I%T4+s+AOJ)os3D%Ylfdkku0=K~gY=O3a zF*ETGF*6v2Y5SP*zu80d_k71vV!OX*DPaI^hLP`mtSJY!kpUHk4!9ROVITCvEQS69 zCI65mfL0iQ1uy~2pzTLy2p!NxdtD8vT5Lb`W4pCMK2;Zv8&pFu0MkAqG2i$>Rm?#E zx`h)5RUHgY8sxJZ31A*nF&KfmHcj(P9#pOPqc8^bLkE@iG3^f3_?HDEQ6{E>aY#kU<7*LFbu=A zPZ(hOpeiI$$BaScfv%Z@DhMO9(D6HFlK{4V?w~6Dg!A8)!HjWe3kH>W91c4(lt7L_ z)h8WJ9^|W(nb9f|#2+|ykS`>i#z!+V01U!*7>0e&v1X7Dslf-0JlLmd<)h>^Y6$U{s#8J&tVz~Y`=&B>HmH?1HrYwXKCOW7gKWlXTnl= z8?1)+LCri(yZ+Kap8w%s9|y(opO?`9j$6-6;RA3xJh_sYz$alJ3|zsCCsUCtNfe$3 zU9eyi{oqyCvPa+qAC(pRhCyXNbedNBClZ0D+(NgYkuxVQV zEd+)$ZW~mU@Nw7x&)&*u1fL5Gsu7rW`=H85nWnAT#*)E;J6U5mco%yDE^Qc82^hMY zc2lNl%kE`U!x?`e9$eT&hV2{_G!3f#&U_ErgAoRdCSO@pP%RXikTc&AG@27(Bp(quE55|}=9N$d^p$qmw zpQC?JWldvEVKEFrH;lk)n1FRqA7C#)2Mj^yAOpf6G#$?A2Fs_@KTfH!BXAqG=Swa? z*iqO5Jzr6AX?I{yMGv3G|Nr+dPNy^k7=vLr45KiGhOVz!Yv>;uRQXW;Aq`2A(J#ZL0CdXCAEOb}|6R^U^fp%D2)j8VJ&o} z#g(s-gD?kspksPm#b6MctW;tK8ACrTgb7#<-7^UQBd`%V)9DXGFa~Y2=syP=Wg5$IY*2OEL%;;I<>mopHI z!tGEymYG5)jENtbkD?OL4)y%FazPLDL;r~^4UDdct2lI@%u*gr{8hw^FMGtCFQ_z0c!(;upVk|HY2n_^Lz%lh)pE?J$nF#E@ATtFO91( z3|_|O6J9~$3uxzM$)MwEHXRIKLn2~tCN7NrA^MqIToCNmg^S_cCzA%VA9Tj+pJ=!7Mrzt33!ga2ek(DMNUK|hR% z4u?hmn1plKTl-lO=z--h1Z#X8L^!C22^fU>Cu|yMgY7T~`(Ox;i2W&>)Iq<`2na(_ zHYarU##M(f!NAZDQ*xOQEP(E>sR#_iIv5(_{BM>99E73vOF06L(1m>G)= zE1>6F5{7~A*iD5|0>2@xKVQ6Lw&8jx*JKIPr4iq?;!6h44KJBtsMoV+rSzenE1@1BRN|w|*~W@D zvgb@O{i9L^q&R4|!VI}gs~(GKR~eu})L^LmN-`L7mdTM`pA ztrqzLkxxhtHOIcdaK1@Ro6w&Y{V>sY9c7XL3eUYz3zVpJx*@p9Nf|#GJdb7PBkthjRTC(s^b*YlO?fCQQ#@=>QTD{T_HB0M(PulNoLV^=M+ zazz-R27Q|}|3LIJHrum}fatB988c+y-J;JqHFu4XNVb2mQmvKtTSb58H1?uA0j+4$_cof?^H159Blo^a~-Kh&AZtdQyM?0R8w_)hsj(w1ai}j zFW%2K8?U{~=@DjV`(YHMw^ChfSl-V(+z9Q;Y${Eljr3QlW%%WX{+cO;|6wm)sj`yF zsFsda^6KU4@SkaRG&dRxmi%$@Ung2Tyg?bE$1)3wYq9!X*uXFFqdyY80WI&f4eFFJ zEgd$aMfO*zA<>HE`Y}G1YJN$R4BGLvd{U*1{jX=*QlzRwD5amF1Ru|IBo)ULzW;hm z$@5iWMX`P*(JoHa*K#eAk!#V@qg862==>zJLCgCetr^YrKUx^A@@JZ4wpZePUZu{F zU?->QD^t@~r-mmQgRf^=Qj(XxREp6}qFiRv%{HvIKCJMc7ZqA7u_FCdYQA*lr-*-k zwE96>Bw8{HCwE|JUsdthS34fhJknVAL}q4wI%~fN?NsTKywHwcC0AORN*=zVMAc8r zk%3l(R)}W!S1zy`k(cM2CVP;!|Eo&v91W|U$UM#*L5rgq&L=Z%X1*On%lJ1|^qEYj zVLK(uWG-ZYx>T<+T4-Rc#EN1ql`Qyi^UsgAc{VK)PiB@)=KuTG(&u^Asm6gPGv^!E zK9#xLTEs4BJjSaW(uE(%uS|Bv@$~Y%GT-K?#Tq`*s}_ixAA)ENXt9l6m6=rd%naC! z=BlBWwKdajj$+l{h2?6^v^q?@oHpF&<$FIye(J+FIz@v7O3rvKBc zZX2!d2~THcnupO!(2T&utTe;5ZobK!&Y9FGlKZV+y75CS zbCTJE*ZMhaS=T~y8X3ie5ZrCI5dt<$-+z_J=E zpUIqK{C#)k@wuDP{QX{)E9K!wN)kY8Mw^pVM)yV|nmO)O#iP67t5dUb@9Jg*GxrNa z=%cq3C0IpY989PhtMqHJ_HyoQ!>Sv?N=ULTSWRLbtewfB&Ez_UlsxUmQb|KI|J(c1 z`7T>03oQf9@V_xX%LqT4X_{PyJV#nltnEKyxt`0kT21V)eC1U~{;YjES|OT|*qfP_A}4u1O0_7Fe`Y$T6rSG-h8vf6*kQeUqw{vHf+{eF&?Q5W~|6UtUz&Ao~;kdw5VDwl-8V| zmvAkVipq_r72WW>m|5g=VRc~rJil_ZcC>?QC8O7%?M36}DfuH>J(}}Z|IJ9WAX+h6 za#U<5|60&0&eRrv@t@L_rQlx+zKY^%b-MUYPqq2Rf_9*XPp?)vqVpq*&_K{)?k{FCfNAw7 z++Vz4&P_AsoWJDov^@NK@jLcaszHuTIiGOL@-&x`viGvnEGdLb|FBZMvIN&8>1w%m z$#mn~3zjUgxFx+wm#gO(%e3}We4ihk$8F1d**SVEzL8@tS0`~ZZQA|WRKxu(ckid~ z&7Na1&t=o)U#_+;!{z&I^loQ{aZ88YVl?i}w&`vfWK>?RI=R;~bw$T+tbROgX{s@d z-_n9V?7dvgrWU66`0~5aoKAW_dx^ztW7V&{T-|mIzURf4yp_81{p=iz8{g2b%hmS3 z;9JF)+a-NZahtW)Y>8%3*VR`j|64fk=X>QwJ6`^2_A*NWdnJGRmFne3@V(9VhmCf8 z?bGZ#CR>J=Qru^*R0BJ3-phA-jdr}DFMF9@!W5(HJZc4-(!{Hp;V4*egwb!$)n~6v z4YC>~RJ?&k`_K2NE!^>%?%<_wG(cuQDJSry{obRduEh7M_;!4iGu^nRpQ#qIbdd)= zYM6a!S~FfB>v!w%_Nhj+pE_-)LCv5?Rq<+SdeuaO9X~FfXH&sPmV)Jk81X0{uhOOma2mPG9Mg^8ylhW3_6}r^ zSSqP=d&&m&(0MetL>m0})^%K*jnF}Z^vgD=o4M^XeKuJ)!s`~!Fphtn0OfI#v>i(o zHf>PXaIG=r97=$dFWILX&)t}lYP8Zoucm>&c7xKm*EKzVsBT2k7i1VIU*KxTW#76% zea^2srkumZVxM$68^w*^VrBE^zki83LH6|thY|bsFR~9m!--siyhdcY$r)dmYP+5S zB!B010!QyJ_yPThMqs2RV;f4caS3!0iH)BRGWO9OxR2EL#}0!-CMf2;WMOBTEx zS3zc#`X|#ieK3u_$y%TNRd&u9w&U3-doLOLC1vLSGbbnh>i-|VjXAmT@5P@i)#>z4 zmMXUvIe{#fWz(u(hTY8mZN%>^t5Rv)BAHG|cKd3{^rx02vdrQyFeU26aOtr~xzu}VE8YjMIX{4eAzn`JzFOU|@e zK{Uc^t+Yvb_Y(D^OmMEW`TPLC2fFW>Z?X*IYx`RjA8CSbLbCsJjw6j*zUCrUcoMfA zJFC7trKic>hpS}&B|B)(HCo#WH*Ns4Uewtw&;&R%7EC10db)L9BlayBu zWzV&YAXgwKf8&2czL!Yf zK-N6NYUP6C%vr?s1bf{Yo)K{Kcuq{x!{Q^^{&V(M1JA8+?hs2eomStZ6)`W zPmZOUGnQ($#f7{FIT>l@Sfu1{@g}_LKrdwT#z`M?%JXB{JTCIe8<;=_cMWc2m$be^WO>8P;zl-w*=NZl zMSkZ4T5m_rN6wZ?tQOhwo#c*ef1ygv75Q|LFSIXNG2KpQJFgPMxOPjR1>)NAUG`kP z47u(_ehZc!lQ>76Ph=ip41AY;l4TDr|4UV)?@qlvogTb9wZL$HpUq1NzyCMlbIYlF z|8#xy%{k-y?9+5VuG)?&b(};ra3v$Aj%1&t_u(pglM~*IYu&+KzLD(Z78f^1vG>QO zzgq_5eZg!?J#yezGZXA!320uah75Gk!gkT7j{*t-%0MDN$yY2pJkl(BX38hoyz*es?=Y^)ipY; z*~SAuW-qi<;A-ZLg5=V@^iz_J$YJF5Qt<~w-f_Y69%XHH<4cn|TL=U23wQZYklG-9J1Q>tD4~e|xO#33^^kZ{oSt9uM;=5IRmx#~u+LEztnsNsHeyCCb@tu|I$2;Vf0_0ZY zpvY@P-gOA0)F4}btWsBqJX_=)7uxMQstc82*qs(>>|30zCy>jLmB=4k#;W~?NyI5U zlNSwDr7o1Y?UWun{z7iun=-BvL-!lBv|s5>&mwm=Z;>A z)6XKaao*8{PmpdamoAx|ye<~us>k&~GHG#rp0{M?EVi~L1J>X!81GeECGu=>e_(@GRa-TR#m@D##jPahxE4$gO9^{OPUiGZVPw8V> zKmVY8xxNqAW?Zkyur?F0Emm$|_Tjr%qTMLI z+f(e>dMR?j6t9{s@pWSMS;4`Ip)e`XyPN5rHcbVZj zk#$X9$9*2Y0`Yw&zFjBg9GfN~%W*}gdzJhV(DcTXv9-PQHv81OEJSU^y?usPaZ0g} z(sQweLJlE^kw1|ui;rH(73tiPJI%QNqs&8e?xNhYyy|LkKP0_YUd3g)8ac@O%E=Sr zQIV772_d&2CyTi?ncWoog1fSoOq4i9R`#QeewBDGoJNJRxM8kDzDDG=BJcP!7sqns z5OVT%`q-rW95+ot?7hfbBQ?`Zk&|0wKXM=P29du>K|bSfW|n?FFNbry>JF*L$0=ho zdk~kU5?9TUys0a*dP#bGez<*=C5&8R^Q!66<57`!EMIc0#e4yQjv5>G7LosuMvy{e zC-UVo?0S)p+L$+MCU+VL)j0h)KNROWah~|soMSC*$mvIqm0^|0$ubNh7a%9+J5S^t zGT%Hm#YcWbf=m$kg=4scN2c?N=fSrZUvfKtBfoGaw{tVHnYZ|pb^bu)qh?TxK4d%c zTN3Fhexpvl6Xcm;&#*WyWX*7`mPy|)Jsy-EmB_;xV;8Zl^hjQMRqC?k`d(bF%rV!h zgD&5DiTseu66>dE+D z<-LI9)oew&eU3hit1QQ>c2C50qhv0x-gn)(aH_E_-R`t_C_rPLcl3@cnZ8^fEX~Nn z$mflx+m*>W%wmP*Z`-D0z3N*@#49oG6Wdb;xD>E#-O{pLY$Y z&z2>29W{iSd>NlA>V^AqjxZMW=cO1I%(h!BDO}6)Pa3=0CF{3kHqnZZn~^V)L3T@7 zFZ6SvNX%w`1n})$;Z?0N(!Ju_F+Ojm;rC~y7||;oW=jVRnw(zsjdZ?V8mzS1kJZyy zBlpSP(LWboBujDbf^;KjwVN%4xWc&P{Y=w}E&ap4FSSzS$p;z@ug6~bH$L;j6lpPiH7f+?1>ipWsFbDMrqm0AEk^PbM4u#3goil(Z98sb|do!)%D|lmwZp!O4B<0 zl?VL~{nF3vvetxuGyX$OguTOj@HDZ>X@aZ3lz3J7 zSlVnwk?WAlkRKBHd&x2R`|2L#2=a>}zb*2vx$^ht~5$#qEJE4j?8vZOG#i0|_ScB`>v0Us9YsNzL){a6;)ijNYE ztwANeR(zv(Tx0!m^k(FyO0T+4(m3mou?x$Jt=UtJUuW5uSkk=Q3|%pn=4$CiK^7aN zIm56$%QHolG^pD!c4I>T^2xHVwd_UqZ1j%4OSMMihPSF+?C1q*cY)>!^oA_ct;)}(;dkNu6V}@pVfEpE-4x5Vj>M8yOFuZa=8+jn~7P*WqI}^3|D*JM12zp z;7^7;O#J^1*@!QJ?|}4uUjBx#WnxaY9z`DV^Rgvn-Dw)T!hE&Uo@>|+Uu3crUByl0 zbz`%=R=QbCOLO!(9PN zUCXT#a!f|f7Wur)T;2tp!)wT!lkJoALKYqHlv zoT|>HcGDSAd@+0{OAc4!OTJ81|MW7Y{eeyLz?gsCFa7!SvEeWO+t}~ct0i{wwPNQ| z`*ghwU+Y6&rKFN4kW#Xe{Y&jD^gXy-k5Dq1pK&nTvzFNx>gj)Ee?2<(d&PR`B~^KJ z8T-qRt2Q)t$2nI9<0KfJNNyXxCVa=qMAW#kiL6gfq!4XC{)$~*#j6g#XyG@`$g>}t zo8jYRM^1Ko{+Hckeuel$_;nNAb|$+W&UyE4o_(6`$5;CVlMvqr<9Ho@kq13emUDl( z7nlEOuX--pS-CeD|aQ9t*sZC-VZ6yY0*y=yu5tpVif=f-|{ zdr#ykmGY}Das%=JS(zRedF3%|3G)`N>d$-C%Oc+^@==%P@e2#G9v-`YyHVuPzik|2 zpOd={U*sjP;^l>#Uwp|muS%B6h1P=Ky~nF=mE@02j&$}C{{D3=+su3&XUD6&G|M(y zeQ;v;AIoh?DXx*%c&uU^t_yG_|6Kf)xSDVkzrl8vUTbmjSD*~Tna|DS2rl!RJjs-T zYn2R^{NwZ=bNLI?Hfi9xo*l>oINwRwucg5Td9d!2eETxJ8D9g>-Z&+0@4>il+`lB< z&@W#+S+C`Wq=(<}WFpA|Cu4uPesQYd2`;fF-#jXzk*(jW{8EjNCH@)yoY~V$Fl%vn za3z0rd{tb@KTf3{Z(ow9XoVH-;O>~F*>Qu_}%yqrYt970Idw| zR_Swcs`1d{oNFJynmOIvfhUBAzlSd5qgbBzQR~3^*rujtbA)ee^*~=pJGgXJ#&uP zd<&I-pJsWlXJ(o6v9=9hmA{@@YHJYR)f?5(gwqOB9p~}rM;3=6^o|=hCZDy;Fz?6G z>Ncvo-e$74H!@9Dt)A_Ka)|WfhaIY=p%tMS!B-b-HrySVri|@Kek6JQ;Hi_~xC!IN z$zvzdycJ*dO}}XFq^iwG|5x)ee8HQ?nkS$2jG^okMSn9h&uP1jjZpvp_DyG~0(|m zMvzwi-z{?9^)KdAi_$7eaOeCI!+C&b4r55^k0R-jOlz+Bb}ns?Z~W;gPMt7Tv_Q*7 zHCN*DyNJI4xrDa4m>p zwb?iE(Bt3&dx{Nz`WIDRa3Z zRHAwEC0^P5^f~od&Vo%pJ%=gf4WgBy{rsWMI9d?xXAgCzaPJvC3F)T?6Ro94c`N=K zEl#tqaMA*Yxe=>$HCFPm%mh}!ud$L(I_h^a(_#sj$Sky$VQHsr`f1Ne?jAHN zS~7QQK-&Li(@#%iN{dFcqSI-Se3EhxR>eArFV9uRuo}eD-_NWxm)^z8?Nqool~e)9P@gjR|+`aq%MZr-oF8jA-C9Y$bHp2=K^8Y$0+ew=CYg{AA0 z|E-!-Z!cO6+G?5H*dvId$I(Oohi>`{XYv1`ThVP#ZBnZw4$n;eaqOwXJoHj@%6qoB zl65XZEEyG(nhaQm=K7xiqF1BWp>tO9DLbPt=<@zyJ-XhyNj(&~VZpeHZTGR^cW+YM zkMjZ0&SW#`-HfiaZAv~*qK)_cr0^9@8h6j4lBw`qM~A=!hkx+Ahc3a;%Z4riOD`v zQesk4vWXinBMgXX<*rm%uSYS`MKAX@Eq-Y%y6Z~OPQ-6yW9S|F6!YS$Me)%MW24E9c1-n%q5K#f!x@M@iu%f2GzT3j_g`53mV zEdKaa*a*K)SVMe1MLGWX#1QSa=UhWI8MXYJFEDGnKA$Z#8|%Uy+Ul>v#*A~rQf|z@ z#0WW_0+zwkQuFnNhF$s5ueku5VV*_#`oA@MPJ}~?8#Q^DRvR8}i4Lmf{+*WJYji84 zj1!gsi{NkhCGjr-mIj-xt$aN^T&s7vg0!}E5f-iXB!g-hYVhKG#)vP&ORPaJlCfS_ zC9cw5SH$0FfnHZFt{&6nQM0VL?Tp{)#N>LGVX>`n;(*nVREWIC_Fi9-%TjprlKkE| zp|DC=6U@rr@)K4E3%WC3AEb!E8eti*5f`ymSmmnx-rKK)?SieY2VNYZrH1Yc8+}pW zAlN?G#fdm!>Baec@yz&1gb6SY>@t&u@PB_2slI!ep32{r`;P{gTY8utukHV6KOb%J z)y@HS7oIX2@7FIIf~Q4zGM)!9nT@iqM+^Ssetnk(?SN?ZX|Cz^7H}DliT@`-_FNnU zGwJC(V@d`qI(P<@aFbgl&gr}ga)aZ)W1-y-JX)}_oc&;$Ytk?md2B*YJa@nT6%Aqp zv&TCp#QMA>2ES%80tja8O!5}PCz+t3_;F$SUq^jf&K(WV8s@N5q&S}COgB=^6*>A> z{gDPrs#w!b(Awh3XcJoE_#ETa$Wc|mYn(ChwwLibfkzOjxVOPfx#kS%@?{s-O0`vH zCJr=7IUc|3@moI_zpr>xzM~V1%&KdgA=i|l=S1fi77f!$Ud2_?pSaeWag~rW6<0le zty6RKxdVtRMzZRAt#j5jwjDU9tuazL!(i@dOGhkwNhDS7Kh5MNiyK_CklrB?Es}`d6kG$& zOwG}s6W`Km+L@UwkaU4tZq3oh38sOx<{NlKz2SGf)NsDSz2vqW{R5E(Nr;ud!}=&2 zoRVfn)L-zcg6qHyx94zj4!$o)$NTYjSP`{@v+pqRF~JjOfdlKPq{TVq-D>RH(F9fql|wvwH3YEW;EM6wB#H%qA-kE=8!XG-u%UNT*gO` zoCP`h_<=~fR4}n&Ot@agn_XNtYjX7YlAIb?R9-XNc>Ox|1_n6~9)i~9==tK|Y;T$u zlE_aJTH=Fde$*hR0;{|R@22NIY=(R8(r{U5sedxdU)ZP3W<4|c7SLh<00p<9R2T7yW!M?GP`^;k)BqG)LoXN zkCAu-dczL9fx>j5?R(s;iIbms8>O!%65gN(mzxQ{-RnWsL>ZbzGd1l}tqm>qDQ~Ow zYSfaMVb>n|;bt?#b3VH`!`VpXTg-T)dc&$T8_@PWV`>90)ok??w9-uT*r(pY^re}O zhuJTfY3};;;xsFf_Enpew6!;^RFbU=t^99nS(CcWCzx7UJ#dUY?e`@)FS94SN!aaX z!!44qeGONR=JT?d--W&LsFdbPPXNw0s4p8fY6{WH1X2Z|;GmOTUP z^9tFNVfEw@@S4GqW3+$V#Fbr(*1p@kvUiAf{PM_=+K`)_qio%1wXf&sDRMPvN4SJ# z3(3tlbD<=@&Ah)M$9Q%1f&_cyW`;&LIBjo^zD-h+5Ngf1?PeLDk#_IPQG0MLt0jbe zo^yn)8{7uoEX7$&h_WSQ(JNj^XmIWk4|R5irC8phSj|jlG-A{YQQQZh|Pl*bRt<$ zZ)w%0mUhvb(NjLp(Pe+XWhlDsNmuFnzYsU{0vdsDv;{Om=YIFuVidI=|t`b&*dY# zgxoLvKl=CF2VMVQ)R>sdv4!A0g1wz(ihUhgLbRy`$k5QI9YM>wie)(I%}bT`XSo~v zANA(k&z(3vSC1Qlwp=vznqtZ!_7jzhhY~#0EzH$-OJ39%_{bhMD}DKYTy#xn5w}td zsq|M=;Dut^)5w$?oZAmv$mpgzMd3o;qIrEPqtlB?G&Lf5igWdS(m^*!DF29&TG(O|3vQ-H*O*ybD~T;xOb5*XCxCk-4|4^p zT?AENp9f4F)r;G~4Pa(r3}k|zp2^MV<{4KGw}l=ernP2eUiie!)`oO)T#9sl9cfEX z--D!%nb}bk8EJ1vvhmuZRAM~(iPS+RlZhX0cV2D}`41h%vf$-{l{tM2xDBieo=e(Zn=|%>ox?;T;v;TU8_Zy%Rcx}mAOlWtL(5yYf2(x)R8T%NR7On-SWG*z_XB2Hp?4D>bvpa7Y*-btoGf^|5=On~lKWqU?!MnkaO8jdD zA6mxbtR5W4YpJ^gFBVJ>oo2Uu$~Xu{<*{7wOINr?YHvI!_IzoPmf>m_Wg@=(x8@p# zbwkD1lf|ydfzqqiBb6elN9?m7sp$%aDw)o!?A=JoyyIdF!e;y2flk$bQJ%R)=t#+_BPLeX~KLoHN;OTjWu~ z(S|8uTKZ`*%V_1wsLEA4_AM(Um@=K<-Z@O$y__jp6&{lRnrrOU3in13^#|ufm23}k zVzn85sF~~pO@;sGeaUv|qIV?*-xajnd2kc>d%@3f0V*TS7W`-Dl>N-CqL!`++Ipfk}kef)sHy zS0`!=o9K-^OH9!E-_KJ|CsHHQvm)*2?a2#7i*IMF_&nE`|KD%+((&3iBPWj-Ug9ee zm*QhLKHiYfbBUOzP8PauoHQbcYK(`r;v?dVT>Wy%>{y9oTn=}H;ICLmIF_s5BLNj& zl0&_ug5$w|6s${+U-@TO_^?ErJHd5==PLZDYnrk_ z4m`>H0qF&iCWv%AIo8;Qn~40mO#tM>;b$SW$yU&wI+xE!p^a@Q&>X1Qutay44%S4_tx z$Sl#;Ts?KH{Rp^~*Y;{TI!f>uH-!xRH^cwGbB&z?F@o7_7OeG*V8_AJbE5+`9VBz< zcv|;OuCZjR!X7G{5@oLhhn~tcp1(#&*yu^#{jaTPacC+R=MJKcTSa;NzhRI7ua#n+ z5UiephLo|uTpQ>L*2-3KC8Xmks1{Y?ZAdtEgG26u7UBGpTv z7erdJn#a`)a2t4-1-!b+T&S4VIOVt6kE?0TF7%vV%;{IS1Y`OY9#~5(P8unwU!J~L zf(|68D$nviMh0oyOPu%E+R*n6;8l7*bnSqtAFbdpkK_nPkoHo~sUrY01*w+RUP+k(&+g{A*Oq5YeqtoXH7_telz`jq zdB$VsP{Gp8R2|nNMO>a|oQHAteI(y?)Uk#8a~t>{lE#7e&E%C~Z5C4E&^%+HT`eIP zXqgp*w}90&cCp~-Cz;%}gR=wkj0xNf!I;v<$fo!KwjX%lK~i^|p(3q(kTD?*TsxaB3LRB7>g|r zvm_L8o>#mfX5PFcV&;L zjkec;YokrylY4!)fxD-gctS7szd+ovCLZ03YA2zVVr4=pi4z4iK-W81n-tpS07ct^q zoESMkyQ7q~ch}F{$QI`ro6C2JFV^OaO}ZYW>U1-2ul&QDnVl%*obG0%x+NG%>PN8h|b2Z^Wb{yMY6yYuum{?23Yk#SCd1seSA77u{ z7_l+MW7+IIwOBu1`)QBs3cCj>_1-+4F_9V3djwY3__g&ehuZwygx>LRp1yn_x<*iS znSS?_V~7@8#?3Fp*ViX>W1jIU>J)nO^AksFtIJsR&OoYsJWpTJpP)#pO($qg5^OhG z>83pWM(Hlc2&NY0LpJjK;m_92iY!# z;&@y}OmNkyJmX-NrGmeDoHlC%w_wS0@;CUNqpmQqk-z2%=L~xyCRl0M>ztEfEfDPy z!4=@F3*026h2{y4KERn`-#@_^(TdiHLCzl4sG^N4mzmuF@-#4CpD8#>@ceRK@5O@C zy?8_~P6JnikBe_zy1+K^y$+mh&DYOJR@DWo8uyEGd1ZXc)=s(iR$X@Bp_M-Y5A ztmD;ub^Mplz4BOms~qgB{HLSUyq4cc&vb?f3Ao%Z+PdlB!#2G)DP)`kECB@nn6EQ%s9zlaEr%WPb?bK- z-8JKESdd>c%-P?q571U_jF_%9oW(*ei1n^@er|oI7M(aTSo`3u8vNk-< z+Kj7H^wh?QA?h^d9!Ro3dhPerdoare>EdesJ}l(A*|^r@nk41T7{VzgbRt;QuUHnW z0p_hzNw)-64?C%COu@Wm%GY83+W-9!Hr%fPA#1Q(|JZ2!Cw^eNNDs_5L^AOMn>XTy zQdzj_E($v2T-b1z8^IFbzQn+|6lQ~Yo7hF#l`wypmVHx1gjV)bw8h#2S}&+%L`0~c z4=0^v+1&c|+RUx2TQ{Af=y9-&Yw*!|E-c>a!IgY1F4y_6B)?`{tux&EIc?_46CK+2 z^H?kgb4o?oYCLNXqGsd!NTvfRKWQ=8FKMfyg z?SgfRkAzRd6a33CpY9OQ*xfFS# zDa#SC(y1FIx-_?bo3_%%*?Er~4IiYeRJ-BU+wpIlMSSolj7k$mkP+BThF`x6VFA`G znC%WS7jhvi)UN_p)nd1Phqf)y5g3%>J0u9Ry5EtOT=V--t#`Wh7$eTD7sAE_+nD5e zmb!Z_7DMnC3Uk9WSNNph;6z-OKe~JOUxeZ#4d#Mrww|yMzje4$iwg8PhFSO9FUJm3 z2HIi!5OzOPV4NRIuw?#~k%?}5zRs&b<|VJm9Z$~c?0k}0LOWW?xO_cT?!p1P%&92wI9>9cJnW|66ZE-xqG`JN`?z$8wNX+r)f*2i?~4 zm}JYli*1NjCJC&^Lwux}w?c0ODsQbwiBV?Ui@Z`_-dv;T$kArd>0Vt0U5At%V@jhh zk|t>-Z7kp&K~MW_zWzK{vgN|7WQ&Qwc5egQ7FPond!_ zo2KXMK2n3ukmj4^E$1EAx~AAtk^GnD>o1QsB{emCelydV8l=qPe0`ow4L9r}PrX)+)-AM& z&lObcgZcVdiS;9If4O-JK~s>}g>4v?9gv`^Jzt)IRjN#fs?nWgWR|}zhebcWg)$rg zr-9!W{EABPX%;L(#`^lSgO>^3ELbfsq=BvF`No1splp8H=Q@*iwN7tn>pJCmh4(y}l8+*Z5 z3+~$s9z2dK5^b?W7b6|_XdAb3Sle!Ja7DiH;_@SDe_mWp z4ot__d8DkT^7Ug9;=rrCJC`lI=@HTK_O$WLcK>1)r%*zv;#7c>z%o6v%oTj7l6N32 z;B4?A!J~;ty#wKlDpn1@4&&YJ1m=I}^`f7xBiNE{tjT19b2jIz&n{Sw)tPHDkF|IY zJv)M)wk2PeyPQRnV7@Jp7zvSUs9JelD|F_wRNHKD+tZX&JTDcjjt?sVr){Lfa^+oBU1dc`Nlf_yMLDw{uQf|9&jW09VyEzf4?|q8N9f0J!eYG zypl@338@033w)RC@xeR?D4pJ1B)@NevO!D25^MI>~T=;OHA8 zoi=DX4@;^IProGbyc884n1QDfq&g(k*$=;Dc6MHUM-NLt?m!OSoo}4Qv_V2*oDgGo zx_GbyKOo606CAnDyG)vi=6oYx-znN$(W1X`&9c{nGxy}1XZ8yAy_p5w^WawS-QruX z5#KwwV?;!gZhgLfr{Gh9m+YYXW`L8yD+KQmye5Ey7}X;RQo@^TxDn|Ek(9YYGdKf0 zTkykzc}3$rJmb+ree;Xi%YQ@Iw-JxL}Nzg0*X2aSpTxU+L=;ci4<+P;ZcA zaJd(s{+l;D>%d)J{82C74Nl^@xkwV&)r&j96<}4S$9i$dZyD9WDm(WJ?#oUJTJoo6 zObg8*V*{nB*CY9Vmaj9_;R^kmX{+!>9hKKCF&@p=|0L2N38j|PC%?*addM^$Z$8gA z&5vF*uZBXAvXSbL+9liDz0v`Z8jw=H$k(rwrYb~It9QY#v6dDX#|(|f`A})#xi3o9 z$a(JBqGh7_cjoI`Eoieu+x8k=sS2Fkm9PIxmgi;=n_6NVvSZ?qO}hwn9=Yd-d_BE4 z#^_znaJ%a&8u_Pu<{DQscNoM|uVj6x%DOB{*6b#ORcJOI zIycFJt#-%Wa1OB5 zEHlOAHgga4la7`X&Lgzc{ZP@= zD&)(1m|xeSB}eiEC?!4n0-9Rvwbe5%w_fY(vn9%{KQ3_|e8EhUEhItO>H63K_Ehwy zXqFSCXirGkjrH7XE5J!p-Nu4yzQU=l7<(%?BF3%%O?)p9%yfkV&-cVy?ZGn`s;_h# z)&kQ+Q*}_kg;V%c9c=XtA7IPISNk-#VWlvL{HST?#MfhnYF!&Rv8on5CC;tqND8N) zH|DpS-f{-nx=>oKa;t5)mi?xpB_P>d3Ct+sdDNCdZhfAlqZdU-DXWMaq!1P^rbwTA zOeAIW-uxDI+KASZz*>}Og}qwn+i1Zvd0b`zW3pT@%S2Oc;eOj0&tdVtK0z!(q)500 ze%iYeNsc$*nJv_LwEQY#lJ3K^xFxf5&`qp4)h|p5WEhGw6Dx`1xkg{$9x& zG|e+(HLO@Bn55~7V-k}ibXes$_eXi8` z(Z8CNpx$YOoSn+|QqYs#Zv9PpUfiK_xrnFbfOnna?AGg;a;xU)LUEWN6@t@ei+Mw5IgQ9)TLH2Y!g}&g{-;tbemk4%li-{VRN{_2Ts;zeG?Q)ep z)*JUr-%mAqlg}J($UEHnosz@FqN}TrFO%?;i?!x@P;jdZ(^V&8G=pG&^`!oK-hl%Mw9xv5j^$%))Y-goOih=<7%R-G?j z^A8z1(b5l5Z8G-iRcNZ(9z8d8lCo7gk6!<&+b~={A$s(F=XBfb8<_gEy7h6=xbIe( z4S2PrR)G}U;noAC^S{y?BgY60*3Ryy0Xy-~@r_&ml9fEm2Jz6l7?9XVmJ)7c#J=Fx zGo@#pR7uJXiANi$r*gDP>niZ*MsH!(ycy-(z` z>2hUbR_WU$V^2@?-O|iTIa-7`W2$7-mV(xy9XkMXx#+1b>d<7m8*3q^{DZOP^b+hC})2$8Y3ZrmhdjQwJWh zmaWp4iHFC;gUa-`=cfi}i3g-cZlXr=R_WJBjRmN&UA{Q;=mCixE&HKWdgkS5PxOxM zUy9a&R$8%2zge`yqV+8W&2A#%_?vm|``ar0dnpiiK$Wukuu-(V9L@F4D*YizRNZim zT*)UMzince@5V#=zgFo#Nw!a#frGT`K4joXp2wj2$MEgZk5v%_Ci+Hdk6R}@`K3i6>o{%|TU$)c#Nw!n*kQQ8^YtqVZiwD(E&;OIa zHE7k51^ORkc$g=XXl0P~lW0EkX{5LU{c-6%&xv;EpmUm*eUJ+*2`wnTz?l3Ns&Hr6 zb#j|N^$L3hTIV%pxCLgo>9%%o!c3Bqv4Huyxywtw29wZCHsfw#h@4fReX z6WekJh8wQ7aQ4tQlW-}%60a{XUdkU3UrP=#vu*&l%rWtvUfc~%zrn=YdvU}9a(JVO zH}~Q+usf+he_e98p%<5dEjOFKSD1LLvZ3FHR5q``uuW7m_ci@ug0+$V;zg-{3ODd% zGuZUr*b=~X^UXvi_u?FI!UEHGfZ%a0JbzS!n^Fq&WikrtOq139O}z@9yf}todY*&B z3h~r&Yk_g3<_R@nmT%QKS4S~t`UrD?q~9}Tysg0aAjEUxL1lB>M`W`cEqhUc@z#5V zXv&h|^hb<69cZO@n3)jaJrIX+qQgR+6CILaoy!Vzr;&-RIvLvnYtAgtvMj4fj&>Of5^uu@4d`1e04g^ z|D}T7quv-MeR5#dU$ONt%dglLm=A0MVdN)ou4`dUbp>jhlwr`_Z#VCIl-7in{c3@F z95J;1_VfKvLkQS`n6jIa*#nFZaA+*9>h}xOQQ>B$-Vv`M_)Zp|AK=rC z&x{;gsRs)5L=@Afyctt9RfblIHd!=|4f4MK55ZZ3R*B|f_&37!zoNe~n!i!yNvft9 zKQ;d(CHc;HXcw*~Tq?GkBsR?J-!&@HKZC9+KINFJ2q&(Pg9XMpKgt}xALsn>2T@DB zN$4f$>g%T&S-2{3$%Ben0?zIaCP9_Ohs_X zD?_t!Zjl}?8FisG9Vt-nVa)2-e{pprqkBFrP)m@eu6mh-%|h!!JHX$jMz=DmTJl?p zUin$U81>x=GvVLL>46fs8gbuIve-O`&!RTsvb5sr8bq(}#O3oj1H`aNfll%4zl@6% z@D+cXDSdQt7jU8{d_nNGl8C@036TWpg52E~g74V(b($;*ajZb?!82oA>&?4_FGa6K z*J^JI4|IhBU`v~@p_Qrln|LU0{9hpUHNgm&YKJ5RdAVTP-ba3MHtEO)e`X>mgw!K-6&o&T}G z`1+`E5w>|#NJeY=sX%|GFO~|?q#m=-k}q(x@6*b>1yl8m-i(eJqc;bqE^en9^xB>R zU)2yneoZ)ierBA})R|GE1Gt?8-OJ4grX>V$Kgqxq(XWtW3THkTf#urOjsRYFIYRvE z5K{dL^%QO6gAw7H#pVdHT9(s7BMNoRX`@X-aaD*b$wqr6;tHLJE8FG>b>!em#dV$J z)BMb927i{q%it@dS1i!(I}tWcJ8E-W<<~8dISchSwc}g4@m0JY9yHh|0Z$28+}xsw zH`DHj_gjZ6(N(A))y}LVyKf$x5}>u%9U;*z2uFTfsLm56l(MqwfbGjIN zE!2+~_ATcwcZ~Gwg7v@-Yvb02U!hGK3Ul4ZvejdSoXxc}WFosshZ42~*7`)DK16DK zq^1tVZAKW=ES~>TsLZb=!%qIS!#ZFXtYLkjjSF-P^$T1;0|2vjfKV?QCpMe8XlmI3AANXx_!VSWKIr3X3EtXps;r+DM_$syyv_vizSc;}5I-VE50 zU$I8my8rX&v@&;w{7FpXzmW<7yO_Z46p!9y8cmy;?o4 z^xJT${DkCFibY;+9j+tdQd$SD@-$o$i(itP!Tk11^H2+mzr*W4a211%xKxhZxat<; zk{YzO;wnoweflL7a2s86X(_w$?)(&UezXJ z$2qRF#(Ee!$2G(XLt5zf&vzK}FO%sg2 z_wl!uJ|1ro#VDEHKyF-h;;Nj0)`%-`Ev~K!jtIZ=xKePPG0vJ?u{46SCRdZAhwzaV z>IhLws1jcjkFjcfX~F|Mj47*hcMH$Q9yBXY03LZ1Jh8^BHHp@YR`+Ou{*XL7Zxv0w zG8y|Z@2NsarMt}3mR_o5qs8)&pu&Y;sx_chG3xqCoTo~NbKK$R88%x9(^pHOK1|l$ zwwIVsq-xnT{S#JwGSFQ^3ib7}^tK0Gy=#d-!kdfTNS)&f^*z@j6-tad?~R_ISq~G; ze+@0Xu~2_XqTNL><9wFGyuC?7imNQtPYpxL_e$GEsuAhULVc-P2=q!9knBB3srw7{ z`RRnxSCg1ps=M|G%TLJ6Px zO7O#ieLv;l*=H^FPB)1Vyj*bPr}&Nq*V0LNk;U?(;3a}H!S(cyHu|0=T=0{Ew}3P6 z@fh272MT^)a5FgYUXOl2A~{(M{#meP9dR%B=pRWW2L(re=A3X%95^k@W3<)|FgNr$ zLmK+6?brWlU-MkG23j(dU>W#LxX+_ME>UcjC^mkE^>rzDH@I2wTET0=BLlS$MQcQJ zK7P0Hh4ICreg7G+do2(0DrtooWV+z!qu>N^3%)}o>mvlK*R~}`oq={YTGJDE8(VqL zv9hfFRf5!kUBuK+f_xt_=U^^{z0-WWN@KL|2i%&zNWE6WB8Tk1)q1YwQMY7}JX`K7ly} zRDBJo?*!&bP!C8wG?Gp%|LVlsY`j&<3Cx|i+UDSDdn1gai%YrWl5ojs(5_Tm-N{9l zoF174v&}E+oh8Yfv;^jasRv4HC9bBsaP^&}+yLqkBqu3r*&oPx+@Q>RKg!RnZt@4j{px7nVge*Z@KWi~RAnjv}8%3P$kg2d-^GE z3H4_8S|pNmFM9?!*^9>twlC%blr`WAurifBkt4oOk);lBJy=;!y(@Uz3@)3{zc2)Y z3nba+1n*r7P6vm+=`n1#)+*l#QDg08;Mw3|Qrr~^%jYwXfP>%i7$@A!6})C9JIDh! z6ZhMUaN>KJ;6t7%)3oGoDQ-Gi;9ie$mdzZc$yqjK;C)~Yrqxz zJjN+9y9Dq2jsdj;+zH+&5otuEuBUI;(>o%b<`L#SZu&C6Tq+^d`7QUJ<|LLfw7`Ec zqmeP?bdK79I7)l@wDVf~d8E>h&52;RG}X%MXsU!~sO3*Q#@SK>1^;1F?Bq=z>Zb%L z2k8#U!(pii^@;m>a0NI+@Gil7yU6i*a1;0=7IHWm(=>e?d&c<(d&O32?U=_n|K*s3 z@SguN)OG}|^|;44!X?Ig8E}M)dGwUCk`eezvn%NmRt`t8WrAzKsWKEDBsF!2*Mt8- zsz=)WH3gMA7(tBcfRw?H(xq(M=sVw-y?91%FHQxQf@7qU^cTG36W26*C3xK_k8zgl zIZ67%q^QZ8PRf-cQm4nT6FMu>t&c^{(n{7d630DD`+RGT1qVb^LxdZg_1%Br-Qd#G z|Ao(kYr1}gCu<3um|=^1j+#E>(QlBNCIRDSt3Sp`VP#1Bel!QwwNesaOmelCzjqF| zH>1t|$?VtpX5slD)c5r3pek~Kc2wGQx@h(vCXX7fb}A>L#b5ZZN-G1e^I}zLzS`7j zwj*a^ig^2u1kvU5FBJ(3!f zRCTH^o9_cRdqZsR4KbSnbR(7MW`=i&qz0w<=UJKnmr5D$7d-PkgOVE@>{Dcn=nDj^ z=GqO8_x%+%NA&Y(Y5j@}Gg}p;*Ou27`vOl;XsY}%my|yTsk#6ElI(RzT^2JnLYbN9 z2HP(C6`rj2TEtd!V;@*#ymeI}HoB(JVscx{KY^*$_O(RGh8KFxqp%I-C(61`hqjqTnlARh1Q7n zthB>9H4t8qIo017hz1uKBc2)`l_h%?cs366k z8tsec9B_#jA6@Ci_25SE8j1Ni!F$EGrI!2r*dpUppJjs8sXl4o)Nx?(Jx6fget~^x z$>WQR$AJskY9={aJGh(E*pvlh&`t)12}Q={onxZQ8KSSBVZpt|8fmqqqB}$Xr{1%k z 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

Gdc`_+BT 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

ZyLuQofrE*PE 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%0DJgdBGnX|Q09A=L?<$kFNNZznE^F#@C zPg-)n)C6#-z0G)7a&z%uO~8jex`G6r(Pn%wOgel&8IghHoY-b0N%T^GRL}iq@l}cx zJE_e`6JNiQ1l3MvJir~M7b*4ZHsf~j^&yhFpE-lwf!xSlFLJA&*=8QGc0{s;#>9s* z!Re8HtPkQmu=SwVxKM&rnRr56R|%fSI-1~3;(A5_xz-JC(wM!LVpXMm`Xe;dtOAd9 znd2qK(9uliNxJ9YCD27MWaZmRgQX%}L_BUcmU)f4B^+_9A1wUYl{91oj@1%EL*)^hu>j!%@Q0Hlvdvr1gjd`}u=(sm0(vmZt6EcWt0(raVNj z4M>$6+KjcTto=o!uX%{FwpP+QuV9@~qzwV-LGcxf1do-pA!6SAwz*uaKzpIYP(%9)s~wsxMDl2e&TwQ z;AMgbzy&+n)Z5C|wSu=$$-|>wqZaOLGky`*D+NFC2u;EZPRygK30@%hQ(W5%z?tB$ z1cz}IYSec6qg;DEl6{w7I=;d$twIX7RPoG#M~ONb+yho|yenA6kqXYe zm;Oau9}EQamBdkuWZ&Ip{7s~t0cpw};%GwhA>Am_CJAiC9l2fBhn%9kq*wgzs=Yt0ZkCxBDe(XEod_`1pgcl4k-dRf^84BnK!!k1TPb8 zd7ZEe+syL=UK6~nh+{Ql!I^vfc(>pe1!sYa_qM6s6xN#se=C8MgPXuAv)2orxR-+T zf%6_~Gj5WUTrBv)y|}g=;kjCGGsjwI3BF5Q$AU}2V^vLE4t{Yj1(^=6D`7@m0{L~h zzqEeZOHP&{Wk2ChO|$q2e@xmSxQeCpe~OQnO&<?PiyQT{nMk|E$1d@a z0B(B6Yw%qzj!(gd>IOb~jMk8Yl=~^~2k_iyB@R>i_hX)|_Ru%z`zqUvi{xg#)i1eD zJ!P<`m3|@~NA<6_nO}ojEioS6M;>H@`;N33OXOlTm5^d^1$cn;!d#be^{mx z*FT?6AZx_6{eM_UVLej0{zULDuss2s)zM}ov-QOK^7;Ng=%Zq}8l=MS+Ki`|jj%o( zkp3-FB~pKHn{l7`y4f$eB2OE3HC;GL`L)gPiT~9Sl zr0{mLFvcONj^@+Hi7^+cVS2l9$WCDYT4rXgYu1Q|G8`qG({7$`Hceujv7Z>b!F>zc zjZdZH7Qbo?b>n{e*@zmh(c|~=<+6Z}Byde~yRk|N@@OEoqr+p%!;vqw-B>Suony%5CXq>azZ+;6iW|)1LAcu=Tj$e}nC{;Mn8s=Jx}S z5v}x{u8#+6f?71`!;ypOQT1-kYvT8sCn%W6qqOIX@SK(vG?QFY0aJjcM;;#Ka?dG@G)=S9Co+PmY;C_R074M4$Zvoq*Yw4TEc9@t$ z&j%mR$EnwJ(~yg89p-lh#)+@bpQKkQ1lNF7(H&pvzr;I(ml#DXbvR0x$dru4cx)+t z7e2+^pjZ5Y)iKtu3Eub=330y7-E2~au}$)LA3;hd;(9B1-<0kk8AmBhldh0a_IC06 z`=`jYd~hEVg14%!#P3%RDW#RvAQdt%^lm^>HGNsBXWTNmzsI~wBTDQTJOxqB=BRzi z_Y7W)WUAvGVz{_Nt;AV1mFQB>Sql@uO?a0XG3zvNpiHnOz3F~k-K@rlH*QvEsk>4M zQs^pX2*vA{=OKMdi0Y*?M;!xiBt7#<%@vETrUetA1<+&Ewg5|oC9Li+Uh^}#q)ga1 zN%*eAx2+f}qM4PGo+tSzTn*MaYdQw^AB+1&*czDbdP;MykbC# zwwTP@ae$^81D;AIJuP^j;8zaNaMHkq;P(aJCb&azA$V4DhfyGSgWyx1CXib24zPO5 zYO!E>ywq1cP4Cx-wsl>Hc{u-M(Qd?x-9-}rmwC{s(gc4!*WX{hf)9HNQUhg_F2(#^ zK;nVV9L^UY_g~gwem45ubIr(RhS!1*rgj*s#n;PzOd1YK8qi$c4)gB2PqZ5kl5AIf zm}M?mt%ktc1wV1nGc7g=yc4VjC0Bt14Q+K`=5_QR0_7)_y8eAun6IY%Vh_*=da>4% z_j=j^YKQ#;MloXLqou@RU3qQC;1&xhpCs5e*fabsKNtU{!3>y8aSg^U(?=z$f~tAn zeB9i99U=Eitd&?Fh~;{kwFDnl&h;I4;TykfnemtpCZCu*Ay6%HDz1hs%%(tZ%R`RFmG0MP}oZ2H}%1?&&Z( zOyxsUkxFd&D9rL)UI#0R>cxpiIPWmT4SVKZnLJl}a^5auLBb20u$!2g%801|>p`p= z^>5jVq)$A=HPpf0%Ev{_Au_B7s|Rbbxl(yME<#)%hgp7npo2}*vi(edMOZ4Vtbjhy zoT&f)5SyS1VbdOBx#JlEs>V3)Vaa(F)rx1>_|pT+FYI8~mtwa+qn#BJ^+}lJ!$&%d z@AMN7GPU>mGukAZ7k0-UN%S*X)Rsc5E1n#_f>Q=dg-NZGpVXgfSO!c}#AFSyoiK)e z>L>0xVcD?2ep1QkKG^NBE#@Wec$TblHd16Tz35rCD8^yAp9-czVoruFfa&$ma>Y4V zJFwEsEIFlI3rnbgy;9ntPS2JENc^?14F`fD32TB~4hy77Lhtsw(^Jc-*P)-vax`(} zm1}Nq0#?W~R2ke2wu{m6s!_-?Upo3Z=qp9%vsbE5ywz+o5??<0I`lw%Ql&~@m%{YW z=h!LVfVJfn?(Swqxa>JC?A(6XYgIvC>P4{6cyNKul9>EI$K~&uL>* zCF*2^Qal8X+>tIk9aaKU#W`fFnrL}wm1y#}97P!D-X+PU5(%1af1Xy=h;`-1Sn`g2lzykYG-1$L#%r463To9FbnE zn-SH;1>zzMsS`P9kzeAnr-II?9IN504s&zd1U>3Sw$eAk#^c*z#?*u9z?^Qr9b)|> z!zxTY`$gJYG*&X!V`}|%f`9+DWKs%BgSe{~cez+u#B-b4M6&D(E=sL2NfuY2)uRPo zco0?#tAhoyT~gizYlP|XFOl*AtoUy_jE7W+XUh7%3Q?+L7fDWOrP}egwJnNU>EF1+ z+Uo*i^4|mTnYnth znMaSWNn44e&E?~19BaQ>?Z0}7YM%_t{NE0Cs;j%;xR-fBAqUnC)BE1nrfE7=y1D-*Y{{x9&BjG z91qJK!d!%u0?UEv{Vy|!$ib=>%UQ|Bf)Xt2_gHb2n(LA}tO2b5R>>u#F27#J-@%rn zb_W%cq2|!AmDqk@cyy|IrEKzw;Jk1?bTtj+%I)34Hxm5T4b;v)W4+}C1tiIw)M=8W#b3jKw(dr4xTQJOoWE|hDRMq_QK zr^1b1@hZ2QXsoo8SWRN3V8#9otDn$pIat=eV>w@wQou?Pi;5JX-k__6xPFDCiQb8o zC03qT16XxpmAyu|ksUPXeyoPq2saTcMXX+NnSoUWdl~R zSjuG&R<~HnrR@va-9G~^qpoatvT) z9wse4SovZVVujegB%N3vo0~#@I?P5~vE!&xdU;XlJ!9;`RWmb|Ww%dCJE8^ha9 zEv#$=Yl2mdVBN5q5v(6pKZHq_723)3G)%90ox5lpR^6B{*is`_CRW*4Ec+4aT`^Y4 zX(`%1tAq#88#pz!dGK`j=^a)L{#v#lN>xT8i8qML+p(6|kBfjG5!oDzO z3!Cf+ys$0RF#)N>PQ*P#Y|F&5giA82B^g)+SobS$dUCZEI=>Fqd&U>$hbaU5&*Vu# z21W0Epc>}?N8FphH&tzI<0lP;rkNYsCeT8l1zIM_v z>qVqw6{z+ppjy7j4H49EriQ!-&bL72GnEgjRT$J(P;HQ#%1);(=5OFWrx~2OpQDPv zGn_|~WIFj`izG`wVBZ0A(iewXq;A}UgH4M79j%Yd@oXQ5efOZH6$3kyUWV7uZ2JbvO)RxwrJVA7*zLGWs%1KwL;@7+M;#62cFU3;g-gZZSHr#h64*} zx%AAgT0_oCCK-_EXU=ZV*PAPM{Nj$APvDhB!IzVQ`pwKo_f zyam$5{Q3KloMf>*gYxzUbpf2|cY^w^Pg%u}oEA83@(=82 z-?EAdvAP{`0Ea7&16w};v2Hv7`4>R79|CIYffkvWnWr$tx~8mR8P7v;ZVWFn9q&kZ zMcaSNL0I=|!TI%p7A+GOfLb)X3_k#&UETNc{Xuz}h!t-~@P!d&6@Q5N%Ii44Z)f~H zRxk$9v=j2aRaGM~ht~QAMU_`pag$3sJeGFRQ7M&!+aq{Wep$socoxdXlaf>1l?-fM zrh?(Z9Y|urA=s0F*n%(GILc~#pjriRn`^0a>Szu`|d981KLz7bO=+aGr)@0 zKv>}+ykR`+TeQS`%e12$h@h2jcVMpjz)^k(C3z#LAc1lnMz7igYU&F43m12f4~1UQqfCDo%ee*7>J{T zFX2wq5K!ezg)TsYyAMLR3+69@?aI&9V91K>KqO7Xcf5tI^6!^2(0w;89=~fF)@CxZAJ%s7P4NFhV{lDyzKr#MZOc z8MJ0#x+Uel;|2CLFgkbyZ8aCvosWY$bEHLPZ~^l_QC4vje3d;T?xji{>k+#PQdIr?0qb;%$>z)O*yR7103LTz_xl!p+*uFe~w&Jpi6}4&UVhr5r z$1u|BkeTZRgeDwA z{L!!C?o>IbmZ0?besKH-ESEVpp%l`*VN}hlRgI82S^{$c6Xg^H^$AnIy^6{%0QJ^u zpfX=;k(E^pYUk_7BVzGSgln5SOSJZ+b@Nh$pFud4zlQlt@oV_~tKR^5--v*`KVvc- z33UgQFQK$h9;mIL3VF1`3#ITPPVKhce3N$D?v;~({rKcS_WEM^$6TM z?gpL*T(c`=8lT!s4UbE>Ym2(&e8K{g+WJDm({bwee?%O$*%IBif`dK^~)ZX&lA)W{Vna|>Gr`EFEtrrxtGolvCLH;yUNnL7CrKm ztr@i%W=W^>Punu7`L&iT+H$R>7tOxblB{+eZmDag+Q(f1b;~G=CxuQuXUn2fvn`FO z-5g7nI$)0FIg@R&qD;Qiv?@;d#?+O1Rui)Hu2-(Kb-+S!!`5s!cz&^m3{T&sZ*)$^NrthWg^qmUNT)!!MRM zUFt{X#P|kkO5?=QKr#{wYt#OKD~$%VNbF0S33+^@MPjc+)z>lcgk5dgFEKBUZeHtL zq&6Rr_*-2XG$ApI4)ect@s4J+_PWG*v~faWP>_cvBxY-&>f;j=pQuF(PdSFG$EGH3 zH`C%7iT#}}<$cU{-#0scH7j44+mPc1D4lde;g0QlDCx zc&3)RXHDW)F52}0>ah7U_GXm+L4uDujtste`gDN}tP>m!)nz{>x)Nz|E4NEM^n2pGgbjnNoi}W=wx{zmld~wrWL=;> zZn9>^(b!?BnKZPPHIL$a-fn7gymh?=uT`|PQvYyRohEvDoGn{j=d!Nxs9iFxU7YG8 z?X2_S=<2UrE*j9$+MRywXw9Tfovn@OTo>ys^+FfxhD!>SE=|7{|C(Kc zfHBJ*4^ql7>p1+Lto0f408{V1*4o}g9Y$C?3#C_%w2l|wt{;Q+e>lq8vlew7Z(Xgv zJKnm-M6GfY)9B*MHoJOwg7r(YdVI2Vt%Z^++#^-sKXH7BFI}5B?biTGDO`WjN`j&$}7;EcJ&)jJ}M$Nu;bf$^lI2zE;EgV@iZN9Cff62>S%JDu{NdAGm~xVjx*M~YSFZx zt(ocv=d4$l)ZV{a7n|tI3)X--`J%OD9Q}34Iz+`kubsLcwxvXtmRGPFp#3JY?;rUUu2q$I(KM z%}pI&b~d0=k8KN;4fdwdUv+KwQ1Y6(&8RflwvAF|+B>Ur;x^ZvRyMG`rjBW7J6B7+In(x-eOCqnTu?h>QjqsPnoFuMR$FAV5h@LpWSNPNsr%V zYe;RDpwE6Y&)$$$FR^*))DqkEH2-$nKPY>t%}yhi+McK6knJ~WQefMKXR5Xt>ilK4 z+&b!Kt89nN>gl^}&)25I_d`Y8dYj!$oyb;KokF&6P3oM@wl%e=OCL*fy5zDrXyG>7 zF=~91t%17aA=}46NaEnb?Gi!Pm}uRGq%}rl-$)>kDhqeHjQTAXz8IYf6lfwo*vn2yP!6I z*a>?u=Yb@QUI%RbDDEIM;oqOs{E%%g{jkK+koL7p_0h>)=vX5U+c07*KW_8Is|QZl z-maw#aU_(RO#7 zI{8oAyYVz|u-&IVKG?n_PMt8+{z4q>FSa(Ig6ph})tT4Wops2bt@bQ4Exq0Dru6sN`AuoAktU_EPnp=k3?VQ{#R1m(-v4*}Ks$++t{9-&T_O1)5O;y$Ic+I3f?sTA?EOk3} zs3(&g9t$mQ>TRfc(;P?Q)VPL@3$@j4O&zODYX2<9i8yM}!f{sZ(bDmCEw*|-8rjCN zfQI$OoMoLK&8T%-$5&Qr)YCCl-PPC8!c4XSjy>w+p^h#l^_8m~znJLqHI9d=4 zS~kq_ZUR|~G0J{8&hfIDUYzK7pWZo;+)llm=V%p2cTI8JNJL3(^Dj641{Q@@|; zs2fk$<6T_pvYC!gOzP|#9fM5j=d&Ff&19O72&YC{m(i_r5?82eZgNaFkz=8wA-$Ms zO`+FnyX(?DZ{nck(+eF-O*DIybrxmjTCe8;v!mU<)wDkDAGMWY^G|UKg%>%V_|Heq zLUmw);{`Krl{oGs(+bB7TCu|Mp7u?Bd!^&DN&RJ&15ZZ3xR9DogYI?Qs5ZXO(YhJs zG_YIgp*O5ndgdi(L$W6(detZQIX*PeRYTqB>N5u%g%~0}x8A6p{Lq0}-nRTyKTY@) z!=m=B-WS$fwfQHGUu&zqzjC0R-te{Kb-MYKV;R-?)-jseeedwolG zuB=TjevzC;S59(XP{&Mm{%NM<-!UX~+>$hvrtODyt9`Sxm})O_4#5cFG@EJJC}(H2 zLxHoQnYP~H^pWq?1Ur4!HaUZyT02W zB`~`ioN09PBxghQ!41xZCYnsnm#EDq=T5q6i?aiL<4tNnxL4YN-alvWpnmXx(;26p z*k|ivqLruYE!B08IDe{5y?c5ZszaV~PBu~EE@yk{`HiKvx@ed44-<7AWUEWfpLLE> zAAZ((+~lY***BP0m@dXCTjExm)Ze=~7u2IpZJkr;t3!!y${EF3XzOgCRTKKTnnVY#wEAhT6CGmQ%dYP9(#x);>WL$+lP0=pg>|$wae((PlQOXc%|span(In4 z8mH?GC-z0lz<Umc?nseTDC8-x6^`{H2X*A+}7`es&vf$v_pAfUQt8jfQL_hVr>rPsE z!PSO(ncQjWbd!6ciN3M9>#Nyjcbu69EWK=#M9V;J9UBf*vYnjWK!nd#bUK8yjf9hw&JZq%S^9Rd0%%nec!;{n67OI zX}2|WH=twvfz=z}_EX1sb!X94&tnXHY%G%V%~*FKZEWWV&|l*)UuZSnol8&t=5@t2 zaM14MsJ}<9a|h^`>)b18(**Y;G-0AUNVW6a1Jn*f+?z3^%}mOo25(vy(YmYMed)&~ zuv`x|bkwJuAS9Irk&2XZM@w2d*xg=jp6i~1;eDX{I=XcNW~B26xvdz!2O(`IuXRtQ z&)%@6(fM`tOm`_Z?! z?q=%sU%O{uaktJkL|y!iyRC_=-?{J9765eaNB1FG`iMJ)?oLTeq?7xw6Y&VF>? z6V3_hcb=p~(}v}qY|5yglwvQ(?sR#aBOIrkjcY)y)06trshgdXHB(41g-z*5M$%~d z;TC6o+LxJRhs8+BriM+Do}+WW**nlPJw5el@d%sER$;Q9OQ?N0LAjKWp)Si#vf;-l znkOxz$t{yc(Zyr#WZKv&X$LKD4RQ0YNV=NN4NYoZ-(F%`XMR0iIa%v|ZXj9{Nyw}{ zRcVg>gDFYf=+q^$tKORV$L7#0+8bDnhOd6<8dnoC)IEpuU($&e2B*AXA*^}g@4f~Qh)8_Z;I_O{T zC1uc&BFvHJKb+KpZukIMZhIA`ktgTW&7jS-(U0sOCtX3~KSnX!`*G6s)b$gP%RWhJ zN^gFW)S9k;C@GybexKBm2K|uKoW47il!o81!CY?X*`!>$YoV(VJzbRKqfI|S#}JdJ z3my6;X$1BEEvYRnnv0#I$A5m0d{6-S9?=pYFSeL|Og-KH!g}78~k$+HF|o zd6;_slGI(T9p}l8r!{pvyJI~0VYM1HhPcOFj)T43DFrKIP^kmW6QiqTJ zXy&<|ZprclX!;}WdbICSN*aAM8|BzK+tbEGA-`uReeXxS=Novwri>Pzje3sX zJq6_Gijtk))$hNbCdPeXG5=(&MLuJhJ! zQ(;P|YwoY4juoviD{hX`Tzt1F;}m6_Yql~gLxc%Fa`Z{*La$v+*+}#LNEuH*{(&;N z{!&U;n)OMNjSYKUy2F*4MgLfk3_G8c+LYo8uw`&4340DrJO~(grKJ)5alge+t@FIC zX;ns27kd3tij$@mdKyse=~(N%)!f^Zn%|pRpR)U>UL#iFcUdvF3YXXtY4X6-?lkjV zTZS-axBC-)RMrrayLvVZM|bVVtYv5e??x)FXZK*6tvjAd#OEuy@pF```q5wMi2*u$ zH6;9X1kKd3HMJkjH(N(j#~*A9Xxg=@Q|U-cS3f#D0xUO=O#OqF8x`otXUfmlgscYSd)Mjn!lk`S&FSge1MdmK%r8ZG-y*D)<(;Ht>BN}{vY7))6 zKXnDQ-kOS~R;JfWlh&tRss6P-HP=MHJm*ZOZagnf-UgF(q5>0{$(vHIri<^{l4)fv zZ!bD_bz)PxqOP|seRQ+M8J}kEtu&iKP{x5TN7A5L9qa^Q@gqRcvO z!u8bW<4`(}rS77WZ=n=5xy}2h25IK%x(%sEBTILh-5Av{^CN3Ry4=vwiQdYvbfV9T z5>shgJa%F}couW(4=!L8_U8*&9*;Pb>ZT*FIWp;uk1;h*w|jl`*XU$y(jH5_k-EN@ z+MaH`BC#E1zmeLRlE20N!VU=bRq;`Vm`|wj1ei z9q-k2!s;DEeQe&*lyXgC3$jm0_E8^~cO)eY!c`=(wU0=kK74?xt%TL>zQhw9Ajp=YY+S&1|6EnCR8_|culalC%hTey0#c2y> zMV(w8^}WunPPJ%CGw&ceH!67(t-S)v?9YBhw`m;kV!}SMjd#4-znvF#R?m*|ag0yS zrUyEC?^Ans_F~36G*mZ@4tMc(rUqRRY-o<>2YVM$z3#}`p6=fDbXN~=E>dQx&LI(1F*Le3wQ+P(GEvBQ#oHBtO9OB4EKLUJa3FwQ%P z`i@7);_+ULbvI0a+}RVn$@J89=m7Q!$QH-||7%5eO+=`+X#HWL7j`Sp`>O@!rcQiQ z#nzejPx3y*q&L2&lHP}Yne4qf0c1P$($3T-H#u8{5F+ zoxLs@hM+Z4@yzw!G%PlzBl*ux_s*d;GrTUf{tey%wP@*V?+~gt$GcNKJIA{tp3c`p zFKXE|Ii1ce@ZO*{5Tk73StNWlo zes;IFxmpY67TKw)Hexai)d(Erfy42-0?>{K_I66f5&!j|Z z%{$_)Uq=<*{}#$oR*>gJ!lElujFU%Y>ssCS+tol?%BX5Prd-q%%ooK9Mj zi=;L1=IZCt6&` z*NC30t_KIHKD+R=3$Un{k1 zUEcx|txNIMryo;%SJE@dzVXyJ#kbp8VRE5raM{4*d%&b@ri4AtYpJ2nS3;h8zASZ3 zJ>ShHa;N!jpf?&@no>B;*OLaN`{^{F08YUpc)C6+Hh&o}g?)k&!9XsI-=M|1qX z$LLzW&u_JTWy;-NOL;nOb)34fkq=Gcm&U&IMC%EY>vNOxsVRfTWcY&gQKqlC>S^M0 z#8aE*zU}m5b6;yq;(Ql=;Agq1BMoT*h5K6g`qT85zN0j_l`o49wDRT9ZLNL7DEkWE zcgYnd_b$_@U(Cw6xNc!H_SX2pI!zAv9#h-3@!e(Gu+L{zFSPZ&ZK6-x`#Msu4n92J z?BHv!*6--6W2QM>d?V;zU3`b>R99b1wMjQ$iAnvryYFxuy_@43PLKBXVNb8OZyF`{ z@rCJBU!RLM^o5{r`P)tX5c+FBUt?N(rLPB_zY+!iSbtwrx_W>wlkOOR(80OBv+Cl3 zzOE*xE7$RkNqNCk8!z|SZ)#6(T!m`wdo?m;4*HTT4_HjKG7_(V^;(vhkw=A@8Q1*3 z|93Uz)!XmgIAX7tzxX);*mkS8zaF5R^up;&d7Y&AH`mhq@=e0OU@1na_ZYjkeyIG^ zVlC+4=XYtoeiia3So+0vMlaG2(^5u)RaJD z1dnyLXCE(rCLe~`3wu3Ad9|~S2r{=R8X4>6-vJlxnRNU_TZC^&whzx z!J)Z1NEBZ|Fygag;KRVn2ab&VeFYw>5m11DK2ah}0@ethlrKd>@4$CxVMbL{e@Ed_+OHg@1CTIe_v*W$NCiocfp1`;rdA<@E&`K2g z72Z4G2oV9G`Taaxd`5f*a4u3KJ|PDF58zy)M*jK0LyZtn{+(zN1^CWRZ%Eb?f!an97txksWWvEe$AK6YrBqM$hTDWN$@jozBOpJoh#%nBDp^^V) z;HbCuH3Bw3(4Z(0h9lcDLDb^9y{#;PF4Z$)34SfcRguk5@yjCAs5cy=^gJ>0`wiMr zwDjAMOg;{0ls^@Cdb9>SAx3q+7NdZc0FPDy8;~F#em9=J3;(fArv1nJ(%}!sN8ndh z1#AMyg4UghjIbRT-V{^=-v}%yaQb)xY=KLbtWf|?JZpo25oen|SqQ-Ys)S6(cNW~> zN0E^690QBIOj5pn}{)BAOiT_?ZUG{&;)#E$7dV!@Ijr>fr)4$k!`}_dZ~Jg zF$YT;P>a014H7C_j%ltx)sk09YSW9t!_^~&T(VvLBy~@MK6VZaHeAX^d=@Y^m`1z_ zFur_e#L;)7%DF7?P>l%9pcoCV23`*Aswnt;VAy3<5`GqicRjwdbK%1oxV;%CLDUNS zk$fIz`dOlBeQczh21Cdz_Uv%3LhIvD;R67Q>_u%H;9fp=F5_ruD=d1U~MqULgb5Jt!t zu>@_L6#=J9lhLONr4=?ZzJwmxOfYH!bHJGW;e-Uj^KjEs2482EPND-eahHSiJ8Uqes;_N;9b{07urlPGvD z1oe-CpFkP+ih@5@)dn!Xfz#{u6GY%nV$9jwz}W^G@kvOiY)mYsQcgS)#GT5>|1D-7 z27XPy;zopwC=og#rP1(nDC&k$_%|S-(MsrH;7z0OuTFq|9=D7sy&3&(P!wDR-Z~1t z2RK{j&A;D;|H9C+KOAj{yQUFuiwv`z%^^dCpAo=~%NW6la_bQV9|)XtY~=471OLK+ zkK-YM9lv!inxKz?v&AwhI0rmhg3e-g!EFfqblY?u`YNY+z02#ThH~VfW|a2>swgFj zo~tnXKu`_+jezsC$0)}J9Dgog1fbo=ReuXGfoE_0zeUwBryf$#=dBVWo92kOX;MV}du%&!bahDh;`+{IM7oTSM z~9 z@WT=>k^Vkq4b>0tZ5`T^uJO4{BCmNGg~LI$gdsHI0W)s(fX9fB2min*_^-gOz-OM6 zKL+2~%|vfvIU!@f90b%yfDz|YO1$x7#GeNqjsG6V;j9_?Hvoq{P~H>?3h@Cm&9z0& zxPLc^6D7gMjNN+RgW((TO~6^P5q}UkTXG}*0utJ}29AFDqRfFY!am^91lgdVYYjoj zRg45B$pjV1j9rJg><*w?c4fQpnIV8jOz!vH&7vfDImK=OijG_EJrW9X@+`uTX{8#T#r(=~d<+2^URH%uH|xH1{Ny(FGs4e{J|p)ta+0|jz=`b*f1L<2 z?!r%)8j?1U>Vgtm+<@agH|@z|0d zp(?{~6`_G2L|qAcSVZRNLxWmVag7lp!KHoSB9WP;xXxy@-UWHcXUtwUbnem zx{cm!xi8(4^8pV6aI)s=I;xT8Vtajh^YgvwmeOg}vz!qQ^LSHpkMvp0fH?iwmZs}usKu(9 znz-~yidLhcz#O(^xF!9FVCRi}c9m*A5H)M8gX_?4*d7G8i+GC+@yb7m9*?)oI9~WM zEnY~;mknH3nDb@yh=XOsoX3Sizd>QquhHXW$auyK>_j3G*|-`5*no0R%{wj>=>@1K zP&pzL#R@N;@$bW3GF)Mw2bWlaijZ=4vBL9Yr^}bVOZu_+!w-mr=^0qmyjTn_dWtsz zU>A`>(0e7WC#YP~u@a!P5ORzq%Z-Z5v>ML&$0N*|0UDkV178^f9})xqEC&7vFLDhj z(iERY(MQ97ih-xcP|zp_-bBYkhR0didVm2R7XvSiflq~*ik5-(2L4cEEx(F#iy=VA zJH)_mj-lXK4E}x5@sM&u^Z@0V7*1uNQUi7&&;jdW35HO(gD05M#b^K@*U;B7N6;+#@`+|{P#r!J%Kq_2*YAbP@cr~1gw&D6os50Wrqx( z`&H;J4bZFLD267s{nad#7XD@oJdD{_H2%+k504@TcM7y8n3eK{{lnA97z)|}$ADfV zLA>L^PXa0hY01Q404Ru-pj%?#p_CYk*8;y1LXF$>DVRU@{2045m76p< zc|wj$(}KEYi^C4PG@5T<`2RQ@b^ZTq0)`^b|7ikBWL4<#bl?AGNZ;oQ70c>~Rc)m* zJSR;omnLduuPBegAAnDh#3x9+HD=blxlti;eK({Ccq`zBjjhoC`c9bKc&f4Q6m@%s zhcM&z3^!s7j>>iEBFE$Lo!zrC2eGzo_DlY0f?eUw4Q{DM{4HRk@oCfm@_B1sk5B*w zLqKEyhsG`E1+I&24V+j%7tU>1jWm}g)~8wgbUTu(#8Q13Y&<+?*rh1+h)$-j(B&?L zBugSg3r5I3Ef#;Js@SGk#rc5KvtdRyJfMv@Kg;13V8qLTHHw124~$Krk^duLkWbU^ z-0QOx2j!N9woTh4ERB;gK;(?B3}m;=>AS?qL}Yv#+@wlD10vc|i}- zY`li)={4jm_@^|hdbkuI%_n~Ct$Kd?7V7(CI=ew!>E*u_r!~G@w``&@k zjG`xY3nqy=HBMefp^!NzM*Pt#oa*0IW7{wkkVj3*UlH}9*N$H41!ER-Stzl>%dcl6 zg?j{&FRNFvMhEf*Uih7mm?!=6Gc5(bpob{$`i1?Rtijlbly z?nVVw9qQsoZ`t~Btrvx4C9Ah6;D5flmc>-ka?mQ3Y6NKw%IR%l#v1w+(yieV(TN#o zu@>s|C+9MLATqv7HVA-^82mk=%Ewf1P}Bf{cZ-sPtHIC4&!~7*3^|NP zlQW*>K)>S0Z+EgY?zZGeywoGY@5m5sWTeI|mYG~)Mx1Q|4?FoXUU9OBUs_lAy4-M* zTkO^pNyfYs!B8$~ozXApW|<-Zybr-{xk(tGPo|6Rua7x{nh3t@1e=0)F=`JGjQB7U z&R+01VGP(RBNRU=%%nb%(#>zlc7X?niUjNa!_BZRy?1Y`_(JaB+DKv54-CVi(&TuT%#4_(_Ou3Ls3z*_NE&1D%dhq>W);lssoV{_QB z`}ejoU&>)g>k0lq(jqyE@~wgYyrg+G$j)*TClGd!M+VHbRV+ko>$BCd;)dxh#vQlf4o!gYki@GKFo*ZDU?hambyN1%Z&%psb}edA-E7UzNfG{zR-$q19eg>4<`Lik zPPgIF_Qp*(&QPo`kwho-=U4AnX4is-wB`{!1rPr!i&bN5Qo`Ed3JQeZS=O?irSebF zyR?;Tf?Ub!^OuOn;Fgj^kyJ4s$tb*9hzs8;eB%PS{J5`jo?f~&TQe$&a>hNfHO%8? zG~m+VBJ!K9MfMkHDaGrJQBCNpiV;6A@#P`WKzTO8Zo8y;WMfx&hmcz$Td7nqU*A`v_kvTKG|s0PJ|ZwJoJrbrfOfSKWRCFK^OJgq<^QXk=ra^8h- z{Dl-0hbBPJ{bo=Oe6H>&@EKaDqI?0LM?NFY`%2uXjrcXdhT`K|ED}_J@9gx17Ia`7 zy~w!bTY@GME$2s3oZO|2Ir$JcTTmnZ0dUTJ$!d{+EPQ9DCm?tNICm)5?Ses!&{Yh@ z?#f0KU;0n*h=p9yn}S_Vjf<j^&m@-Be4@*CMRNK3YA_j8VtIw#xzm;FCJfT zts3zZOflGC8}V0xHN(evgzayR!i8!?_`9=k#;wPHAVHi#Bd(y}c}O34|uVtN7APbEKnF?Vl6OU{Do14*)rj6e z?RpfWsbLOVK0C5DBM%1#BFIp|kD`^W?Jl~@7@=S31FOmH%ZN_^-Xsb>GX{S{ z;Av6#(@^c`1|elmugHFS9Lyb~L}-Tytr%Y|DvE`&GbXSH_}Ee#@rketH4_5Eu?+#a zQ6ek^9xbQKqYA<=B0%xbC~|fI?*n|LY+*dH)?6)Q1p3*+Y3`0CB4@QFZOp-aXxq`M z#0s2q)^?C6$?-CN7>fDX$@H~Cu0Cb0xJvL%Mc4r5?E;fF7=HBt#uotR!Jzy$(FpSx zgwq>m;E*t67^9>Q4d(-;s0#?8x!b5XaAf?o@ar-Vj+o>sB^EAm7JCgD4~^C$tHS^?+$ zi+iK&53dSfQoB#e{%GJl(@?gGe#-5Fol)>K@No$k@$X{D&8Y?bG9{WoJ%v|Fg+@Vd z#SrvP44e<;M3dh_$3upq2_S%TYE(QFb<17Qi1XFBX!wX2_*erTnxy3$w*?IWI(}OW zd?IkR48{cUVcuv7ni3rkDFdSiDCf|9GNUN?9#}L5XMjg5xqUJCOEsM9-%thHV?;O{ z1AiHKG{sNF;Qym~#<=}Y!iU|h_(aRuK}3j#PsOO#8F7pmxDhyy??(Iy$T9M3{qNBj zf)2#M-$Rud1wo%OEs6rhTLI^Jf-yl2%&>pCQ34jlP~0nqf=1wH17uXtTFPlRMHry5 z;9&1h5~x}87!Gx#cA5x3Hl6P3>do~d18EaX;iiGS)O4Ssvtw?z<3!#34&^#ILIvHJQjtrM8oOE-mscYy`$3v|wrNv@Q6SMT}u-tA6 z9*M3ft3ILfBq1|2Rn%>s%)~S_1}^TxS4DWS#1o{i-)D*y zZoK!j<9Z>X^huGm5|`%VC*H*uMZfrzC+YHILb0w;_x)6$B_U?`n_4ebbUyzyp*Xxz z#4DBZ70m~4i3|wJfRgW{mvU*Zn>EF;!u>K_=i4L|mpm_WToj=g8?#L_#EeE)oG+_a z&#CSgURtOrjuq~g;X0pdy2x=}hEQB!P+ZuXC*kPVz_qf?~=Zb>s1VOl(9Q4*;4eR$f0QOp@QdRiRthRk)a$Zr&#)m^z-Fo z|DdG(pNag4RYp~Q3a5&F#8}}05gt->#zj(bu}o0DL9t)by5je)7oBLLEXYIf*{~UL z?yk}B`+;Y0os^yxIdB1Br#FT20XJ!M?lhrjoJQeSFktH0@NJj4o&X!P@Q#HMPXXRA z3hrkd`fEhs0~6dlYE6$++y)qrB}IKif{W#%P)~4Ru&B!5X%TL0Vuk+{ZP72=z86CQ z>#xkQe=x5i&{)fbfE^lD6Y^WAr z(_fi@V48^Ve=BIlOwm}w*9e8Br$oYxRaw+iG{!>dmq_0~EF>bjhW&d11u{ZxL6LHl zSt4PIlxsZ1S%x+Qi=^a*40YTU0ofd2z~^F!;Mz0dcLL{yj}fme<-|JNc~Hs^O+#dM zth56@{bq$hjhAQomz?A%D%e7p`Vl8}1wv!m5O8zEXc`8kNgcY|pUAvN+onI^j7W^jCrWZfD zw&n^CMHEADZ@R!mA(hCfnk)WxlYp4q(4vkOQgSA`WvMGu=Fp>_|HrFW%hZPI3a;g zr2muj|B!zC(;|UM(odIuGwHXKe!hH~&{xtUr60dt#GfMRMba+-|CL6b|V zJ?Wp3{z!QYA#SG-Xpz3`M}Z!CAJkfw{;+4cY#H-e6uNUkt>HDV%I&Z4* zjq&*DAkP%SlD|aq1!TM;Nf(RoeoCIMKr$3ahI2AO-8eOHJR9JV;N2HRwq%d4dMQfr zYMj&5cWqnE77bl1ImEI##rpLoiBAT`j^EMJ7ybtl4``@(nFwdU&Kx0UqQnc3y{sts zbb*JI2j)f&U@Tml59AAcoD}pdd|n_c2K+z_d<$^y-9_Jua-V_k>~xFkKgc+ST~W<_ zOIPwEWlX02CHS>8fY$l-Yd?6iipIxVnCxE0hmQyF8&|r$i+4yAzP#6+AfJ>8+gtg> zIAO1-3jM*?PMMd1EC}u{%tyHpjrbv)&t&|(XyeoPEd1v0*I^^mj2ugM!XPZZ90jZ%~i@Z0jShrKf3 zIvFsYCN0IIzW=>fZJ6<@4ec?XIse55;u&w@6CzV`0IYn*D|Q0>5o4OU__=g(f~|7I z<=$=%+|*DE+@-69uwb(A^&-{>?vg{*m1XM#cX`9;?Ebr|v&WYgqujMANqq5xnA&My zL;3s_PJ`f=E*4X!(heeWNk`%5NxE>2;8!Fb{#Debh*i}r0(XjdvBC?NYvE`%k}>yI zA);I=Dv}BcBwZ?3%`S;6FA2rRwd7YRR<;YpvBHZUk>MI229Xk}xJW9>Hz?L|U9sOK z1n{0BJH3{|r9Cw|R(R=N5l`pqd>b;%gP2QJYfviAlL;x{4GMM=&&d=5{2ExLxcuEN z8WJnq-$j&^&R5Ke;kb%fzfxdO9C%3fJ&6ZoQ5$+UY zrWR#&o}+qu7V|H@&NJzqIHd4JyCm7eMsy zy@7M(W1~*2%3MoDTEj9)#WJn=k}i;CukRdb zJ6tis^JTcGlS%&Pgt&Ev{B4l5LyCV?(%PH{*ggaOPf6=5n9BT%Lo|hs#zK&&`p7di zmZFGIbE&;CSx?|tRQ^GkS8ctSUH+6Hb1ulN8>S6~5u;c}`%NvsD84~Te*cD2q@Qb}sV zdO3cNMLQf+xTAqM98~(O&=)of-*`Bv;7NhYo~0iS5@fc%=FNXgXbp&rSLVFyiqDJ4j3sgt#>_untKF!Md`ML=jUOb!2@U!B9aTXV z$k)WlP=Dm{>&WL_W^Aho4V9;|xjR_$BF?E<@*>|$hZm()*IyW!I+wiTD)k2=Pn!oK zn9aqtF}xSpLYz zfJIXx3cRF_oK_2werXhChKnM}l1Q>3l5|Co=A5S*h~z}Tmi$OEFOn>dB+DZWlY#U{ zFo#MdS-eoJ)5eI3)wZ;FLTkkNa8P0t{1ULP_~gqmGhi4PiVjE%03LR-7t$5G(=2A( ziWXhC?VWQ(zDVS8nPU?#G5Ucr~D%P(j8jnLQ0PIGzn{& zpGCwhL&RXq)>_2;UqwW}tWZ5((HRks4`s2_Em|N`#4D8w1BQ4mEuomiuQEg|@Q8?o zGGbVyv@)Uo^FpE55HDC;#4DEZatsP{ei89X( z#0$!JE`!3nABDm^L%i||QIami(-tx1289J-5z*Lei>0DM=_>|>!4+aCHjbMGI|QEp zgz)uu%ODTbx4eF`Iqw>=jbMBwWzixLLA2FLx}|M@v*?~TKmfbv@ac$8_eEiN?eVpRQqb1{l8-G88!H7E;M-iT^tF4A=2 zx6~|gi%=*0{?Fo|C^bm4$o_CyRfA&0Kn1 ziVhstMYDx77tF0J080+PVSt@huAzK6B5yO?iEH}SI*m)WdYvWB4=31NC24;6z;2qP z_1)g(l9ofb@}Q&}33lbMphMbWCC0v%45EkNS^No+09`=Q=WDg7E-4^QhU@mTk)-)b zIXmNNTt3XomND|$QAqqE8<%fnfcO!Up}-$8luUbrV&g_~FT~+Q&V5~E02|txD>P(a zDTmKMke-7(WCR}g*csmAUHOKn64^j<1)K6Ze6FTgRwBsOK{SxyYkEVl)T%@+C9mnN zMVr|~z8=^bkatvY3z%kog(VJdg9y!{XYvjvuW2kLZ$^kIis;@}+!E1Z;c_r_yM2Ev zGnR(hBqUK@D#=@f%Y$FzfLOqSahh*X6uvI*2xf<07n1YW3E#L#Dv{x$O=swfq>@FV zCyf=!)gE^^@V)-xH8l7Xa#A%*)-wM8iVW$B?prJpI7KFqhYwC*iJ_^y@lVl|^p^3S zr1iF5ZV3ND(sEU$e0;0WGhgT#u1vtX;R+Cj0EGu8j%397w|E#|c83t8p9W|kHhUWJrG?@sfcycJ_B=xNdFENLue(mn5wl5ATPX{E&97j5FOq z0NU|)rj15+6fkaE#bXxtf*Xwlsu+W4dozpSo3Tr%RT!Oul%#G3)Dl1=xcNWnqi!$(#2$#QqL!Y1Cn_c;nP!Dbw z<);hVF3VHjX_c}RBi}uzL_FR4A&r_d@?DmEy48ylY@r$g`%1;S`IOs*HTd!jFP_q$ zxfvDb8~F4AUGSk{=sDgjQ>dG*+A(r+o8&`_*PLELM#WbfN>JAm!3X`yJjtjRp+yRg zU<9^L^65Fy`Hg%9h8$aC$h!^lSig3rg?+uqjRK#QIo1ul?AtY}MI#vuadJ#63`owJlft${N4*r&T}#`K{R2d(5@((w_~tp zDt+S%dz9uPyi|r8fA8h~yM;lStVzNA7M+#*t8v_X64~t=1&{R`%>5zcnkfAGZ!?FC z3L<};x$5fp-~BeT@qM4up_CQ>&1L!VmG9mBpZ;)6tP_~7wRi#7&wE>S%m1z+(t%-Y zV`I$^X#cB>OZgFP<3~}XAC^ba0!J&Kesn9n_}|M2p7`%&6rBCc5u} z{QSR_Vd?tLe=8y(RC4ZrEJJHZ|LL#q6wVXPuvj$1s`nIE-a?6Fs2l{1w@~&zDMXYG zk)}l+ambUtehH;W($#)tM^k+k|Ks^gvN7Pe7Elu}tHP`O`i_3SPT!pRU;8nhkp5#l zbJhymc&(Of3=ObpY~_u(N8(2$e^B!CX)i9Kf-R!tjWhJhr)ZL2&IYv2Z;Sp+O>X-X z$fqZHON1ZCPouU%;$5th>vVzjrA6pd*dTfmy|K>7t;fW$ad6Ah= za$Xg!!}#(Sev-hml?!LYFzM7b?<-#e`IsCXcS-+6=^v8*G3lR>{`=DZRQeU)$-py-+k7pfL%q{ut4j1>jGW506ZIXKuv%>Ky zdhXVEfdcit$d8x55yc=|siD!9N51zghfjC06C12K5uq8yFNn}jrB1z>{ecKvqOI@2 z&A0YQVek*6FlSaXmZTJYB%V>}4Mq3Mzs}J2WDQ%4W^6I)LFVA71^V|;;Tu9EFimv9 zZqbH{<*BZmJ|a9%(mEcN^yYg+(az9fV=)8Yflu_cc#S1@Ncp?9xN(inwbBS5<68Uy z6qhv${_ofBSII>>BI;}Oh{by~Twl8z7yI*JDL6s;ZN(7k3?yF9to_GtX2a)oesET% zhUCTYgKtN#RsGGs9~BC@qN2n*OnIt)>Ry4*(xhXm+Z|uB@X7f=2#k0p1H9-~k&v(q z_XA^B*^Cy8aD!l_HF&tW8u7lsID?DsJNfGXS^1HThR$*umW4I)R^ z<2$=-;B07(IIoo1AV=WPuhfkZfuCw|=Z}a0It@6lc8oY*2aATk30|K28~INF3)M&w zKn`dXCBkpOqAB%78OX(}Xqa~DaPN;F4jhEovW(z$d^bM_o-r~(6x1$mX}!J z;Ri&x&KEo+=By=hPU`9_(o-O59arRBHZ(>S89Kh^M&Un4G2RBB28;(oBmOfmp70p) zi!pHCeaoog4`~k^Kr80RfJ*#fg!RDZZ#KOChx=WaA?Ux9{Ga~L%zwH;5xgjxgs32C zu%TbkHz=YqAl$e?5qL?6$e$+aHb>TRzN}+?gQ8s0#(jvhkQt8;;}hX)zh}?>aeVXu zrpNL>xH5dA;Z0Fxj2jm|Yy#QVV)aO~tmsDnd)J#R`sRfkH*kANj2o3Vg0&~-`rAc$P=JdNN)+ZS=R7j`qGB*|P$Mo>h72NcODK`J%eHP}xuL3OC+_@xOu$bH~t)Rk=ZN~ESmDOoPOGG1muy?X$_$4@&MI#^$$+B2q8KqGG+z#svBHa_t|ZAo z^T5SUZ(O>-Sm8#+VT0m848>A!NGZ7EZ*m+X+^BfQtD>m&9J~I#VkLYF>qYwuYWc01 zW5G}}+^D$Rpg3r#W4);Lk`8ngZ7!Gfa{D(Hbp%7TaHHbUuSMp#;BRuQ%o8P@&x+w# zuh#$cI*!J`j7G(!2E|2xqc~PcLa*rmu^5bsbB{;nxbSZjy8@!9zvEoM8B5v~kp17t zU{qXUP@MNSiowkS8MsWW?f40xyzu>HU!r{W6DzGG0(u_>kaJ zq{3oD220k7@O%*u^)Dlaw}^mZ88QF9=n6}uLcfexv`z5k$#{W#BjXj`Bj^GdFD(7? zBF1s9HY|(8PlC~ZZ{>qqbM;G_F1Z!2U(&qrhG>k%(uDhEzt5Ajen~T|+kWv)jTs)(xxO_6Tx(us+ zl?@xVRNuR=b;9K8!Ipx&2+}nvf(*!42O>%n%}tE8xm!bV60+Q@L#Y4gaq7BHg-~(EY$EF^`ei^vnA~ zB_Bp-FO<_BS%-oDL)@FdIawtC!w(Es7?l7b=x_u^bOsm*AcEo%zykp_hzN*aR8$m| zsH~!>iRYrD60dzwJmQVAtMQ%z)OfSv5p`9RU5&cCvdgYU*MnVkeZSRJoypVlgeQ;7 z@Bj8^GW~RQbyanB_4#!7BL>GoYzp5^UEAJ1OW9ZB@jyyUi%}AJIUlvAJ+B7P@~?8A zT%)|81mBc+nwXONM8dSnOKyvVv0$rQRR<@%o)YdT@#5KEE^O)=h&ir0ugV=S=5t!9 z1tc=3axn9gyDsz#&2sVP3(ck+S1SENGb9adQYw*tp=mL^t;}`C>aD%zmFF9gCt4Yd z4`IUyAq6>Iw9#Mhu1cdmCB_&TE*4~rgCcS}n-q~ge`vnvcns^Fw3cSV7h(N$AmBUP z!AmzWJd<0G9~GYo-vAixj=%9v#-EF4a%=Geopuyquj+$IXYx^+hr+RG#~ep}>ofYJ zOCNFhm=&Yo_|idDG|rpD+dkE&xayOk@3E-!7bk4x{Dl%huaVLlxaokHAFRm=eEhwf zD_VsicNern@1Fs;Yx*@0#aRu_zN+L@NCKxh6#gxeexVBSw~q$l*@P2)2yb=1kNKS? z_y@zEh~FCmKT+WHWh`11HsQknhnCw>gk2pfx&7Syn8_m@_`)a?ej(}@*@X!Y!Vn2= zZk~;Ik&CP3-kk$Q!gByeNgmcJ!8M4eb0KsE;QPD4KLC6f;Qe=8hSHsCH+8qw1wr~l zj%N}aju*-CIbsPD4{~>{VwIl2LF-AVhz_Zk@EZmG_un%9e8GPQK2=Nup0H@k8Py0Q z!upSU0&6+o)Nz~mG0-9S_aZn~YYb*5lSRm-L-0`m%4JWZtYJLz^f$cBPK*5Ho=262 z-M0Fe`)0h-01qoSlnGiWdUBdz>MA0L`NI&7H}6phUd-{a2^>EkmB29{2tCUP)=7+D zo|ntF;rRG0j-T0C@hb|DyGa?=xQLE@GWKFw?n=3>J9jczuLD>j2=ZqtqY+;0UzrEKL+rAfT#Mhz&fYe zPs)e1B6C=9?YHc1Vg6P-l;!>))DnRJ-1dM|bv5B3!08Q#34aIGo?e5R@GRh@OcOpR zfrx-h#B#vh7(@Yg6UY|0*{fv4HUbMSYl5kn`J9hYBZyYvZf!DbBparl*Ov7}>ZwOHUC5S>LzG z!M#%b&sKb5Jy@?XDbRA|5ElK*geU6EW61eQ_@pDYTHiR5?v2B2_00`c$&#a_rO&w% zcu)-{)Dh4w1B%0n!VWFZ`IhHIPR38!U9MHxS|@%^{0-vg#or`;LHsS^A1Y>hg!nVW zKSuoH#6L;=1?+dW;sTIY!^urFuz^!WQ+0NQFa)%_c3IoqE-b_ag*b(%Fvk%bu8aDQUR1*9bd@vt%$0b(>Eu)iQ(HvtG70O9 z-z{N1w|a`hZLJ;ci{nlGstU6Qshi-8Biwy-H8YQ=28U2SKDlvC&+Ag{)E@t;*f%X_ zr$gViJZDPak&@?B$#bFPIa%@?EqP9tJV#6D$4lV3lIMKMb5=d8N>P$BSbPq&Ek1T? zANdx>^~*m^xn>xqDZ$yL_FAn^UB8)Ww7Z89pRE!L;Z>3tu_UL=zI{qbfWy|kou8jf z1mzoBR~W}N_NU^2({^eW_k-QJdWRGi?z0qpnM+wGOIS~>&ojb}9G+A>VUrdF^g_zr zFJT!JTAA-SL*{493hhf<;uB(W$an8Y8Wowikb4!KGnuLh{{V2RyCys*@T-Qh9(4T% zo;~@E$BXvTM;N}9>ic~(~DS&bt&b!U;{CJF0I-YQ|O<&1=NlwC+frq+Kj7Fen#Q(Qca8=$tlB36y&m)orD2RX~+ePu-RPIO1u^zx3g1I zqa>cz0LV=?!pCvgzGIK({(=0Dr83pWuE zV$UF9-H_iQVO@h_e|0Wat(ABh(~)~!!g@USXAXDcTVH|jA3@m3zWDs6P`kEhAMB^^ zZR*|j$3gbsJ7Ehc3m|elYDpFx*)m2;`Z&EHr@zq1>Y}Eg!>j@=LmWDtmB>ol<<+^G zooR)gXR(nojYRs+gwAKH-udu7*^GB*Jy_>RSoi+65$?RBv(+<41A~ls?u0QX>LLuh zdSS0#_hk`C8_lN@)@E)t(_1K>rVzRt?=~6$Uar7!p{w&Q!*TlByB(k8*7HOWdk^?% z5Utq1xzx>z3{pn%JHDCRKEDHoB-H)&NwC40Rb#HSKDxCzO~SghNlI8(_Uk3ATbqo8 zb+NrAVcnQ~q{Ao)F?v>yF|(Wz16js(C^6X=w@IkRgesjG z#sNmlgs%mhtki_R3HV?aI1RRkyTIQ99HaXwtq9R~@Z1PJ5BR<=gw_F0Duh7x;8hsC zCnL?l_9?pTkVmCq=Z%If>QJMb>~*DcjCwt~2{tiUH!-?#&-QHqFE}1oIhSM-DIs=9 z6Bp4u#EAOG|!m2|EUm;^tDp9${(!S@8*Jmp2p<*nhUg6{&EirY*;xBHL=O!#ELs2?)n zCj&-3wz;%g2iv1o*<3zX%j)(&$2ZrMz4T=eR$q^DAxYm=p=QuzrI&q8xW}sRlvaeU z1_LUoayC`y$Ayy@+bZ3HK6@rAbhwW;IvR2hj)gcFxsz=)kHR3QZ8Y*KcRS_=^Vv_c zRq8j93z3eRY4e+YX~2g9ZsOmLG9-Kx{$v^WYJn%r1O*T|)P+z~UQw9%rYmEdw78IE|v50^x0Mq)dWwW#DJJ z62b>ekO2|Yo_rAAwd$iwPZ?!<0Lm~5Nlf^$fDwV^{n-|d#xuEb_|fp{&OA2^x@GaW zn<8QTY$PDE)S8&^a{xO6zisudfX@P;#i90)+@r|xNciR(_cszVZ z1j4fbCo8vBb2ZJ-Gn}rbde48kcyrHx?nkDOE^zg?{yBsPUAccS1HI|LAmNG6I_rB5 z%n!tGYli_yKy4H2@CPtQqPz$-N*A4DJ(D;hE|`7RIGrcuF*> zHABTsz1&j?BZ5k1Fhv;Eu@4yZ0etf_%-|S2lbZyAsGBq4Cjw6MyJ=a*KY@_p_Qa1G zB>e^^@k?L9^o{UfvsU~%@f*Y+A^vFb_Yr@b`1sU4$zy*xsky$`<5qae-Sd#UIZWF6 zp>x>b`m9Db*CJ$|ig&V29y%*Yl0s2%Uxix#b{q5PU?a zu!i4(P=EZ)1DGMnnF%jBC9LQWO>+8F?=91~2JN8wQ$*mf!5-WI3o=AZOmIHxRJnTHpy~CWLq*eqCE4ig0S=+~A~b zYK2V(`v`uQ7g*tkAWUv8ehv6J;V3LZqv4skndlUh++@Hndyxr^!!x<*fbR|8gf9Y| zDnq%-760upN^Zr(k9>_V6=UH(u4PHJtqFi;4u@Z4KXNDg(Rk1S+AdItMxBwR%a<7Y9T zARJQ{b2u*?v%)bh95YDx10^g7N1ZToB`1sv$Ea}33C9!?PCf<+Bf>FwD<=r2*iQ<_ zf+S2y!WOvwE@r+lL+o&plc$AmTKE=(Z}9fs_QpBQeMbmet*7|) zoGyPV`*C5L5k18q@8G$RH*3gS_%$cUNkU5)21VZZZ5$u7$IXGBLWZ7l7jbl2k{5(u zZ~?=U;HxYmWbjS?h7nSd(VWhx5X#-kHn>;BNSM2Z6GnBxO2V*kjEjP!EO5?99$F%N zrF=q?JSEA~;JfBnC@OE{GefCO8PPGY#ui}ImQB+a{&WOMnM-A93Y9ud+92w!8mE>_L zVe57#FNPd8k_WHj=z`=oEn){Hc@|=?IF9seCKQ7ViP&MCQ1TltE#F=vL`vPzWN%=$ zVM!g)+7fflgRQE!X`_5H*K)#`E+5HmL9`W;;$3PFpNo1B7pXPh%&$0kMv~_xd04U= zM)6WxyjR8$IJQ{$ioh8WI4S}c9HlfeE6H^s$8X`}5lJ2wzBx%ALVH2xJhGtGDD?7I zbHc3VD+!~L-xL(J{sagdHaKR_6ONM8q!3PNdlW@U!nLJ?RJh9qH5_!f{*bsRhASls zZRZR4K+YMPFPwI|ZR0sKuGSTBb-Qg=RW>wo4j`O;QH?r3#MacXRS}eoxTnF~G z*=j%c%Ggo?f)~&z8IJevMur{A!GWCGocJVXowwEa-~*ga<4x?xwjU9AY!b&u#801h zkfImma69Xr5O%XHz}iUWL|PSvQ-alJpJct67f#Ip29}(yy7{~u+R^^xm8O29!XL4m z(YZ9_#;d1mm|9-6Vt%m+f*2 zD}i1)ksB>xO~Cw?(Ge0)jRmty9F`(OY*$F9TBl278%3W%dd4xDz0Pr{iB z2rH?NfYhsf65mn*@yUxI_18WLFRy^Gl6oej9(20Df?QVt@v*;x)W`cIoUDMbl6nfH zzQrf;;1k}paqv0K182SMlW^W!YSj}p(4oDW8UIC{?0kkljn`Emd(FAf_;?{anma+y zUNTYvVbzg6j77}zd=j5o0rBd^kUHa&aJ&M-WG9J97pDSxzMZZ=Z;&w<574K)=wbih8^n~cuWJ`E4TPbZxdFfMek_gRp4_sS2c4 z4erh8n1A+3e5E&W*V@H%&6X)+tje+0x9B)vJP+CO7Ej5Qw7A=Uk0h~@JTpY0b$iHH$&?8eG*?mhElW(JD$6BRh#3xTm`h1Mjiz5{e2SOR4MU~LHt|~;^ttbSF?A!J-ZR=e%L2rs{+Dm zjQ1JdW_<3Gc-WgbS044Bx4zM%IjP3HfnN_{bgW#~xIksbVm5^BC4QcSVc5#GOv1a; z#N#>SrJtab8!q-5=bQ~r^v;Xw;1bg@e@uE1H;XssO=Tdl3X3 zfpTrmV@2us7R6kAN%M|JLG&gM(dUn6z0hkKaw%`o)mU`S#~|KG*q2kfNqn(4aV129 zeVpCYQ{B=U$h|s6!Q`c!J|U^s7s#K3@{f3kVir-MQc;+>+Qx}Td*Rv5+t26(hKqeN zTVv|qe8!90F14$h^f9q|xssB!^y<0#fbzd~EXZR!@ zs(|?B>mc=gJ_$!FAgr3#?vVN;pTx&_6IaG)wi@OX`W#H5t8Ty)dZ#7+%4E5>0QQ0# zpti$&5}scHVbxLJkB00DpTv`u5Wf*ip3ey3N|)6$-h?YE5BWf3qE$cm^95W!x*P0t zA%}JAj-^h;KzDoHBwlYk*j2*2DlFXdE#dwWK1IU(njf2_FEI$*DB)g`;I|UyC2!mZ zE#a;b|Bi&aNcd9;cb9O^=*Pd6c-6Vs2cFT~WyUn@Kwl^ME>{puhj5>ycd2agE(l&7 zJqyJDBRtCyHyfh7H*u9av(}k|8Wbk?)s>cJQ8{YaIB^nWAAS)RcsbcuPIh+I>wcl^ zW{dGM9rK|=HZvuw^~J^dr$xZ_YQ;BkBV@k9L*}JZSZ2Li9$e$u@Vn|eDO;+vQJ{f^ zMZ;xf50DFjijS7roN@(XsV14qxE!z^F7Om!WXLV}q%pX=@RJC;=4LcB&wHrEG{L%G zsFD^*lpNM?F&KjN?QK2!{Z$GwfZ>)t$7RCxIj$nyzWC&(-2r-7OTuyaaiQRwVY}E^6eM-xO>r+}LT%Xc1;rfu) zy4M;NWxcQJ8QAOyKm?vp2TTYfg$QbNUrum+)jPX-QY2it3%k3$&J3n9n)NUE6Yw+P zbP3X+R&ba*-Hl3n)aD7HBk)Y_82kp~XTs@(OPvdRZ5ezrWj8v%1AG`&HBQvFqe z^b<@VRL?%;mYil3yK9ub2>Za8Ftf_-g8a>SocQ0od(-5VfBzuaO&G|enVno+9h3ct z92}ln$+4H#HY$QgFOgd$`9&+Hf@rjbsC)YDiAkhUBCfDx5xq{gn8*$uo2<8Jqfv z73i)v?B@+o`ACf*sZL_XQT|UNcyd4(_ z$M1HuThS+VkVsdht^gYDo~{aJM%kMQKPMZ!nQVRf5hh!%Sr0AQPvu#phzhy{Gar=h ziVx&=b6~FI1p`=H7PZO2^2nbaE@N7W7R=|kYl%g zRj7HY`cPI?=ul`O-PC77_D)t)OtzVu-?vF>H8wEbOqRT*+C4Bzji6%Ja~5yCoW~7q z1@CqV>t(!xapmj160hf3zrB>x?~2KY{KUPKF|ezY8m`~fYY$dq|+Pi>CQBDFmJ3`2V|PSnF&TBK?C5s zEOn0cOuT)8x4ldHW6@Bz76g6G?TDD@lHgZ>yXEu}S3;KcTQEM%h0gB)r}4yFVl18U ztQ;L@puP_Dl*1QIsp8)%J_!S7@BVP_uI*#jz@F`=AHs(joQG?okFzQN?FQ!3g;QBuB)o%! zJKV_e)c=#~B4O;dQLaY9bgGTqC<*uDpmn5#b*-PzVfv28CkvbU1v0btVoYxHBWUv{ zXIJ+Lgm-no(HH2xzN&C_%X7ZuIa~6aX?bp+yP9->`@w4x`U82^$K2Q?^X!`+!n*_& zaXREO;aP!)-r#1UP8!4FP~}8kPU-R+)|ze`MH%*&uQYW{=<`6SH#v);b2yREQmgiV zfc~3qVj@(L$^AvbgE(lVj(xz4>p^1wmTn${fgmt|Dw1M@x7d0JDt8~>H z%;*#awX7T96C+b#{kgZ$ZCo@Nu~1DXbqd47&$Ay=EeVZ>9i`xrK>Tz;EB?G~P`(AZeJ!_ZJX>XSvt+n(*gk3;s4eG;DU zO_;UI=P3?Et=#T*f9e_I&BCsE0CVkI9I7v z+jlNRjqHX-DC?6&lQ#?d2a^4tJ_%cEecAiTkbRds{MpQ=3S{5>6l6cxC*g3#vXkED z91GbO`DD?nVix@$U$cAnP>MUp!j0S)!q?-z3CU#~ml<#P?{PRNZJzE=iOWUB8Z+3-X&o@0)HUA%%0u1cIP>7Lh6Mc zQcsNY$Qt&pT)tANRiBo46fA!0!NMG)t*exUp%`k)a2DvRLVz zA$!d;sATW^BwX+&%$l;5>?z3J?k<0Yk@aR_uX+};5BEuUu{Yro*%QY>_PIV;q$*{h z7?mI3;_herg)H_HZSpC=7;oFM2R}!x>)rlJCFD)GM0qp5#{6}>PZm*c7Iw|^kbR*~ z!bxw!C9)?zgY38ZWHG-|79ItU7yI_e7f|r+@9|eY%e@7#SFLLvkU$qR#V75IH*MCR zN9G2BcY@xJo6Y_n&^UEOar;G z+6t+Qpv?%n>AMROQUP{<1xpog`;@TGTf0g!ZAs-M+y`S5ER^!9(;7%J>t~;m%&b%r zHlLJ>ais ztx8!aM&&Eqg*dA4uQ!`}B-Z&9V8b>NKt2qRXf@iSx91^9Z}#OG!0Dy83BSK>aj{?J zS$DUq&2|g$T_uABYki1S$U)<>A!^lu$u{R}u+rjfu3V8XML3w(#Iz;|=O?*{yxX>*Cmpl2CE1a~7;qX@O8 zqbE-${Q;%;WX)Pd`<7uaX)ADgL2oiR9Qd?z&xFr#q0Q6!i+%IsC#yx>PEK+`$1cly z?4VNwG8OY`5p@WBk(JyR7QxR*WqVXQ5uW# zhXz8|{E6tCW5ZK*OiY$gHv%;fTvJ*sRhbKT*J~hiw1#6A)iaQE?57Gu>z&&hkKL0c zQnsB)Nm2j*xkW7y-b0H>8K{rE&H0H5IKl#3y2H%Bs?pUp*vP%pOL7z_+!&Q0)#a-A z+k3fPb$y6#0b*w|G4tZ;2JLZ)^r4Gzrr z<6v%%JN3vrWEHewtt$QdvGUH+xaheG7d`XU(5bhy0gytf_2tx&53jK=-nF(*;FUE} zE7fh(HG211GO>@+RO)?B{y_>Cw113|``_0x{wPs=zo$7&hl4N?B}?mt$LDVGqtj_KZ)$brs95HXcME`(J#r2zs-yYd(SO z4bS+~`%G`bs(c3VW|hM*iaOpWi?}xnyZTeeZu=x0e!fzhp{1cYS;+pHPZmqPWiL_B zoEy+-wRzTG38X7#p*E6T0v3DvWRde`VQ>BnC9uFJ;a zyFLkT@>WVo(av}YvUkq9z5MPyetL+@!8`D8KCn}xmRuaNx# zpM+O>6E2l~0c8KkCySUj3wzb)kiGkJ{t7hfO}Iq%IX^-6i9T6u@Wxlb0M7yPvT37Y@+e%@bkcdC?yD)g4MzT7c9B%3I3bodeV znE9B8NkhXt2^%B`Ujl>X9p?@K3ndw>GUf>)ZD1^*m)fgiOCjJab zKi*|Czn*u{5N#%Y_X%#LyrY%!7TIMe*xC9@81=Q^`nI{}v@S1l9xLTL-bS20GtfBI6WX_xPdS8M!CeB zKv*x-hjN_tZwc#l*`~XAE`S9bMTBsza=Mbh4OI}_UQ3$lKNbY(` zsKXB!;jDyf7~R^4Tx|XVs=%~ zTEbf5BP85c-K;X_D5&&5B6~UQ*WJUi>vfNeVMAtKi`rM)s1sAbA}(AjWwEYO7Lv@!$o@rajN(Hblz7m(2 zqX`=>97eHHEOQ~yERKj#xlR0*g+n#dprhv}`D8KE7mFFEqbEJ|HP%z5xrlqSus3hP znDr8$gqL~~R*KdmN^Py}U*`}}uh zXL^<|^(4B2#b}=_a+T&n<)vjnZ`xRGTgzVcBbuSVi2!o7iDx4bt~ifsz3ktp1%2LR zHCD=Eu{R65@h6zTRG)-n-h{;jNcO}Nko|I>EGAaU!lQit+XkBm|BFq8ANdp@0+ z{WFwT^OnC-S?Nuulge(4^Y#*TPH zpH1wek01t;f+V-GMK*969$$~t*Q$N=HmgnFpYhwcn%}Eyw20?b7=zF#3~+n)VNYYn zMw`{aK=jE&l|W3aD)qq(z9K2~hp~J`QsMPdZUJNagz?tc*m{w7ZoLTAIY@;Y9Kp!g zgGwX`WE_G8TDD%O%YD*&9i(2@)<=KOM8fB?4-G4)CrZITI+*AU2r@Tu-og~nw=jvK zGktVgwcR7~h9j7g*P@zK!m)D%w=9+BCO=rGRqvvM#f>B?80uddTa_C$mTzc^G@=l2 zL(?I#ml+{5fqnCaru;^RM^0m(mh#AHZDe0#IA^RXx^b-I!lt3`vgzo>nXrWQsMWl% zX|%-aT?~^XtWD2(VbfT>OXcA&*dh;S;jGtD6G!7YJVvCJX^)mVx}>EJnw2fH2_i+CAjqlGtV+GcwWocEGQeAA3erk2N+S9m_xNwV?`$%yPp(mf^bV5G zBwla#`BuVuZE?E|oW5G6!sbQ^>v}L)!nz&_n*HU%rmlh9?v6}nhdP4EVUD2lda*#+ zpenia$kMdcv8z~rwC7|+@8&*sWV_YDT75%VL>kVJRDNAYvY)XUak*S6wL?NeEp#4( zd!Z7O)9Io~*)4K`#B+2pK6rlV9eN4uPErU<`*PcGlAzNrSZZEO_>+LsjNXLj0qgGq zKL+?zd?x<8fOVyvzh=Y-h#=-a%)3s?am zNI*_2s30v_ei6shHDRUkvG*9xwt7NJ`jy}n?)prf$NEf9;`o)cgb%0LMP$=Y`Z)LW z=_UK&hRxM|J2^L3#l?m)GdP(hr+w=chD%qO`b-B^dzX28tX(}A>r|0G#xDwju9_Pp3>#4HZxYrU z^`mQw###T2M$`@B&;(uLZ$D=d&mi=uOMgvMo`#pbNTA-b}EiV)SRQz z9-=p*#^$kNL&8VvKXdC01<9Sj@pVRg%CY$^5tPA|sprgx&KA$i=IT$JdN;HElEm*U z>`k>vuJ^Naw#|Yv%SEXL#B`JU5iwvj(OPqT^kQx=!ez`kbAh9I$w|MIoy=-V%aEn0 zM%hES2fu_VzJnR~Dd$^@y_XSAf9%xTp%Sn4a1w_TRu@ssuLMCG==DbUVF~No@q*HP z#w5M&l9D;DQ1SgaLj^HN9Us1co8OS?EU{HQA_R1flhUn6#c*21OY?M<*z1krhvgE^ zuVtFCS~d%6KQ0lqZ z@s`A=LL9$NQ7h>W{=jfiW5yw8ef%=6Ua8)U6~RgnIn6y@Oif#GYg2z=C1?K2zB$ki zeY0Q7EVhm6YqM+IrB}HQ_r;4ZCg28z7k$9a&_QOr+kP^R0*h@4ud(C zOdXI^^C^6Nb+CMyGc`f0&0r;l}g2L8~+Lx(>++2#3Iw@D;6JYQ) z;A33D6&WlE<)(bXJ3F+xVOmV)eoq-6wm1Mej6!e|ek@?r#xL*B89f@$7RE%|AV`0~Mh^`7tx4bx;x{%xY%x>)KQG{-d(#6pPFY3wZ zFxFRfQiK>?*Jv;J3~DhJ{q!oIpzFhLSY@==3|QSTRxb)Z^{g|u5wO&mvK04La)PE zKXUHoL2`1m;6b@F;Y$GT=K@axrfRT3XDQ$`3Nq zV|*nq=wAN?hxKfJqTuU=yTc`1EixR<;X#~X06m3Q!`4G`@@0l{y2yW1p)Q!5UK=V$ zF8!@Pa#H`wk&FGy54l82UUFn*E@3W&B`;!f*v zm9Ifoeg#jJf;+eqz|t3&r+w!vH0L>~ZyBMd`Dnl8C?B={hr|UvEECO$*oL;-uw*aZ zk-2Cx+Ba6vg70c!hd&&jFAbiMmdgLK%y3>4|84Ov|DH8$?H{51T3H#t z>I?+C?XTeH&fpe*t_ty2HfUK3aC`Hl=7w55yXk%{Bc3dXG#90=0dRZrkkt)=(5}3Q z#42g8PMfOJq_wG$<5Z%2zlid+4B8JJwZHpm(*#bNsuZy^qe&lEfSdX8X;3&XGxWK0YM&n%*KMWW#7lz+=g z_PLNeD<=_Y@l68f0*7*B4!jSBW=I1jehM&ZUp^E;j=(dyf1|1+3BgI$mir>M!?bw< zM>ybp0H>A|3G5e!t!@|`6MGN+d4Gi%RR3Gnz0|ky0Be}nXxD^Mb<#I5qKw8ezhH9%lZP13#s@XfolOy0<6IW{uN*}dNT3B5)5hN}oYn6ar?76|W z1H7XP{+)pBi(k8wof)8pjEpt<5()zRtxOmEgVQ-rJ`z#k>@49N)|6PtyBEGB@Fu0Z!G?gm(}+sj(3v zQydWM3`V=NfcZHQYNuL%g))2I0SeAGTC2C;98mAHxgpRzb*kWRj~xlyZkgs%HJM?*68a|k&H4N~Pfd8f=)z_9+IVRrTz@rk3%jdxU*q-sf6uu{9Eqj zl3A#*`Sl649)R1c`e8Es$0Vo)>|0DxkOlpLV{UH@Q^UjZQqfAQ9a1i zvNovOAXn@)CX1FN{&5jR+udZ~4#1D$sCqhL5`Z!Mx_`!!>k64cPWNOBPRY_ z(SQjj#yw4Z`-$<*-R&;Lh&Lrv#j_LiAhqqo7vS+X)0+aF9=$+G%QzF_Vq~FXM5l(X3(Kg~ zVVo~;e2^0tRh_i%!2#pBFmB>LPShP9 zz^OS{yzT1`UD+(8;jtzSWP8>Xo^GNevoqmGK-X^YTLu4ytC`O6DkGLPANW)}(vl^t z6C~mRBp};1o46Xlr@O!p0u|~DO#It`A98`O0G#Sp{^RlZuX|z?Sh2$G#|?f;{H*u| zY0C22cMxbvpA`Ibg>-UXp<^L~v4n8uA1qmvU~pQn*b959a9a0FFLO9oE51j1>siKg zqoeqngyw$@$>0i;s6gRz{;9z? zBfPGZJF^Wln1!_D9t8s$t(b6{=27=(!k57osI5G+O~Og&CPYvTz$c6Gzhw@h@2p!Z z!$BHhlcSm0DEyWQzV5BYgE1AR37-Y{p@4^;<)Y3g{R2=e>v}fAA_C&b>G=GoJQauu zUi2F-s?5_|RF;fRQZgDzJxKaRQA&8T2&$)li7yaIU4a>~t_=LcGVtAyGollbrn7)B zIW2hVv2iL~5dY5Im4*}60tMz#Bu(vO8(B3WfolR$`+Nlnp2Op_n1qw!hcvuQ`iS5; z>C}Q@8A9{FWz}*g6NqF*!>Tb32OFk-dZmxqap1j3Am(3T-d@L^6+kc43)VeC0h7&RCM@8EPfNf$EGg`Veh<`^k>Kczzz z$w9Ue;sgbVG#Ob1vE=K97ifYyT^KLbrv0@)xLmIU1 z=+3=nM*L^Re?$Dd_+N?tllXB--(g2i-&On?@$1AN0bex{`wL*Q_{WHUhWHnVf4%s( zi~p?%{D6cX75{1R*NOkG_@9XXPw{`c`&w?Ieip#?Jy_zM#jg{8toR3sKUMs>;-4b^ z+2Su2KR*8;rAeBElGD{a*>NTVEPKGiy?3gQ$t{_=IOB&TR^z9>VmMc#TD|phyv)XE zt%lrP7>Esk54c^^4`+13Yp3d|UsbN&MtJ zV|~ryrEliet4hd`0d~hwJt@gX3;Zbw?;+vH58N1u!CEurO@CD2CjMql-_{z!A6|TZ z2TXhVv1pa@h;Ny18P`A<)m=K3OzX%z_T%&6x%kANpjG ztC)qlO>jT3=o<1@0!zJF*eeb}2~6}!IPFciqy%Q157`qwSy=0yP$afup?2dW$o`~H z!V|p-i|p!*=u*i3PoFFnd$X{YOor^c_V-tyy}SvF?AI-A?tK(QpY4-F%$tL~V9M%& ziR*n54to=3(ba#Rp0H={;{8&zC9!^PRI9>N| zuTmsw2t@Auwwx|~9H(2#;9`#weU8&{3%xI|R1?lg1Go^;L@KvP!ZfWVcZGzh*(bMb zK+0Z!=;}VReijwd41nAof;fVMR$bdi)f450T*^?PiGQo4AJnqTF`(ZA>Y=0KB9=s6 zwjr6ixDzaiYxV@z#U{nSrFSjl+;w=gq{~aXbw;}6A4_$Jp$V<_lS|j|z(`8h8dA$T zg#{}&)(B6Mu; zucJ9A98YCpVnhy zPonjF|*3VW?LulvpL+`8Y}>_u!gj| z)?RP~b_U-rDa)0>mJVD3Y-N_U;TM*GDS%uPc7&yiw$pB$g>EA8N~0R>BJtG{KTyJY z_*f_509)5{Xgc5V$Xlu-=S|n#(C?p6#C1Piwowuh%GCtqt%E{o$Flql&FOFvubiG2 zcXH~vu$LC|K<4 zlSQy%7HaI@02XKYWHGa17AhC}gT?(GEX=x4S1}89oydM*@kgI5)>T^EQj4}y^|=$& z)$O17T%O+<$4i@$G{@RBv-np=s%*Om> zt_NYWbo1VXSv`iao1>`bFw)!AvgTQ4=e|w^(j6;C8;X>+V6P#vImAVurB1vg^633< z@W^d8=;-c$27A*ZM=QHJbF_3DIDa`q*3#r(I91R7O>J zbK+oefln6U%30V=J=KSxh9~6=n3?0^pk65$d)S7s20HTb#V4^|(_KL2G+^~)4d_9B ztWxoWWw{a2hN^2r3Psyiy^Mf#6GFB$_5{@2!#yNiDH3WzDQ^kwRVSe4UgneVVsFAK zN3u9Y7ded0mnoTINr;-dH*m>duA>~~zHuHpfsZ_d+|rB7N9TTJr9uj$a^)ieZdYu1 zb={uxHmoKj;+C_T%+5}$$yO>AH+nyz`Izp(!ff<5RLa80xY>O4Zi9V+w1{R_regCU z1P&g`MW%=FN9nMdLC?4Wn(Zzi{f^39IoPy|v+z2-=Gkr9n@?IjaN3C;gw1xV;H@0K z((z`WghSpED|MCBi9k$t+VXl?t=@-g7Q{JF;3Op0TggUd&uvt+CQ1P;hRyfGvzf3P znvjDSZm*b+f$-^JE~#?XYHDjtrI`{z%GDtm-%cqmvUm+}%{AWlMR2{YjsdXUcnVsD zyF7BVt`8fQ9yUd{QI2{HSDI{VwdWqBGZ^GOWXbepS#-lbf7{6tR0W_15U8N``ct8u zU06!B?}#wWYB#Z;vvo>tJBf&0LcLg^r~h@rQ-M7Y8`WHq&nmW`$v1aQpkxmB&_hA= zpv^0@4fQaLLFt+;uiasry=!a9#U@!ap@I_S1L94E%U&l*@J~?vdb%FL79dt z*C3$!gcL$i_SQ3Ed;RG!;V(QS95aBGpu7G2FO<-1JDno%ITKTWK_j<5GB61*_a@A$;V;U3fZBAdu&C7jla;bij9S_nvnJ1| z!ajRy+0Ak6IuWRw5cqIp%KqUj)YKb1l(Bes*0P=oZrMg{&R%E@aTw%?Rs*>)h?we< z19P%8VGk}v+R{nx7zy{_Z{yTK;4T6xR|?TO&YNyegRgI!R%rC7R7A<7TNM}WJK_%* z#d*=Cll}Y}d(9%0PL)KI%R#4l&VjB2b-yqNrX4MY_8?56Rq0%e2zB1b*kv-e4E#jE z$sSDx4?*WcUEq%b-a;RHEOm?jJR<1ukV)t{z{y-pIDLzwg-{EfQvfG5oA_r7zGK^s zJ^h^3HHq(}5Gvgu7%>W=%qB$jwRcET95^)W$yP9cfN)S9Is40VRtFOEC9+Z>3cpYY zNB+V6K-h3CggE!y)m;;-eG1XZXx1v#gegP=OlUmaXlq8ig~2bGmkFnf+T7s3f==rh z-=4M@bLtOAv(Cv>$e9wF3%Mch9NFtZI1wDVJ#Tm^ptF@i@cLj#Ofw zeI6uv#-}8Uw~^(nf+Q$|M61Gij3ZjX*9d%<9e864Rcmq!q%e~w(FDKsS>WIm47V<4 zzvP1hz_#bkY#wxA<}!}U&SgKSD7EbT3T~(%UR}6dAAh+5R3fjo5he6j*3H8_IOX$; z4*3jh%L^h$OAa2#SeOn%m~gtY0f&6%wTfs)L|2yt+o5jk?E>E(a5^nyGUx_4(ZQi0 zd-Lf{eeB$B&A97Vw8Oct#%VjCl-{=Wq!g>t&NO}I0~cW_JiWX9GH8b?a7y4aR4n$F z!*_#UFYrycP;2akt8wv}+`(DyMEE`Rjdmjt%ilMy?l~!Yjn)6t*lAjfO;R?f?F1d!c@Up222KPUbM z@$=$u62Bn+7V&?X02s7r0ru;{Eg2t9Lm!5gjK+kI3Y;4fjMhl+6Dg-z>h*V z*^1C?H$_aUr(4WI*6)@y)aTbk>+MKAO`-XbeL`G0o8W zz&+t6N%)quWM`;!mh~olY6BM@$RmE^h+8y3)d83JNPC55Njb8p&++@|08U0jFLI-W z%oq+@k$oOjPhx@KCyNvUH}TKm^lhy$FGuZ<)b|NZKJf0%qgQ1-tgy(aWqa?Ns}zJ9 zc5*nmn!v?jt?R=l7&{Jifz#Sq)CImbbU)7pJ_~Sa*vZP`s{g^VU#>ks&mP3aHbP>*lCUnw?0#%) z$hC5roYUA${9O-bdUb-Y4Z)OpL(R4J4_9G9YlQSQZZ z=6y}eAk=viw_doRaV)2B!;G4zkQH|SKC||zVeFP}nGKoue zB#UU7wIDjdS+XlD)lQ3L)`Vo!k}2t-lT-GJWjNMXGkNRgRd;~1>Sp~5F;=VH6v9;3 z25IFwi$aQx+#x83yF3KVi=et5towzHoM{7?T!&nZqYau<>2&PD*TLHR9=df^ntlF; zN>wT9DAx=>$$Wp(dQZYK2D3gp6t9V{L*ZZMA@R(ExbStyQK(en77Glt zoUo(Cl|yi(PG!eb^9=M2JrHBsh}jc9bQmjHKHETJtqTM+LiA+Tqs0evE?`8;jroO^ z;Ud~@ieR~3+9~UtFM#~GhpeHAEUUKSP^GfkZ5FNVm-wqs@|`Lr&zdW~)NoM+VT`xR zsbbRMTx{ATXGwTFA?#FDg6_)gB`D>JHF^lEO0$e^yS&gM8$RSBvK2dJ37;WK-a*1n z+2?El_(Tuc>n5@6x?;_*RQ8s`(j#-PPEi7wHR&TjsWUUn2+f4O;x`zr?KpMo?Nr@l z7EX`WmRBmA5~t-QhABYd^J@sBtrg^#xqn0x{AepI;`y zS|o52XdYTcT7xh(cN*X{zB1wWgN_^i-EG0&En-a>27f@Ax#6EwhCu`116>5_3;0BW zCyWMSaT&(@mtoK!_%vcOb39b&Sn@e{S&FwF0WPhmX?Q|MtT7@qoLVw!5&zPQUou4T zOpe|{G{E0;XNFHzP;4Lve6S1r3c&Vm4Nq7X0XVL8g!NCr+z180fcgNFaW&w(mx0qV zp@~ly8ShSO<8Bdd33?zw#D&mGz}y6V7;rZYy##nM17!bNb+6#rEe8ZY1V2;Ib$}i0 z0)GuKH#!72>8Semx)7T8dLy1%?x3XQKgyX2r*fof`IO+(I|OoJ{QBZoW+lLiKgufv zu}9d)Zh}sf&N|(~8{>|2H`Lz?8;4~;Q;cs9#(aVIBwSSC=9pOK{ zHy1$+&*ZMfk5pamB3AQ-GZh&Lx>Op#MR+Fn4B%9~O?VFQ1TiopK0*Y+&6``jZgfqZ z!d9I@T5{T|^+l~N@sxkOe==@#4bSAMhQ7HqCpWkz#nT1S|L$l;GUaIrdBsugA9+#d|P$NtAs^8gP!yIZ4LkEruZLElZX? zE??6#5c|?e%6X@2ws;#i?)2yx2s=nsVSf)xch7W{DdFJ!;9Ir++#P-2Zex4gu^ze~ z9|K5zSIRe$624|7s_npCSavbj6XSBkSRImB@vN@Q&X^L2s_X5@0o6T61j1JVP7S^Ze+}?mT;Q(*-p2+06yRh|CLOwi zuOrzHBJ3X?z}F?UCC336`C!SmmQ7Ew%rRh-qdT}q!8hS+0Vk_9;co&y*ac24Hi>59 zzXkXZvJNwXW(RJBo(G)fNhba}z{xsHIPEW_0bJpoDfo|e&-m0u@DBt>>Et!SU6U1J zq>O*WE?2Agnd-k~oeVP@kLRv6PWat`kr|&VaNYS*VUSrm;A9;;BVuRxU!KK9pc{zY z0Vne_;UfXx-UUvZqo`<1{2u`$vtN8Y(?1T+thq zv`y`rhjwzDzz(F1>kXZkA139y!Q97Hr3cApdId~0-)WDJ=cbFdBGNmXs&t)v>BIpJ z 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�yWK+fk9fy3)eKsAFw(2Z~b^?XLC-U6! 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

&y%qEqQ-DXocPb$seU&($Dykg_vcFM) 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 z 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

UYPM&kgv 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

e2KmDL5eeC55$I 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 diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/delete.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/delete.rs index 946f033..973a453 100755 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/delete.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/delete.rs @@ -89,8 +89,8 @@ async fn apply_delete_client_kv_meta_cache_item( let client_api = view.client_kv_api(); let client_inner = client_api.inner(); - let cached_info = { - let controls = client_inner.owner_key_control.lock(); + let (cached_info, pending_get) = { + let controls = client_inner.owner_key_control.lock_key(&delete_item.key); if controls .get(&delete_item.key) .is_some_and(|state| state.reclaim.is_some()) @@ -133,8 +133,19 @@ async fn apply_delete_client_kv_meta_cache_item( snapshot.put_time_ms <= delete_item.put_time_ms } }); - cached_info + let pending_get = client_inner + .pending_local_get_info + .remove_if(&delete_item.key, |_, pending| { + if pending.put_id.0 == delete_item.put_time_ms { + pending.put_id.1 <= delete_item.put_version + } else { + pending.put_id.0 <= delete_item.put_time_ms + } + }) + .map(|(_, pending)| pending); + (cached_info, pending_get) }; + drop(pending_get); if let Some(cached_info) = cached_info { client_inner.owner_hot_invalidate_version( &delete_item.key, diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs index 28ba872..42fe4e7 100755 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs @@ -1,4 +1,5 @@ use crate::client_kv_api::ClientKvApi; +use crate::client_kv_api::get::{StartedGetRevokeCleanup, finish_started_get_revoke_cleanup}; use crate::client_kv_api::msg_pack::{ ExternalBatchGetCancelPlan, ExternalBatchGetCancelReq, ExternalBatchGetCancelResp, ExternalBatchGetItemResp, ExternalBatchGetReq, ExternalBatchGetResp, ExternalBatchGetStartReq, @@ -14,10 +15,11 @@ use crate::client_kv_api::msg_pack::{ ExternalPutTransferEndReq, ExternalPutTransferEndResp, TestPutPhaseTrace, }; use crate::client_kv_api::{ - self, ExternalGetStartDedupKey, ExternalGetStartEntry, ExternalGetStartOwnerItem, - ExternalGetStartPrefixResult, ExternalGetStartSharedItemResult, ExternalGetStartSharedOp, - ExternalGetStartSharedPhase, ExternalGetStartTransferOutput, ExternalPendingPutCtx, - ReplicaTaskTarget, + self, ExternalGetKeyInterest, ExternalGetKeySharedOp, ExternalGetKeySharedPhase, + ExternalGetStartEntry, ExternalGetStartOwnerItem, ExternalGetStartPrefixResult, + ExternalGetStartSharedItemResult, ExternalGetStartTransferOutput, ExternalPendingPutCtx, + OwnerLocalPublishItem, OwnerLocalPublishJob, OwnerLocalReserveSlotLease, + OwnerLocalReserveSlotRef, ReplicaTaskTarget, }; use crate::client_seg_pool::{ResolveSideTransferLaneReq, parse_side_transfer_worker_lane_idx}; use crate::cluster_manager::NodeIDString; @@ -26,7 +28,8 @@ use crate::cluster_manager::{ }; use crate::master_kv_router::msg_pack::{ BatchGetStartItemResp, BatchGetStartResp, BatchPutDoneItemReq, BatchPutRevokeItemReq, - BatchPutStartItemReq, PutDoneCommittedSlot, build_put_atomic_group_assignments, + BatchPutStartItemReq, GetPreparedLocalReserveTarget, PutAtomicGroup, PutDoneCommittedSlot, + build_put_atomic_group_assignments, }; use crate::memholder::MemholderManagerTrait; use crate::memholder::NodeHolderKey; @@ -36,7 +39,8 @@ use crate::rpcresp_kvresult_convert::FromError; use crate::rpcresp_kvresult_convert::ToResult; use crate::rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, KvResult, OK, codes_api}; use async_trait::async_trait; -use dashmap::mapref::entry::Entry; +use futures::StreamExt; +use std::collections::HashMap; use std::sync::Arc; use std::sync::atomic::Ordering; use std::time::Duration; @@ -49,7 +53,181 @@ fn duration_to_i64_us(duration: std::time::Duration) -> i64 { const SIDE_TRANSFER_OWNER_RPC_TIMEOUT_SECS: u64 = 30; const SIDE_TRANSFER_TARGET_RESOLVE_TIMEOUT_SECS: u64 = 10; -const GET_TARGET_NO_SPACE_RESERVE_SHRINK_RETRY_LIMIT: usize = 8; +// A handle can legitimately wait behind one full SGLang request-timeout +// window before layerwise restore consumes it. Keep a bounded crash cleanup +// lease, but do not expire a live plan earlier than the supported 300-second +// request window used by the aligned agent workload. +const EXTERNAL_GET_START_HANDLE_TTL: Duration = Duration::from_secs(360); +const EXTERNAL_GET_START_HANDLE_SWEEP_INTERVAL: Duration = Duration::from_secs(5); +// A BatchGetStart transport error has an unknown commit point: the master may +// already hold the prepared target even though the owner never received its +// get_id. Keep such slots out of reuse until the master's 60-second inflight +// Get TTL has elapsed, with a small scheduling margin. +const PREPARED_GET_START_UNCERTAIN_QUARANTINE: Duration = Duration::from_secs(65); +// PutStart has the same unknown-commit-point problem as GetStart. Keep the +// owner reclaim fence alive beyond the master's 60-second inflight Put TTL if +// the caller future is cancelled or the RPC returns a transport error. +const EXTERNAL_PUT_START_UNCERTAIN_QUARANTINE: Duration = Duration::from_secs(65); +// Keep control-plane batching, but bound the failure domain of one uncertain +// BatchGetDone. Atomic groups are never split merely to satisfy this soft cap. +const EXTERNAL_GET_FINISH_TARGET_KEYS_PER_BATCH: usize = 128; +const EXTERNAL_GET_FINISH_BATCH_CONCURRENCY: usize = 4; + +/// Resolve the generation carried by a MemberLeft event without guessing. +/// ClusterEvent::MemberLeft contains only a node id, so a currently live +/// generation makes the event ambiguous (normally a delayed leave after a +/// reconnect). Missing previous-generation metadata is ambiguous as well. +pub(crate) fn external_member_left_departed_epoch( + previous_epoch: Option, + current_epoch: Option, +) -> Option { + current_epoch.is_none().then_some(previous_epoch).flatten() +} + +/// MemberLeft is a cold path. It may scan the handle registry, but removal is +/// conditional on both requester identity and membership generation so a +/// collected handle id can never delete a newer generation's entry. +pub(crate) fn cleanup_external_get_start_handles_for_generation( + registry: &dashmap::DashMap, + req_node_id: &str, + requester_node_start_time: i64, +) -> usize { + let handles = registry + .iter() + .filter_map(|entry| { + let value = entry.value(); + (value.req_node_id == req_node_id + && value.requester_node_start_time == Some(requester_node_start_time)) + .then_some(*entry.key()) + }) + .collect::>(); + + handles + .into_iter() + .filter(|handle| { + registry + .remove_if(handle, |_, value| { + value.req_node_id == req_node_id + && value.requester_node_start_time == Some(requester_node_start_time) + }) + .is_some() + }) + .count() +} + +struct ExternalPutStartFenceClaim { + view: Option, + fence: Option>, + uncertain_delay: Duration, + #[cfg(test)] + uncertain_test_sink: + Option>>>>, +} + +impl ExternalPutStartFenceClaim { + fn new( + view: crate::client_kv_api::ClientKvApiView, + fence: Arc, + ) -> Self { + Self { + view: Some(view), + fence: Some(fence), + uncertain_delay: EXTERNAL_PUT_START_UNCERTAIN_QUARANTINE, + #[cfg(test)] + uncertain_test_sink: None, + } + } + + #[cfg(test)] + fn new_for_cancellation_test( + fence: Arc, + sink: Arc>>>, + ) -> Self { + Self { + view: None, + fence: Some(fence), + uncertain_delay: Duration::ZERO, + uncertain_test_sink: Some(sink), + } + } + + fn take_for_pending_context(&mut self) -> Arc { + self.fence + .take() + .expect("external PutStart fence claim is armed") + } + + fn release_after_definite_response(&mut self) { + drop(self.fence.take()); + } +} + +impl Drop for ExternalPutStartFenceClaim { + fn drop(&mut self) { + let Some(fence) = self.fence.take() else { + return; + }; + #[cfg(test)] + if let Some(sink) = self.uncertain_test_sink.take() { + let replaced = sink.lock().replace(fence); + assert!(replaced.is_none(), "cancellation test sink must be empty"); + return; + } + let delay = self.uncertain_delay; + let view = self + .view + .take() + .expect("production uncertain PutStart fence requires owner view"); + let spawn_view = view.clone(); + let worker_view = view; + spawn_view.spawn("external_put_start_uncertain_fence", async move { + let mut shutdown_waiter = worker_view.register_shutdown_waiter(); + tokio::select! { + _ = tokio::time::sleep(delay) => {} + _ = shutdown_waiter.wait() => return, + } + drop(fence); + }); + } +} + +pub(crate) fn spawn_external_get_start_handle_sweeper(view: crate::client_kv_api::ClientKvApiView) { + let spawn_view = view.clone(); + let worker_view = view; + spawn_view.spawn("external_get_start_handle_sweeper", async move { + let mut shutdown_waiter = worker_view.register_shutdown_waiter(); + let mut interval = tokio::time::interval(EXTERNAL_GET_START_HANDLE_SWEEP_INTERVAL); + loop { + tokio::select! { + _ = interval.tick() => { + let expired = worker_view + .client_kv_api() + .inner() + .external_get_start_registry + .iter() + .filter_map(|entry| { + (entry.value().created_at.elapsed() >= EXTERNAL_GET_START_HANDLE_TTL) + .then_some(*entry.key()) + }) + .collect::>(); + if !expired.is_empty() { + let inner = worker_view.client_kv_api().inner(); + let mut removed = 0usize; + for handle in expired { + removed += usize::from(inner.external_get_start_registry.remove(&handle).is_some()); + } + tracing::warn!( + "expired abandoned external Get handles: removed={} ttl_secs={}", + removed, + EXTERNAL_GET_START_HANDLE_TTL.as_secs() + ); + } + } + _ = shutdown_waiter.wait() => break, + } + } + }); +} #[derive(Clone)] struct LocalCommittedCachePublish { @@ -61,19 +239,23 @@ fn local_committed_cache_publish( op: &'static str, key: &str, put_id: crate::master_kv_router::put::PutIDForAKey, - pending_ctx: Option<&ExternalPendingPutCtx>, + pending_ctx: &ExternalPendingPutCtx, req_src_offset: u64, req_len: u64, ) -> KvResult { - if let Some(ctx) = pending_ctx { - if ctx.src_offset != req_src_offset || ctx.len != req_len { - return Err(KvError::Api(ApiError::InvalidArgument { - detail: format!( - "{op} local cache publish request mismatches pending ctx: key={} put_id=({},{}) req_src_offset={} ctx_src_offset={} req_len={} ctx_len={}", - key, put_id.0, put_id.1, req_src_offset, ctx.src_offset, req_len, ctx.len - ), - })); - } + if pending_ctx.src_offset != req_src_offset || pending_ctx.len != req_len { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "{op} local cache publish request mismatches pending ctx: key={} put_id=({},{}) req_src_offset={} ctx_src_offset={} req_len={} ctx_len={}", + key, + put_id.0, + put_id.1, + req_src_offset, + pending_ctx.src_offset, + req_len, + pending_ctx.len + ), + })); } let len = u32::try_from(req_len).map_err(|_| { KvError::Api(ApiError::Unknown { @@ -89,6 +271,65 @@ fn local_committed_cache_publish( }) } +fn external_pending_put_ctx_missing( + op: &'static str, + key: &str, + put_id: crate::master_kv_router::put::PutIDForAKey, +) -> KvError { + KvError::Api(ApiError::InvalidArgument { + detail: format!( + "{op} requires a live owner pending Put context: key={} put_id=({},{}) (missing, expired, or already terminal)", + key, put_id.0, put_id.1 + ), + }) +} + +fn require_external_pending_put_ctx( + inner: &client_kv_api::ClientKvApiInner, + op: &'static str, + key: &str, + put_id: crate::master_kv_router::put::PutIDForAKey, +) -> KvResult { + require_external_pending_put_ctx_value( + inner + .external_pending_puts + .get(&(key.to_string(), put_id.0, put_id.1)), + op, + key, + put_id, + ) +} + +fn require_external_pending_put_ctx_value( + pending_ctx: Option, + op: &'static str, + key: &str, + put_id: crate::master_kv_router::put::PutIDForAKey, +) -> KvResult { + pending_ctx.ok_or_else(|| external_pending_put_ctx_missing(op, key, put_id)) +} + +async fn best_effort_revoke_missing_external_pending_ctx( + inner: &client_kv_api::ClientKvApiInner, + op: &'static str, + key: &str, + put_id: crate::master_kv_router::put::PutIDForAKey, +) -> bool { + if let Err(err) = inner.put_revoke(key, put_id).await { + tracing::warn!( + "{} could not clean missing pending Put context at master: key={} put_id=({},{}) err={}", + op, + key, + put_id.0, + put_id.1, + err + ); + false + } else { + true + } +} + fn external_local_first_error_item(err: &KvError) -> ExternalBatchPutStartItemResp { ExternalBatchPutStartItemResp { put_id: None, @@ -96,12 +337,6 @@ fn external_local_first_error_item(err: &KvError) -> ExternalBatchPutStartItemRe } } -fn external_local_first_release_keys(inner: &client_kv_api::ClientKvApiInner, keys: &[String]) { - for key in keys { - inner.release_external_local_first_put_key(key); - } -} - async fn commit_external_local_first_pending( inner: &client_kv_api::ClientKvApiInner, key: &str, @@ -162,12 +397,7 @@ async fn commit_external_local_first_pending( ) .await; inner.install_precommit_local_visible_memory_info(key, memory_info.clone()); - inner.promote_precommit_local_reserve_resident_slot_if_same( - key, - put_id, - memory_info, - ctx.atomic_group.as_ref(), - )?; + ctx._pending_fence.disarm_local_slot_lease(); Ok(PutDoneCommittedSlot { grant_id: slot_ref.grant_id, slot_index: slot_ref.slot_index, @@ -178,82 +408,47 @@ async fn commit_external_local_first_pending( }) } -fn spawn_external_local_first_publish( +async fn release_external_local_first_pending_slot( inner: &client_kv_api::ClientKvApiInner, - key: String, + ctx: &ExternalPendingPutCtx, + op: &'static str, + key: &str, put_id: crate::master_kv_router::put::PutIDForAKey, - lease_id: Option, - committed_slot: PutDoneCommittedSlot, - make_replica_task: bool, - preferred_sub_cluster: Option, - atomic_group: Option, ) { + if let Err(err) = ctx._pending_fence.release_local_slot_lease_now(inner).await { + tracing::error!( + "{} could not release local-first pending slot: key={} put_id=({},{}) err={}", + op, + key, + put_id.0, + put_id.1, + err + ); + } +} + +fn spawn_external_local_first_publish( + inner: &client_kv_api::ClientKvApiInner, + items: Vec, + pending_contexts: Vec, +) { + assert_eq!( + items.len(), + pending_contexts.len(), + "external local-first publish job must retain one context per item" + ); let view = inner.view.clone_view(); let spawn_view = view.clone(); spawn_view.spawn("external_local_first_route_publish", async move { - let inner = view.client_kv_api().inner(); - let publish_ok = match inner - .batch_put_done(vec![BatchPutDoneItemReq { - key: key.clone(), - put_id, - lease_id, - committed_slot: Some(committed_slot), - publish_local_cache: false, - atomic_group, - }]) - .await - { - Ok(resp) => { - if let Some(item) = resp.items.into_iter().next() { - if let Err(err) = - crate::rpcresp_kvresult_convert::try_from_code(item.error_code, item.error_json) - { - tracing::warn!( - "external local-first route publish failed: key={} put_id=({},{}) err={}", - key, - put_id.0, - put_id.1, - err - ); - false - } else { - true - } - } else { - tracing::warn!( - "external local-first route publish returned empty response: key={} put_id=({},{})", - key, - put_id.0, - put_id.1 - ); - false - } - } - Err(err) => { - tracing::warn!( - "external local-first route publish rpc failed: key={} put_id=({},{}) err={}", - key, - put_id.0, - put_id.1, - err - ); - false - } - }; - if publish_ok && make_replica_task { - if let Err(err) = inner - .make_replica_append_task(&key, put_id, preferred_sub_cluster, true) - .await - { - tracing::warn!( - "external local-first enqueue replica append failed: key={} put_id=({},{}) err={}", - key, - put_id.0, - put_id.1, - err - ); - } - } + client_kv_api::put::publish_owner_local_job( + view, + OwnerLocalPublishJob { + items, + key_reservation_ids: Vec::new(), + external_pending_contexts: pending_contexts, + }, + ) + .await; }); } @@ -397,25 +592,179 @@ fn collect_all_local_external_get_start_infos( .iter() .map(|item| match item { ExternalGetStartOwnerItem::Local { memory_info } => Some(memory_info.clone()), - ExternalGetStartOwnerItem::Started { .. } => None, + ExternalGetStartOwnerItem::Shared { .. } => None, }) .collect() } -fn collect_get_target_no_space_indices(items: &[BatchGetStartItemResp]) -> Vec { - items - .iter() - .enumerate() - .filter_map(|(idx, item)| (item.error_code == codes_api::API_NO_SPACE).then_some(idx)) - .collect() +fn prepared_target_from_slot( + slot_size: u64, + slot: &OwnerLocalReserveSlotRef, +) -> GetPreparedLocalReserveTarget { + GetPreparedLocalReserveTarget { + grant_id: slot.grant_id, + slot_index: slot.slot_index, + slot_size, + addr: slot.ptr, + base_addr: slot.base_addr, + } +} + +async fn release_prepared_get_target( + inner: &client_kv_api::ClientKvApiInner, + target: &GetPreparedLocalReserveTarget, +) -> KvResult<()> { + inner + .owner_release_local_reserve_slot_lease(OwnerLocalReserveSlotLease { + value_len: target.slot_size, + slot_size: target.slot_size, + slots: vec![OwnerLocalReserveSlotRef { + grant_id: target.grant_id, + slot_index: target.slot_index, + ptr: target.addr, + base_addr: target.base_addr, + }], + }) + .await +} + +/// Cancellation-safe ownership for slots claimed before BatchGetStart. +/// Accepted slots are disarmed one by one and become owned by their per-key +/// flight. Any slots still present when the future is dropped are returned by +/// a registered owner task, so an RPC cancellation cannot strand Prepared +/// state in the local-reserve pool. +struct PreparedGetSlotClaimGuard { + view: crate::client_kv_api::ClientKvApiView, + lease: Option, + drop_delay: Duration, +} + +impl PreparedGetSlotClaimGuard { + fn new(view: crate::client_kv_api::ClientKvApiView, lease: OwnerLocalReserveSlotLease) -> Self { + Self { + view, + lease: Some(lease), + drop_delay: PREPARED_GET_START_UNCERTAIN_QUARANTINE, + } + } + + fn lease(&self) -> &OwnerLocalReserveSlotLease { + self.lease.as_ref().expect("prepared slot claim is armed") + } + + fn disarm_accepted(&mut self, target: &GetPreparedLocalReserveTarget) { + let lease = self.lease.as_mut().expect("prepared slot claim is armed"); + lease.slots.retain(|slot| { + !(slot.grant_id == target.grant_id + && slot.slot_index == target.slot_index + && slot.ptr == target.addr + && slot.base_addr == target.base_addr) + }); + } + + fn mark_start_response_received(&mut self) { + self.drop_delay = Duration::ZERO; + } + + fn handoff_started( + &mut self, + items: &[crate::master_kv_router::msg_pack::BatchGetStartItemResp], + ) -> Vec { + items + .iter() + .filter(|item| item.error_code == OK) + .map(|item| { + if let Some(target) = item.prepared_target.as_ref() { + self.disarm_accepted(target); + } + StartedGetRevokeCleanup { + get_id: item.get_id, + prepared_target: item.prepared_target.clone(), + } + }) + .collect() + } +} + +impl Drop for PreparedGetSlotClaimGuard { + fn drop(&mut self) { + let Some(lease) = self.lease.take() else { + return; + }; + if lease.slots.is_empty() { + return; + } + let drop_delay = self.drop_delay; + let spawn_view = self.view.clone(); + let worker_view = spawn_view.clone(); + spawn_view.spawn("prepared_get_slot_drop_cleanup", async move { + if !drop_delay.is_zero() { + tracing::warn!( + "quarantining prepared Get slots after uncertain BatchGetStart: slots={} delay_secs={}", + lease.slots.len(), + drop_delay.as_secs() + ); + let mut shutdown_waiter = worker_view.register_shutdown_waiter(); + tokio::select! { + _ = tokio::time::sleep(drop_delay) => {} + _ = shutdown_waiter.wait() => return, + } + } + if let Err(err) = worker_view + .client_kv_api() + .inner() + .owner_release_local_reserve_slot_lease(lease) + .await + { + tracing::error!("prepared Get slot Drop cleanup failed: {}", err); + } + }); + } } -async fn batch_get_start_with_reserve_pressure_retry( +async fn batch_get_start_with_local_reserve_targets( inner: &client_kv_api::ClientKvApiInner, keys: &[String], ) -> KvResult { - let mut response = inner.batch_get_start(keys.to_vec()).await?; + let Some(value_len) = inner + .test_spec_config + .owner_local_reserve_expected_capacity + .as_ref() + .map(|expected| expected.value_len) + else { + return inner.batch_get_start(keys.to_vec()).await; + }; + let lease = inner + .owner_claim_local_reserve_slot_lease(value_len, keys.len()) + .await?; + let mut claim_guard = PreparedGetSlotClaimGuard::new(inner.view.clone_view(), lease); + let prepared_targets = claim_guard + .lease() + .slots + .iter() + .map(|slot| { + Some(prepared_target_from_slot( + claim_guard.lease().slot_size, + slot, + )) + }) + .collect::>(); + let response_result = inner + .batch_get_start_with_prepared_targets(keys.to_vec(), prepared_targets.clone()) + .await; + let response = match response_result { + Ok(response) => { + claim_guard.mark_start_response_received(); + response + } + Err(err) => return Err(err), + }; if response.items.len() != keys.len() { + let started = claim_guard.handoff_started(&response.items); + if !started.is_empty() { + finish_started_get_revoke_cleanup(inner, started, "BatchGetStart length mismatch") + .await; + } return Err(KvError::Api(ApiError::Unknown { detail: format!( "external_batch_get_start response length mismatch: expected={} got={}", @@ -425,60 +774,152 @@ async fn batch_get_start_with_reserve_pressure_retry( })); } - for attempt in 1..=GET_TARGET_NO_SPACE_RESERVE_SHRINK_RETRY_LIMIT { - let retry_indices = collect_get_target_no_space_indices(&response.items); - if retry_indices.is_empty() { - break; - } - let no_space_before = retry_indices.len(); - if !crate::client_kv_api::local_reserve_rebalance::release_one_excess_reserve_grant_for_get_target_pressure(inner).await - { - break; - } - let retry_keys = retry_indices + let accepted_exactly = + response + .items .iter() - .map(|idx| keys[*idx].clone()) - .collect::>(); - let retry_response = inner.batch_get_start(retry_keys).await?; - if retry_response.items.len() != retry_indices.len() { - return Err(KvError::Api(ApiError::Unknown { - detail: format!( - "external_batch_get_start NoSpace retry response length mismatch: expected={} got={} attempt={}", - retry_indices.len(), - retry_response.items.len(), - attempt - ), - })); - } - response.server_process_us = response - .server_process_us - .saturating_add(retry_response.server_process_us); - for (idx, item) in retry_indices - .into_iter() - .zip(retry_response.items.into_iter()) - { - response.items[idx] = item; + .zip(prepared_targets.iter()) + .all(|(item, requested_target)| { + item.error_code != OK || item.prepared_target.as_ref() == requested_target.as_ref() + }); + if !accepted_exactly { + let started = claim_guard.handoff_started(&response.items); + finish_started_get_revoke_cleanup(inner, started, "BatchGetStart target mismatch").await; + return Err(KvError::Api(ApiError::Unknown { + detail: "master did not accept the exact prepared local-reserve Get target".to_string(), + })); + } + for (item, requested_target) in response.items.iter().zip(prepared_targets.iter()) { + if item.error_code == OK { + claim_guard.disarm_accepted( + requested_target + .as_ref() + .expect("external prepared target vector must be dense"), + ); } - let no_space_after = collect_get_target_no_space_indices(&response.items).len(); - tracing::info!( - "external_batch_get_start retried local Get-target NoSpace after reserve shrink: attempt={} no_space_before={} no_space_after={}", - attempt, - no_space_before, - no_space_after - ); } Ok(response) } +#[cfg(test)] +mod external_put_pending_tests { + use super::{ExternalPutStartFenceClaim, require_external_pending_put_ctx_value}; + use crate::client_kv_api::{ + ExternalPendingPutFenceGuard, OwnerKeyControlTable, + acquire_external_pending_put_fence_for_key, + }; + use crate::rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError}; + use parking_lot::Mutex; + use std::sync::Arc; + + #[test] + fn missing_or_expired_pending_context_is_not_a_commit_capability() { + let result = require_external_pending_put_ctx_value( + None, + "external_put_commit", + "missing-key", + (17, 3), + ); + let Err(KvError::Api(ApiError::InvalidArgument { detail })) = result else { + panic!("missing pending context must be rejected") + }; + assert!(detail.contains("requires a live owner pending Put context")); + assert!(detail.contains("put_id=(17,3)")); + } + + #[test] + fn cancelled_put_start_hands_fence_to_uncertainty_quarantine() { + let controls = Arc::new(OwnerKeyControlTable::default()); + let fence = acquire_external_pending_put_fence_for_key(&controls, "cancelled-start") + .expect("pending fence acquisition must succeed"); + let sink: Arc>>> = + Arc::new(Mutex::new(None)); + + let claim = ExternalPutStartFenceClaim::new_for_cancellation_test(fence, sink.clone()); + drop(claim); + assert_eq!( + controls.lock_key("cancelled-start")["cancelled-start"].external_pending_puts, + 1, + "cancellation must transfer, not drop, the reclaim fence" + ); + + drop(sink.lock().take()); + assert!( + controls + .lock_key("cancelled-start") + .get("cancelled-start") + .is_none() + ); + } +} + #[cfg(test)] mod external_get_start_batch_tests { use super::{ - collect_external_get_start_missing, collect_get_target_no_space_indices, - compute_external_get_start_raw_prefix, compute_external_get_start_transfer_prefix, - normalize_external_put_start_group_lens, + abandon_unstarted_external_get_key_locked, + cleanup_external_get_start_handles_for_generation, clear_external_get_key_marker_locked, + collect_external_get_start_missing, compute_external_get_start_raw_prefix, + compute_external_get_start_transfer_prefix, decide_external_get_key_item, + external_member_left_departed_epoch, normalize_external_put_start_group_lens, + partition_external_get_finish_leaders, register_external_get_key_under_fence, + }; + use crate::client_kv_api::{ + ExternalGetKeySharedOp, ExternalGetStartEntry, ExternalGetStartOwnerItem, + OwnerKeyControlState, + }; + use crate::master_kv_router::msg_pack::{ + BatchGetStartItemResp, PutAtomicGroup, PutAtomicGroupMember, }; - use crate::master_kv_router::msg_pack::BatchGetStartItemResp; use crate::rpcresp_kvresult_convert::msg_and_error::{OK, codes_api}; + use dashmap::DashMap; + use std::collections::HashMap; + use std::sync::Arc; + use std::time::Instant; + + fn abandoned_handle_entry( + req_node_id: &str, + requester_node_start_time: Option, + ) -> ExternalGetStartEntry { + ExternalGetStartEntry { + req_node_id: req_node_id.to_string(), + requester_node_start_time, + keys: Vec::new(), + items: Vec::new(), + created_at: Instant::now(), + } + } + + #[test] + fn member_left_requires_previous_epoch_and_skips_delayed_leave_after_reconnect() { + assert_eq!( + external_member_left_departed_epoch(Some(11), None), + Some(11) + ); + assert_eq!(external_member_left_departed_epoch(None, None), None); + assert_eq!( + external_member_left_departed_epoch(Some(11), Some(12)), + None + ); + assert_eq!(external_member_left_departed_epoch(None, Some(12)), None); + } + + #[test] + fn member_left_removes_only_matching_requester_handle_generation() { + let registry = DashMap::new(); + registry.insert(1, abandoned_handle_entry("external-a", Some(11))); + registry.insert(2, abandoned_handle_entry("external-a", Some(12))); + registry.insert(3, abandoned_handle_entry("external-b", Some(11))); + registry.insert(4, abandoned_handle_entry("external-a", None)); + + assert_eq!( + cleanup_external_get_start_handles_for_generation(®istry, "external-a", 11), + 1 + ); + assert!(!registry.contains_key(&1)); + assert!(registry.contains_key(&2)); + assert!(registry.contains_key(&3)); + assert!(registry.contains_key(&4)); + } #[test] fn all_local_batch_has_no_master_fallback_and_keeps_full_atomic_prefix() { @@ -553,277 +994,1057 @@ mod external_get_start_batch_tests { } #[test] - fn get_target_pressure_retry_selects_only_no_space_items() { - let mut items = vec![BatchGetStartItemResp::default(); 4]; - items[0].error_code = OK; - items[1].error_code = codes_api::API_NO_SPACE; - items[2].error_code = codes_api::API_KEY_NOT_FOUND; - items[3].error_code = codes_api::API_NO_SPACE; - assert_eq!(collect_get_target_no_space_indices(&items), vec![1, 3]); - } -} - -async fn finish_external_get_start_transfer( - view: crate::client_kv_api::ClientKvApiView, + fn overlapping_nonidentical_batches_share_each_key_but_keep_leaders_batched() { + fn register_batch( + controls: &mut HashMap, + keys: &[&str], + ) -> ( + Vec, + Vec>, + ) { + let mut leaders = Vec::new(); + let items = keys + .iter() + .map(|key| { + let control = controls.entry((*key).to_string()).or_default(); + let interest = + register_external_get_key_under_fence(control, key, &mut leaders); + ExternalGetStartOwnerItem::Shared { interest } + }) + .collect(); + (items, leaders) + } + + let mut controls = HashMap::new(); + let (mut batch_a, leaders_a) = + register_batch(&mut controls, &["a", "shared-b", "shared-c"]); + let (mut batch_b, leaders_b) = + register_batch(&mut controls, &["shared-b", "shared-c", "d"]); + + assert_eq!( + leaders_a.len(), + 3, + "first required batch has one leader subset" + ); + assert_eq!( + leaders_b.len(), + 1, + "second batch starts only its new leader d" + ); + let shared_b_a = match &batch_a[1] { + ExternalGetStartOwnerItem::Shared { interest } => interest.op().clone(), + ExternalGetStartOwnerItem::Local { .. } => unreachable!(), + }; + let shared_b_b = match &batch_b[0] { + ExternalGetStartOwnerItem::Shared { interest } => interest.op().clone(), + ExternalGetStartOwnerItem::Local { .. } => unreachable!(), + }; + assert!(Arc::ptr_eq(&shared_b_a, &shared_b_b)); + + // Batch A keeps only [a,b], while batch B keeps [b,c,d]. Prefix + // decisions are independent, yet each physical key operation is still + // represented by one shared marker. + for (idx, item) in batch_a.iter_mut().enumerate() { + decide_external_get_key_item(item, idx < 2); + } + for item in &mut batch_b { + decide_external_get_key_item(item, true); + } + let state_b = shared_b_a.state.lock(); + assert_eq!(state_b.undecided, 0); + assert_eq!(state_b.retained, 2); + drop(state_b); + let shared_c = controls["shared-c"] + .external_get + .as_ref() + .expect("shared-c marker") + .state + .lock(); + assert_eq!(shared_c.undecided, 0); + assert_eq!(shared_c.retained, 1); + } + + #[test] + fn dropped_pending_interest_retires_decision_without_losing_batch_sharing() { + let key = "cancel-safe-key".to_string(); + let mut controls = HashMap::new(); + let mut first_leaders = Vec::new(); + let mut second_leaders = Vec::new(); + let first = register_external_get_key_under_fence( + controls.entry(key.clone()).or_default(), + &key, + &mut first_leaders, + ); + let mut second = register_external_get_key_under_fence( + controls.entry(key.clone()).or_default(), + &key, + &mut second_leaders, + ); + assert_eq!(first_leaders.len(), 1); + assert!(second_leaders.is_empty()); + assert!(Arc::ptr_eq(first.op(), second.op())); + assert_eq!(first.op().state.lock().undecided, 2); + + drop(first); + assert_eq!(second.op().state.lock().undecided, 1); + second.decide(true); + let state = second.op().state.lock(); + assert_eq!(state.undecided, 0); + assert_eq!(state.retained, 1); + } + + #[limit_thirdparty::tokio::test] + async fn aborting_waiter_future_retires_pending_interest_and_wakes_flight() { + let op = Arc::new(ExternalGetKeySharedOp::new("abort-safe-key".to_string())); + let waiter_op = op.clone(); + let (registered_tx, registered_rx) = ::tokio::sync::oneshot::channel(); + let waiter = ::tokio::spawn(async move { + let _interest = crate::client_kv_api::ExternalGetKeyInterest::new(waiter_op, true); + let _ = registered_tx.send(()); + futures::future::pending::<()>().await; + }); + + registered_rx.await.expect("waiter registered interest"); + assert_eq!(op.state.lock().undecided, 1); + let notified = op.notify.notified(); + futures::pin_mut!(notified); + notified.as_mut().enable(); + + waiter.abort(); + assert!( + waiter + .await + .expect_err("waiter must be aborted") + .is_cancelled() + ); + assert_eq!(op.state.lock().undecided, 0); + ::tokio::time::timeout(std::time::Duration::from_secs(1), notified) + .await + .expect("interest Drop must wake the flight"); + } + + #[test] + fn old_singleflight_cleanup_cannot_remove_new_generation() { + let key = "aba-key".to_string(); + let old = Arc::new(ExternalGetKeySharedOp::new(key.clone())); + let mut controls = HashMap::from([( + key.clone(), + OwnerKeyControlState { + local_puts: 0, + external_pending_puts: 0, + reclaim: None, + external_get: Some(old.clone()), + }, + )]); + clear_external_get_key_marker_locked(&mut controls, &old); + assert!(!controls.contains_key(&key)); + + let new = Arc::new(ExternalGetKeySharedOp::new(key.clone())); + controls.entry(key.clone()).or_default().external_get = Some(new.clone()); + clear_external_get_key_marker_locked(&mut controls, &old); + assert!( + controls[&key] + .external_get + .as_ref() + .is_some_and(|current| Arc::ptr_eq(current, &new)) + ); + } + + #[test] + fn cancelled_planning_leader_becomes_miss_and_clears_only_its_generation() { + let key = "planning-cancel-key".to_string(); + let op = Arc::new(ExternalGetKeySharedOp::new(key.clone())); + let mut controls = HashMap::from([( + key.clone(), + OwnerKeyControlState { + local_puts: 0, + external_pending_puts: 0, + reclaim: None, + external_get: Some(op.clone()), + }, + )]); + + assert!(abandon_unstarted_external_get_key_locked( + &mut controls, + &op + )); + assert!(!controls.contains_key(&key)); + assert!(matches!( + &op.state.lock().phase, + crate::client_kv_api::ExternalGetKeySharedPhase::Ready { + result: crate::client_kv_api::ExternalGetStartSharedItemResult::Miss + } + )); + assert!(!abandon_unstarted_external_get_key_locked( + &mut controls, + &op + )); + } + + #[test] + fn done_partition_keeps_atomic_groups_intact_and_bounds_other_batches() { + let group = PutAtomicGroup { + members: (0..3) + .map(|idx| PutAtomicGroupMember { + key: format!("group-{idx}"), + put_id: (7, idx), + }) + .collect(), + }; + let leader = |key: &str, atomic_group: Option| { + ( + Arc::new(ExternalGetKeySharedOp::new(key.to_string())), + BatchGetStartItemResp { + atomic_group, + ..Default::default() + }, + ) + }; + let batches = partition_external_get_finish_leaders( + vec![ + leader("single-a", None), + leader("group-0", Some(group.clone())), + leader("single-b", None), + leader("group-1", Some(group.clone())), + leader("group-2", Some(group.clone())), + leader("single-c", None), + ], + 2, + ); + + let group_batch_count = batches + .iter() + .filter(|batch| batch.iter().any(|(op, _)| op.key.starts_with("group-"))) + .count(); + assert_eq!(group_batch_count, 1, "one atomic group must not be split"); + let group_batch = batches + .iter() + .find(|batch| batch.iter().any(|(op, _)| op.key == "group-0")) + .unwrap(); + assert_eq!( + group_batch + .iter() + .filter(|(op, _)| op.key.starts_with("group-")) + .count(), + 3 + ); + assert!(batches.iter().all(|batch| { + batch.len() <= 2 + || batch + .iter() + .all(|(_, item)| item.atomic_group.as_ref() == Some(&group)) + })); + } +} + +async fn finish_external_get_start_transfer( + view: crate::client_kv_api::ClientKvApiView, transfer_items: Vec, - transfer_concurrency: usize, + _transfer_concurrency: usize, ) -> KvResult { let client_api = view.client_kv_api(); let inner = client_api.inner(); let refcount = inner.get_or_init_all_memholder_refcount(); - let mut results: Vec< - Option, Option)>>>, - > = (0..transfer_items.len()).map(|_| None).collect(); - let mut started_positions = Vec::new(); - let mut started_keys = Vec::new(); - let mut started_items = Vec::new(); - - for (idx, item) in transfer_items.into_iter().enumerate() { - match item { - ExternalGetStartOwnerItem::Local { memory_info } => { - let holder = Arc::new(UserMemHolder::new( - memory_info, - refcount.clone(), - UserMemHolderExposeKind::SegPtr, - )); - results[idx] = Some(Ok(Some((holder, None)))); + let waits = transfer_items.into_iter().map(|item| { + let refcount = refcount.clone(); + async move { + match item { + ExternalGetStartOwnerItem::Local { memory_info } => Ok(Some(( + Arc::new(UserMemHolder::new( + memory_info, + refcount, + UserMemHolderExposeKind::SegPtr, + )), + None, + ))), + ExternalGetStartOwnerItem::Shared { interest } => { + match wait_external_get_key_result(interest.op().clone()).await? { + ExternalGetStartSharedItemResult::Hit { memholder } => { + Ok(Some((memholder, None))) + } + ExternalGetStartSharedItemResult::Miss => Ok(None), + ExternalGetStartSharedItemResult::Error { + error_code, + error_json, + } => Err(KvError::from_json(error_code, &error_json)), + } + } + } + } + }); + Ok(futures::future::join_all(waits).await) +} + +fn external_get_start_error_parts(err: &KvError) -> (u32, String) { + (err.code(), err.to_json()) +} + +async fn wait_external_get_key_not_revoking(op: Arc) { + loop { + let notified = op.notify.notified(); + futures::pin_mut!(notified); + let should_wait = { + let state = op.state.lock(); + if matches!(state.phase, ExternalGetKeySharedPhase::Revoking { .. }) { + notified.as_mut().enable(); + true + } else { + false + } + }; + if !should_wait { + return; + } + notified.await; + } +} + +fn register_external_get_key_under_fence( + control: &mut client_kv_api::OwnerKeyControlState, + key: &str, + leaders: &mut Vec>, +) -> ExternalGetKeyInterest { + if let Some(op) = control.external_get.clone() { + let mut state = op.state.lock(); + let decision_registered = match state.phase { + ExternalGetKeySharedPhase::Starting | ExternalGetKeySharedPhase::Started { .. } => { + state.undecided = state + .undecided + .checked_add(1) + .expect("external Get singleflight undecided overflow"); + true } - ExternalGetStartOwnerItem::Started { key, item } => { - started_positions.push(idx); - started_keys.push(key); - started_items.push(item); + ExternalGetKeySharedPhase::Finishing { .. } + | ExternalGetKeySharedPhase::Ready { .. } + | ExternalGetKeySharedPhase::Failed { .. } => false, + ExternalGetKeySharedPhase::Revoking { .. } => { + unreachable!("revoking markers were checked under the same fence") } + }; + drop(state); + ExternalGetKeyInterest::new(op, decision_registered) + } else { + let op = Arc::new(ExternalGetKeySharedOp::new(key.to_string())); + control.external_get = Some(op.clone()); + leaders.push(op.clone()); + ExternalGetKeyInterest::new(op, true) + } +} + +/// Owns newly installed `Starting` markers until the complete request batch is +/// ready to hand them to one BatchGetStart worker. If planning is cancelled +/// while waiting for an older Revoke on another key, Drop converts only these +/// never-started operations to a safe miss and removes their markers. No +/// prepared target or master identity exists yet, so there is nothing to +/// revoke and no storage state to guess. +struct ExternalGetPlanningLeadersGuard<'a> { + inner: &'a client_kv_api::ClientKvApiInner, + leaders: Vec>, + handed_off: bool, +} + +impl<'a> ExternalGetPlanningLeadersGuard<'a> { + fn new(inner: &'a client_kv_api::ClientKvApiInner) -> Self { + Self { + inner, + leaders: Vec::new(), + handed_off: false, } } - if !started_items.is_empty() { - let started_results = inner - .batch_get_finish_started(started_keys, started_items, transfer_concurrency) - .await?; - if started_results.len() != started_positions.len() { - return Err(KvError::Api(ApiError::Unknown { - detail: format!( - "external get_start transfer result length mismatch: expected={} got={}", - started_positions.len(), - started_results.len() - ), - })); + fn leaders_mut(&mut self) -> &mut Vec> { + &mut self.leaders + } + + fn handoff(mut self) -> Vec> { + self.handed_off = true; + std::mem::take(&mut self.leaders) + } +} + +impl Drop for ExternalGetPlanningLeadersGuard<'_> { + fn drop(&mut self) { + if self.handed_off { + return; } - for (idx, result) in started_positions - .into_iter() - .zip(started_results.into_iter()) - { - results[idx] = Some(result); + for op in &self.leaders { + let notify = { + let mut controls = self.inner.owner_key_control.lock_key(&op.key); + abandon_unstarted_external_get_key_locked(&mut controls, op) + }; + if notify { + self.inner.untrack_external_get_flight(op); + op.notify.notify_waiters(); + } } } +} - Ok(results - .into_iter() - .map(|item| { - item.unwrap_or_else(|| { - Err(KvError::Api(ApiError::Unknown { - detail: "external get_start transfer result slot was not populated".to_string(), - })) - }) - }) - .collect()) +async fn plan_external_get_key_items( + inner: &client_kv_api::ClientKvApiInner, + keys: &[String], +) -> ( + Vec, + Vec>, +) { + enum KeyAttempt { + Wait(Arc), + Ready { + item: ExternalGetStartOwnerItem, + hot_touch: Option<( + crate::master_kv_router::put::PutIDForAKey, + Arc, + )>, + }, + } + + let mut items = Vec::with_capacity(keys.len()); + let mut planning_leaders = ExternalGetPlanningLeadersGuard::new(inner); + let mut hot_touches = Vec::new(); + for key in keys { + loop { + // One short per-key shard section atomically chooses local, + // joiner, or leader. No synchronous lock spans the request batch + // or the wait for an older Revoke to finish. + let attempt = { + let mut controls = inner.owner_key_control.lock_key(key); + let revoking = controls + .get(key) + .and_then(|state| state.external_get.clone()) + .filter(|op| { + matches!( + op.state.lock().phase, + ExternalGetKeySharedPhase::Revoking { .. } + ) + }); + if let Some(op) = revoking { + KeyAttempt::Wait(op) + } else { + let fenced = controls + .get(key) + .is_some_and(|state| state.reclaim.is_some()); + if !fenced { + if let Some(memory_info) = inner.local_visible_mem_holder_unfenced(key) { + let hot_touch = inner.get_cached_info.get(key).and_then(|cached| { + Arc::ptr_eq(&cached.mem_holder, &memory_info).then_some(( + (cached.put_time_ms, cached.put_version), + memory_info.clone(), + )) + }); + KeyAttempt::Ready { + item: ExternalGetStartOwnerItem::Local { memory_info }, + hot_touch, + } + } else { + let control = controls.entry(key.clone()).or_default(); + let leader_count = planning_leaders.leaders.len(); + let interest = register_external_get_key_under_fence( + control, + key, + planning_leaders.leaders_mut(), + ); + if planning_leaders.leaders.len() != leader_count { + inner.track_external_get_flight(interest.op()); + } + KeyAttempt::Ready { + item: ExternalGetStartOwnerItem::Shared { interest }, + hot_touch: None, + } + } + } else { + let control = controls.entry(key.clone()).or_default(); + let leader_count = planning_leaders.leaders.len(); + let interest = register_external_get_key_under_fence( + control, + key, + planning_leaders.leaders_mut(), + ); + if planning_leaders.leaders.len() != leader_count { + inner.track_external_get_flight(interest.op()); + } + KeyAttempt::Ready { + item: ExternalGetStartOwnerItem::Shared { interest }, + hot_touch: None, + } + } + } + }; + + match attempt { + KeyAttempt::Wait(op) => wait_external_get_key_not_revoking(op).await, + KeyAttempt::Ready { item, hot_touch } => { + if let Some((put_id, memory_info)) = hot_touch { + hot_touches.push((key.clone(), put_id, memory_info)); + } + items.push(item); + break; + } + } + } + } + + for (key, put_id, memory_info) in hot_touches { + inner.owner_hot_touch_or_promote(&key, put_id, &memory_info); + } + (items, planning_leaders.handoff()) } -fn external_get_start_error_parts(err: &KvError) -> (u32, String) { - (err.code(), err.to_json()) +fn clear_external_get_key_marker_locked( + controls: &mut std::collections::HashMap, + op: &Arc, +) { + let remove_control = if let Some(control) = controls.get_mut(&op.key) { + if control + .external_get + .as_ref() + .is_some_and(|current| Arc::ptr_eq(current, op)) + { + control.external_get = None; + } + control.is_idle() + } else { + false + }; + if remove_control { + controls.remove(&op.key); + } } -fn register_external_get_start_waiter(shared_op: &Arc) { - let mut state = shared_op.state.lock(); - state.waiter_count = state - .waiter_count - .checked_add(1) - .expect("external get_start shared waiter count overflow"); +fn abandon_unstarted_external_get_key_locked( + controls: &mut std::collections::HashMap, + op: &Arc, +) -> bool { + let mut state = op.state.lock(); + if !matches!(state.phase, ExternalGetKeySharedPhase::Starting) { + return false; + } + state.phase = ExternalGetKeySharedPhase::Ready { + result: ExternalGetStartSharedItemResult::Miss, + }; + clear_external_get_key_marker_locked(controls, op); + true } -fn release_external_get_start_waiter( +fn publish_external_get_key_terminal( inner: &client_kv_api::ClientKvApiInner, - shared_op: &Arc, + op: &Arc, + phase: ExternalGetKeySharedPhase, ) { - let should_remove = { - let mut state = shared_op.state.lock(); - assert!( - state.waiter_count > 0, - "external get_start shared waiter count underflow" - ); - state.waiter_count -= 1; - state.waiter_count == 0 - }; - if should_remove { - inner - .external_get_start_by_key - .remove_if(&shared_op.dedup_key, |_, op| { - if !Arc::ptr_eq(op, shared_op) { - return false; - } - op.state.lock().waiter_count == 0 - }); + { + let mut controls = inner.owner_key_control.lock_key(&op.key); + op.state.lock().phase = phase; + clear_external_get_key_marker_locked(&mut controls, op); } + inner.untrack_external_get_flight(op); + op.notify.notify_waiters(); } -fn publish_external_get_start_failed(shared_op: &Arc, err: &KvError) { +fn publish_external_get_key_failed( + inner: &client_kv_api::ClientKvApiInner, + op: &Arc, + err: &KvError, +) { let (error_code, error_json) = external_get_start_error_parts(err); + publish_external_get_key_terminal( + inner, + op, + ExternalGetKeySharedPhase::Failed { + error_code, + error_json, + }, + ); +} + +fn publish_external_get_key_started( + op: &Arc, + item: crate::master_kv_router::msg_pack::BatchGetStartItemResp, +) { { - let mut state = shared_op.state.lock(); - state.phase = ExternalGetStartSharedPhase::Failed { + let mut state = op.state.lock(); + assert!(matches!(state.phase, ExternalGetKeySharedPhase::Starting)); + state.phase = ExternalGetKeySharedPhase::Started { item }; + } + op.notify.notify_waiters(); +} + +fn external_get_key_ready_from_code( + error_code: u32, + error_json: String, +) -> ExternalGetStartSharedItemResult { + if error_code == codes_api::API_KEY_NOT_FOUND { + ExternalGetStartSharedItemResult::Miss + } else { + ExternalGetStartSharedItemResult::Error { error_code, error_json, + } + } +} + +async fn wait_external_get_key_start_code( + op: Arc, +) -> KvResult<(u32, String)> { + loop { + let notified = op.notify.notified(); + futures::pin_mut!(notified); + let should_wait = { + let state = op.state.lock(); + match &state.phase { + ExternalGetKeySharedPhase::Starting => { + notified.as_mut().enable(); + true + } + ExternalGetKeySharedPhase::Started { item } + | ExternalGetKeySharedPhase::Finishing { item } => { + return Ok((item.error_code, item.error_json.clone())); + } + ExternalGetKeySharedPhase::Ready { result } => { + return Ok(match result { + ExternalGetStartSharedItemResult::Hit { .. } => (OK, String::new()), + ExternalGetStartSharedItemResult::Miss => { + (codes_api::API_KEY_NOT_FOUND, String::new()) + } + ExternalGetStartSharedItemResult::Error { + error_code, + error_json, + } => (*error_code, error_json.clone()), + }); + } + ExternalGetKeySharedPhase::Failed { + error_code, + error_json, + } => return Err(KvError::from_json(*error_code, error_json)), + ExternalGetKeySharedPhase::Revoking { .. } => { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external Get key entered revoke before prefix decision: key={}", + op.key + ), + })); + } + } }; + if should_wait { + notified.await; + } } - shared_op.notify.notify_waiters(); } -fn publish_external_get_start_ready( - shared_op: &Arc, - keys: Vec, - transfer_result: KvResult, -) { - let phase = match transfer_result { - Ok(transfer_results) => { - if transfer_results.len() != keys.len() { - let err = KvError::Api(ApiError::Unknown { - detail: format!( - "external shared get_start transfer result length mismatch: expected={} got={}", - keys.len(), - transfer_results.len() - ), - }); - let (error_code, error_json) = external_get_start_error_parts(&err); - ExternalGetStartSharedPhase::Failed { +async fn wait_external_get_key_result( + op: Arc, +) -> KvResult { + loop { + let notified = op.notify.notified(); + futures::pin_mut!(notified); + let should_wait = { + let state = op.state.lock(); + match &state.phase { + ExternalGetKeySharedPhase::Starting + | ExternalGetKeySharedPhase::Started { .. } + | ExternalGetKeySharedPhase::Finishing { .. } => { + notified.as_mut().enable(); + true + } + ExternalGetKeySharedPhase::Ready { result } => return Ok(result.clone()), + ExternalGetKeySharedPhase::Failed { error_code, error_json, + } => return Err(KvError::from_json(*error_code, error_json)), + ExternalGetKeySharedPhase::Revoking { .. } => { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "retained external Get key was unexpectedly revoked: key={}", + op.key + ), + })); + } + } + }; + if should_wait { + notified.await; + } + } +} + +fn decide_external_get_key_item(item: &mut ExternalGetStartOwnerItem, retain: bool) { + if let ExternalGetStartOwnerItem::Shared { interest } = item { + interest.decide(retain); + } +} + +enum ExternalGetKeyLeaderAction { + Finish { + op: Arc, + item: crate::master_kv_router::msg_pack::BatchGetStartItemResp, + }, + Revoke { + op: Arc, + item: crate::master_kv_router::msg_pack::BatchGetStartItemResp, + }, + Terminal, +} + +type ExternalGetFinishLeader = (Arc, BatchGetStartItemResp); + +struct ExternalGetFinishUnit { + group: Option, + leaders: Vec, +} + +/// Partition leaders into independent Done failure domains while preserving +/// caller-declared atomic groups. The target is deliberately soft: one large +/// atomic group stays intact instead of being split across terminal RPCs. +fn partition_external_get_finish_leaders( + leaders: Vec, + target_keys_per_batch: usize, +) -> Vec> { + if leaders.is_empty() { + return Vec::new(); + } + let target_keys_per_batch = target_keys_per_batch.max(1); + let mut units: Vec = Vec::new(); + let mut group_unit_by_anchor = HashMap::<(String, u64, u32), usize>::new(); + + for leader in leaders { + let group = leader.1.atomic_group.as_ref(); + let Some(group) = group else { + units.push(ExternalGetFinishUnit { + group: None, + leaders: vec![leader], + }); + continue; + }; + let Some(anchor) = group.members.first() else { + // Master validation rejects empty groups. Treat malformed legacy + // metadata as a singleton here so partitioning cannot lose work. + units.push(ExternalGetFinishUnit { + group: None, + leaders: vec![leader], + }); + continue; + }; + let signature = (anchor.key.clone(), anchor.put_id.0, anchor.put_id.1); + if let Some(unit_idx) = group_unit_by_anchor.get(&signature).copied() + && units[unit_idx].group.as_ref() == Some(group) + { + units[unit_idx].leaders.push(leader); + continue; + } + let unit_idx = units.len(); + units.push(ExternalGetFinishUnit { + group: Some(group.clone()), + leaders: vec![leader], + }); + group_unit_by_anchor.insert(signature, unit_idx); + } + + let mut batches = Vec::new(); + let mut current = Vec::new(); + for mut unit in units { + if !current.is_empty() + && current.len().saturating_add(unit.leaders.len()) > target_keys_per_batch + { + batches.push(std::mem::take(&mut current)); + } + current.append(&mut unit.leaders); + if current.len() >= target_keys_per_batch { + batches.push(std::mem::take(&mut current)); + } + } + if !current.is_empty() { + batches.push(current); + } + batches +} + +async fn classify_external_get_key_leader( + inner: &client_kv_api::ClientKvApiInner, + op: Arc, +) -> ExternalGetKeyLeaderAction { + loop { + let notified = op.notify.notified(); + futures::pin_mut!(notified); + let wait_for_decisions = { + let state = op.state.lock(); + if matches!( + state.phase, + ExternalGetKeySharedPhase::Starting | ExternalGetKeySharedPhase::Started { .. } + ) && state.undecided != 0 + { + notified.as_mut().enable(); + true + } else { + false + } + }; + if wait_for_decisions { + notified.await; + continue; + } + + let mut notify_terminal = false; + let action = { + // Planner lock order is owner fence -> per-key op. Use the same + // order here so no request can join after undecided reaches zero + // but before the leader closes admission. + let mut controls = inner.owner_key_control.lock_key(&op.key); + let mut state = op.state.lock(); + match &state.phase { + ExternalGetKeySharedPhase::Started { item } if state.undecided == 0 => { + let item = item.clone(); + if item.error_code != OK { + state.phase = ExternalGetKeySharedPhase::Ready { + result: external_get_key_ready_from_code( + item.error_code, + item.error_json, + ), + }; + clear_external_get_key_marker_locked(&mut controls, &op); + notify_terminal = true; + Some(ExternalGetKeyLeaderAction::Terminal) + } else if state.retained == 0 { + state.phase = ExternalGetKeySharedPhase::Revoking { item: item.clone() }; + Some(ExternalGetKeyLeaderAction::Revoke { + op: op.clone(), + item, + }) + } else { + state.phase = ExternalGetKeySharedPhase::Finishing { item: item.clone() }; + Some(ExternalGetKeyLeaderAction::Finish { + op: op.clone(), + item, + }) + } + } + ExternalGetKeySharedPhase::Starting | ExternalGetKeySharedPhase::Started { .. } => { + None + } + ExternalGetKeySharedPhase::Finishing { .. } + | ExternalGetKeySharedPhase::Revoking { .. } + | ExternalGetKeySharedPhase::Ready { .. } + | ExternalGetKeySharedPhase::Failed { .. } => { + Some(ExternalGetKeyLeaderAction::Terminal) + } + } + }; + if notify_terminal { + inner.untrack_external_get_flight(&op); + op.notify.notify_waiters(); + } + if let Some(action) = action { + return action; + } + tokio::task::yield_now().await; + } +} + +async fn finish_external_get_key_leaders( + view: crate::client_kv_api::ClientKvApiView, + leaders: Vec>, + transfer_concurrency: usize, +) { + let client_api = view.client_kv_api(); + let inner = client_api.inner(); + let mut finish = Vec::new(); + let mut revoke = Vec::new(); + for op in leaders { + match classify_external_get_key_leader(inner, op).await { + ExternalGetKeyLeaderAction::Finish { op, item } => finish.push((op, item)), + ExternalGetKeyLeaderAction::Revoke { op, item } => revoke.push((op, item)), + ExternalGetKeyLeaderAction::Terminal => {} + } + } + + if !revoke.is_empty() { + let mut attempt = 1u32; + loop { + let get_ids = revoke + .iter() + .map(|(_, item)| item.get_id) + .collect::>(); + let response = inner.batch_get_revoke(get_ids).await; + let resp = match response { + Ok(resp) + if resp.items.len() == revoke.len() + && resp + .items + .iter() + .zip(&revoke) + .all(|(resp, (_, expected))| resp.get_id == expected.get_id) => + { + resp + } + Ok(resp) => { + tracing::warn!( + "BatchGetRevoke response length mismatch; retaining prepared slots and retrying: expected={} got={} attempt={}", + revoke.len(), + resp.items.len(), + attempt + ); + tokio::time::sleep(Duration::from_millis( + (50u64.saturating_mul(1u64 << attempt.min(6))).min(2_000), + )) + .await; + attempt = attempt.saturating_add(1); + continue; + } + Err(err) => { + if matches!(&err, KvError::Api(ApiError::SystemShutdown { .. })) { + tracing::warn!( + "BatchGetRevoke cleanup stopped during owner shutdown: items={}", + revoke.len() + ); + return; + } + tracing::warn!( + "BatchGetRevoke uncertain; retaining operation identity and prepared slots for retry: items={} attempt={} err={}", + revoke.len(), + attempt, + err + ); + tokio::time::sleep(Duration::from_millis( + (50u64.saturating_mul(1u64 << attempt.min(6))).min(2_000), + )) + .await; + attempt = attempt.saturating_add(1); + continue; + } + }; + + for ((op, item), revoke_item) in revoke.drain(..).zip(resp.items) { + if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( + revoke_item.error_code, + revoke_item.error_json, + ) { + // Done won the per-get terminal lock (or requester identity + // is invalid). The candidate may be committed, so never + // return its slot from the losing Revoke path. + publish_external_get_key_failed(inner, &op, &err); + continue; } - } else { - let items = keys - .iter() - .zip(transfer_results.into_iter()) - .map(|(_key, item_result)| match item_result { - Ok(Some((memholder, _))) => { - ExternalGetStartSharedItemResult::Hit { memholder } - } - Ok(None) => ExternalGetStartSharedItemResult::Miss, - Err(err) => { - let (error_code, error_json) = external_get_start_error_parts(&err); - ExternalGetStartSharedItemResult::Error { - error_code, - error_json, + if let Some(target) = item.prepared_target.as_ref() { + let mut release_attempt = 1u32; + loop { + match release_prepared_get_target(inner, target).await { + Ok(()) => break, + Err(err) => { + if !inner.view.register_shutdown_poller().is_running() { + return; + } + tracing::error!( + "Revoke confirmed but prepared slot release failed; keeping key fenced for retry: key={} get_id={} attempt={} err={}", + op.key, + item.get_id, + release_attempt, + err + ); + tokio::time::sleep(Duration::from_millis(1000)).await; + release_attempt = release_attempt.saturating_add(1); } } - }) - .collect::>(); - let prefix = match { - let state = shared_op.state.lock(); - match &state.phase { - ExternalGetStartSharedPhase::Running { prefix, .. } - | ExternalGetStartSharedPhase::Ready { prefix, .. } => Ok(prefix.clone()), - ExternalGetStartSharedPhase::Starting - | ExternalGetStartSharedPhase::Failed { .. } => Err(KvError::Api( - ApiError::Unknown { - detail: - "external shared get_start transfer completed before prefix was published" - .to_string(), - }, - )), - } - } { - Ok(prefix) => prefix, - Err(err) => { - let (error_code, error_json) = external_get_start_error_parts(&err); - let mut state = shared_op.state.lock(); - state.phase = ExternalGetStartSharedPhase::Failed { - error_code, - error_json, - }; - shared_op.notify.notify_waiters(); - return; } - }; - ExternalGetStartSharedPhase::Ready { - prefix, - keys, - items, } + publish_external_get_key_terminal( + inner, + &op, + ExternalGetKeySharedPhase::Ready { + result: ExternalGetStartSharedItemResult::Miss, + }, + ); } + break; } - Err(err) => { - let (error_code, error_json) = external_get_start_error_parts(&err); - ExternalGetStartSharedPhase::Failed { - error_code, - error_json, - } - } - }; - { - let mut state = shared_op.state.lock(); - state.phase = phase; } - shared_op.notify.notify_waiters(); -} -async fn wait_external_get_start_prefix( - shared_op: Arc, -) -> KvResult { - loop { - let notified = shared_op.notify.notified(); - futures::pin_mut!(notified); - let should_wait = { - let state = shared_op.state.lock(); - match &state.phase { - ExternalGetStartSharedPhase::Starting => { - notified.as_mut().enable(); - true - } - ExternalGetStartSharedPhase::Running { prefix, .. } - | ExternalGetStartSharedPhase::Ready { prefix, .. } => { - return Ok(prefix.clone()); - } - ExternalGetStartSharedPhase::Failed { - error_code, - error_json, - } => return Err(KvError::from_json(*error_code, error_json)), - } - }; - if should_wait { - notified.await; - } + if finish.is_empty() { + return; } -} + let finish_batches = + partition_external_get_finish_leaders(finish, EXTERNAL_GET_FINISH_TARGET_KEYS_PER_BATCH); + let batch_concurrency = EXTERNAL_GET_FINISH_BATCH_CONCURRENCY + .min(finish_batches.len()) + .max(1); + let per_batch_transfer_concurrency = transfer_concurrency + .max(1) + .div_ceil(batch_concurrency) + .max(1); + tracing::debug!( + "external Get singleflight finish partitioned: batches={} batch_concurrency={} transfer_concurrency_per_batch={}", + finish_batches.len(), + batch_concurrency, + per_batch_transfer_concurrency + ); -async fn wait_external_get_start_transfer( - shared_op: Arc, -) -> KvResult<(Vec, Vec)> { - loop { - let notified = shared_op.notify.notified(); - futures::pin_mut!(notified); - let should_wait = { - let state = shared_op.state.lock(); - match &state.phase { - ExternalGetStartSharedPhase::Starting - | ExternalGetStartSharedPhase::Running { .. } => { - notified.as_mut().enable(); - true + let finish_futures = finish_batches.into_iter().map(|batch| { + let batch_view = view.clone(); + async move { + let keys = batch + .iter() + .map(|(op, _)| op.key.clone()) + .collect::>(); + let start_items = batch + .iter() + .map(|(_, item)| item.clone()) + .collect::>(); + let result = batch_view + .client_kv_api() + .inner() + .batch_get_finish_started(keys, start_items, per_batch_transfer_concurrency) + .await; + (batch, result) + } + }); + let mut finish_stream = + futures::stream::iter(finish_futures).buffer_unordered(batch_concurrency); + while let Some((batch, finish_result)) = finish_stream.next().await { + match finish_result { + Ok(results) if results.len() == batch.len() => { + // Publish each confirmed sub-batch immediately. A different + // uncertain Done cohort therefore cannot retain these flights + // or their pending-visible slots. + for ((op, _), result) in batch.into_iter().zip(results) { + let phase = match result { + Ok(Some((memholder, _))) => ExternalGetKeySharedPhase::Ready { + result: ExternalGetStartSharedItemResult::Hit { memholder }, + }, + Ok(None) => ExternalGetKeySharedPhase::Ready { + result: ExternalGetStartSharedItemResult::Miss, + }, + Err(err) => { + let (error_code, error_json) = external_get_start_error_parts(&err); + ExternalGetKeySharedPhase::Ready { + result: ExternalGetStartSharedItemResult::Error { + error_code, + error_json, + }, + } + } + }; + publish_external_get_key_terminal(inner, &op, phase); } - ExternalGetStartSharedPhase::Ready { keys, items, .. } => { - return Ok((keys.clone(), items.clone())); + } + Ok(results) => { + let err = KvError::Api(ApiError::Unknown { + detail: format!( + "singleflight leader finish length mismatch: expected={} got={}", + batch.len(), + results.len() + ), + }); + for (op, _) in batch { + publish_external_get_key_failed(inner, &op, &err); + } + } + Err(err) => { + for (op, _) in batch { + publish_external_get_key_failed(inner, &op, &err); } - ExternalGetStartSharedPhase::Failed { - error_code, - error_json, - } => return Err(KvError::from_json(*error_code, error_json)), } - }; - if should_wait { - notified.await; } } } -async fn prepare_external_get_start_shared_op( +async fn prepare_external_get_batch_plan( inner: &client_kv_api::ClientKvApiInner, req: &ExternalBatchGetStartReq, group_lens: &[usize], @@ -832,71 +2053,53 @@ async fn prepare_external_get_start_shared_op( Vec, Vec, )> { - let local_memory_infos = inner.local_visible_mem_holders(&req.keys); - if local_memory_infos.iter().all(Option::is_some) { - let key_count = req.keys.len(); - let transfer_items = local_memory_infos - .into_iter() - .map(|memory_info| ExternalGetStartOwnerItem::Local { - memory_info: memory_info.expect("all local-visible entries were checked"), - }) - .collect(); - tracing::debug!( - key_count, - req_node_id = %req.req_node_id, - "external_batch_get_start used all-local-visible batch fast path" - ); - return Ok(( - ExternalGetStartPrefixResult { - raw_prefix_hit_len: key_count, - transferable_len: key_count, - first_miss_index: None, - first_error_kind: None, - }, - req.keys.clone(), - transfer_items, - )); + let (mut items, leaders) = plan_external_get_key_items(inner, &req.keys).await; + if !leaders.is_empty() { + let leader_keys = leaders.iter().map(|op| op.key.clone()).collect::>(); + let spawn_view = inner.view.clone_view(); + let worker_view = spawn_view.clone(); + let transfer_concurrency = req.transfer_concurrency; + spawn_view.spawn("external_get_key_singleflight", async move { + let start_result = { + let worker_inner = worker_view.client_kv_api().inner(); + batch_get_start_with_local_reserve_targets(worker_inner, &leader_keys).await + }; + match start_result { + Ok(start_resp) => { + assert_eq!( + start_resp.items.len(), + leaders.len(), + "validated BatchGetStart response must match leader count" + ); + for (op, item) in leaders.iter().zip(start_resp.items) { + publish_external_get_key_started(op, item); + } + finish_external_get_key_leaders(worker_view, leaders, transfer_concurrency) + .await; + } + Err(err) => { + let worker_inner = worker_view.client_kv_api().inner(); + for op in &leaders { + publish_external_get_key_failed(worker_inner, op, &err); + } + } + } + }); } - let mut item_slots: Vec> = local_memory_infos - .into_iter() - .map(|memory_info| { - memory_info.map(|memory_info| ExternalGetStartOwnerItem::Local { memory_info }) - }) - .collect(); - let (missing_indices, missing_keys) = - collect_external_get_start_missing(&req.keys, &item_slots); - - if !missing_keys.is_empty() { - let start_resp = batch_get_start_with_reserve_pressure_retry(inner, &missing_keys).await?; - for ((idx, key), item) in missing_indices - .into_iter() - .zip(missing_keys.into_iter()) - .zip(start_resp.items.into_iter()) - { - item_slots[idx] = Some(ExternalGetStartOwnerItem::Started { key, item }); + let mut item_codes = Vec::with_capacity(items.len()); + for item in &items { + match item { + ExternalGetStartOwnerItem::Local { .. } => item_codes.push((OK, String::new())), + ExternalGetStartOwnerItem::Shared { interest } => { + match wait_external_get_key_start_code(interest.op().clone()).await { + Ok(code) => item_codes.push(code), + Err(err) => return Err(err), + } + } } } - let items = item_slots - .into_iter() - .map(|item| { - item.ok_or_else(|| { - KvError::Api(ApiError::Unknown { - detail: "external_batch_get_start item slot was not populated".to_string(), - }) - }) - }) - .collect::>>()?; - let item_codes = items - .iter() - .map(|item| match item { - ExternalGetStartOwnerItem::Local { .. } => (OK, String::new()), - ExternalGetStartOwnerItem::Started { item, .. } => { - (item.error_code, item.error_json.clone()) - } - }) - .collect::>(); let (raw_prefix_hit_len, first_miss_index, first_error_kind) = compute_external_get_start_raw_prefix(&item_codes); let transferable_len = compute_external_get_start_transfer_prefix( @@ -914,19 +2117,8 @@ async fn prepare_external_get_start_shared_op( error_kind ); } - - let revoke_get_ids = items - .iter() - .skip(transferable_len) - .filter_map(|item| match item { - ExternalGetStartOwnerItem::Started { item, .. } if item.error_code == OK => { - Some(item.get_id) - } - _ => None, - }) - .collect::>(); - if !revoke_get_ids.is_empty() { - inner.batch_get_revoke(revoke_get_ids).await?; + for (idx, item) in items.iter_mut().enumerate() { + decide_external_get_key_item(item, idx < transferable_len); } let transfer_keys = req.keys[..transferable_len].to_vec(); @@ -1373,115 +2565,45 @@ impl HandlerForExternalClient for ClientKvApi { let group_lens = normalize_external_get_start_group_lens(req.keys.len(), req.atomic_group_lens.clone())?; - let dedup_key = ExternalGetStartDedupKey { - keys: req.keys.clone(), - atomic_group_lens: group_lens.clone(), - prefix_best_effort: req.prefix_best_effort, - }; - let (shared_op, is_creator) = match inner.external_get_start_by_key.entry(dedup_key.clone()) - { - Entry::Occupied(entry) => { - let shared_op = entry.get().clone(); - register_external_get_start_waiter(&shared_op); - (shared_op, false) - } - Entry::Vacant(entry) => { - let shared_op = Arc::new(ExternalGetStartSharedOp::new( - dedup_key, - req.transfer_concurrency, - )); - entry.insert(shared_op.clone()); - (shared_op, true) - } - }; - - if is_creator { - match prepare_external_get_start_shared_op(inner, &req, &group_lens).await { - Ok((prefix, transfer_keys, transfer_items)) => { - let inline_memory_infos = (transfer_items.len() == req.keys.len()) - .then(|| collect_all_local_external_get_start_infos(&transfer_items)) - .flatten(); - let inline_local = inline_memory_infos.is_some(); - if let Some(memory_infos) = inline_memory_infos { - shared_op - .inline_local_memory_infos - .set(memory_infos) - .unwrap_or_else(|_| { - panic!("external get_start inline plan initialized twice") - }); - } - { - let mut state = shared_op.state.lock(); - state.phase = ExternalGetStartSharedPhase::Running { - prefix: prefix.clone(), - keys: transfer_keys.clone(), - }; - } - shared_op.notify.notify_waiters(); - - if !inline_local { - let transfer_shared_op = shared_op.clone(); - let transfer_concurrency = shared_op.transfer_concurrency; - let spawn_view = inner.view.clone_view(); - let transfer_view = spawn_view.clone(); - spawn_view.spawn("external_get_start_transfer", async move { - let transfer_result = finish_external_get_start_transfer( - transfer_view, - transfer_items, - transfer_concurrency, - ) - .await; - publish_external_get_start_ready( - &transfer_shared_op, - transfer_keys, - transfer_result, - ); - }); - } - } - Err(err) => { - publish_external_get_start_failed(&shared_op, &err); - release_external_get_start_waiter(inner, &shared_op); - return Err(err); - } - } - } - - let prefix = match wait_external_get_start_prefix(shared_op.clone()).await { - Ok(prefix) => prefix, - Err(err) => { - release_external_get_start_waiter(inner, &shared_op); - return Err(err); - } - }; + let (prefix, transfer_keys, transfer_items) = + prepare_external_get_batch_plan(inner, &req, &group_lens).await?; let handle = inner .next_external_get_start_handle .fetch_add(1, Ordering::Relaxed); - let transfer_plan = if let Some(memory_infos) = shared_op.inline_local_memory_infos.get() { + let inline_memory_infos = (transfer_items.len() == req.keys.len()) + .then(|| collect_all_local_external_get_start_infos(&transfer_items)) + .flatten(); + let transfer_plan = if let Some(memory_infos) = inline_memory_infos { assert_eq!( memory_infos.len(), req.keys.len(), "inline local get_start plan must cover the full request" ); let items = memory_infos - .iter() + .into_iter() .map(|memory_info| ExternalBatchGetItemResp { error_code: OK, error_json: String::new(), external_memholder_info: Some( - inner.install_external_get_holding(&req.req_node_id, memory_info.clone()), + inner.install_external_get_holding(&req.req_node_id, memory_info), ), }) .collect(); - release_external_get_start_waiter(inner, &shared_op); ExternalBatchGetStartTransferPlan::InlineLocal { items } } else { inner.external_get_start_registry.insert( handle, - Arc::new(ExternalGetStartEntry { + ExternalGetStartEntry { req_node_id: req.req_node_id.clone(), - shared_op, - }), + requester_node_start_time: inner + .view + .cluster_manager() + .get_member_info_cached(&req.req_node_id) + .map(|member| member.node_start_time), + keys: transfer_keys, + items: transfer_items, + created_at: Instant::now(), + }, ); ExternalBatchGetStartTransferPlan::OwnerRpc }; @@ -1520,62 +2642,46 @@ impl HandlerForExternalClient for ClientKvApi { req.req_node_id ); } - let shared_op = entry.shared_op.clone(); - let result = match wait_external_get_start_transfer(shared_op.clone()).await { - Ok((keys, shared_items)) => { - if shared_items.len() != keys.len() { - Err(KvError::Api(ApiError::Unknown { - detail: format!( - "external_batch_get_transfer shared result length mismatch: expected={} got={}", - keys.len(), - shared_items.len() - ), - })) - } else { - let mut items = Vec::with_capacity(shared_items.len()); - for (key, item_result) in keys.iter().zip(shared_items.into_iter()) { - match item_result { - ExternalGetStartSharedItemResult::Hit { memholder } => { - let external_memholder_info = inner.install_external_get_holding( - &req.req_node_id, - memholder.memory_info(), - ); - items.push(ExternalBatchGetItemResp { - error_code: OK, - error_json: String::new(), - external_memholder_info: Some(external_memholder_info), - }); - } - ExternalGetStartSharedItemResult::Miss => { - items.push(ExternalBatchGetItemResp { - error_code: codes_api::API_KEY_NOT_FOUND, - error_json: format!("Key not found: {}", key), - external_memholder_info: None, - }); - } - ExternalGetStartSharedItemResult::Error { - error_code, - error_json, - } => { - items.push(ExternalBatchGetItemResp { - error_code, - error_json, - external_memholder_info: None, - }); - } - } - } - Ok(ExternalBatchGetTransferResp { - items, + let keys = entry.keys; + let transfer_results = + finish_external_get_start_transfer(inner.view.clone_view(), entry.items, 0).await?; + if transfer_results.len() != keys.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external_batch_get_transfer result length mismatch: expected={} got={}", + keys.len(), + transfer_results.len() + ), + })); + } + let mut items = Vec::with_capacity(transfer_results.len()); + for (key, item_result) in keys.iter().zip(transfer_results) { + match item_result { + Ok(Some((memholder, _))) => { + let external_memholder_info = inner + .install_external_get_holding(&req.req_node_id, memholder.memory_info()); + items.push(ExternalBatchGetItemResp { error_code: OK, error_json: String::new(), - }) + external_memholder_info: Some(external_memholder_info), + }); } + Ok(None) => items.push(ExternalBatchGetItemResp { + error_code: codes_api::API_KEY_NOT_FOUND, + error_json: format!("Key not found: {}", key), + external_memholder_info: None, + }), + Err(err) => items.push(ExternalBatchGetItemResp { + external_memholder_info: None, + ..ExternalBatchGetItemResp::from_error(&err) + }), } - Err(err) => Err(err), - }; - release_external_get_start_waiter(inner, &shared_op); - result + } + Ok(ExternalBatchGetTransferResp { + items, + error_code: OK, + error_json: String::new(), + }) } async fn external_batch_get_cancel( @@ -1601,7 +2707,7 @@ impl HandlerForExternalClient for ClientKvApi { req.req_node_id ); } - release_external_get_start_waiter(inner, &entry.shared_op); + drop(entry); } } ExternalBatchGetCancelPlan::InlineLocal { holder_ids } => { @@ -1626,6 +2732,12 @@ impl HandlerForExternalClient for ClientKvApi { let started_at = Instant::now(); self.validate_requester_owner_status_updated(req.started_time)?; + // Register before the master PutStart RPC. Reclaim Prepare checks this + // counter under the same per-key key-control shard, closing the old gap + // between master admission and insertion into external_pending_puts. + let pending_fence = inner.acquire_external_pending_put_fence(&req.key)?; + let mut pending_fence_claim = + ExternalPutStartFenceClaim::new(inner.view.clone_view(), pending_fence); let put_start_started_at = Instant::now(); let source_node_id = if self.is_side_transfer_worker() { @@ -1649,10 +2761,15 @@ impl HandlerForExternalClient for ClientKvApi { e })?; // Ensure master responded OK before using returned addresses - crate::rpcresp_kvresult_convert::try_from_code( + if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( put_start_resp.error_code, put_start_resp.error_json.clone(), - )?; + ) { + // An application response proves the master did not admit this Put; + // no uncertainty quarantine is required. + pending_fence_claim.release_after_definite_response(); + return Err(err); + } tracing::debug!( "handle external put start for key: {}, len: {}", req.key, @@ -1709,6 +2826,7 @@ impl HandlerForExternalClient for ClientKvApi { local_reserve_slot: None, local_reserve_slot_size: None, atomic_group: None, + _pending_fence: pending_fence_claim.take_for_pending_context(), }, ); if !is_local_target { @@ -1789,39 +2907,33 @@ impl HandlerForExternalClient for ClientKvApi { })); } - let mut reserved_keys = Vec::with_capacity(req.items.len()); + let mut pending_fences = Vec::with_capacity(req.items.len()); for item in &req.items { - if let Err(err) = inner.reserve_external_local_first_put_key( + let pending_fence = match inner.reserve_external_local_first_put_key( &item.key, item.reject_if_inflight_same_key, item.reject_if_exist_same_key, ) { - external_local_first_release_keys(inner, &reserved_keys); - let items = req - .items - .iter() - .map(|_| external_local_first_error_item(&err)) - .collect(); - return Ok(ExternalBatchPutStartResp { - items, - error_code: OK, - error_json: String::new(), - }); - } - reserved_keys.push(item.key.clone()); + Ok(pending_fence) => pending_fence, + Err(err) => { + let items = req + .items + .iter() + .map(|_| external_local_first_error_item(&err)) + .collect(); + return Ok(ExternalBatchPutStartResp { + items, + error_code: OK, + error_json: String::new(), + }); + } + }; + pending_fences.push(pending_fence); } - let slot_lease = match inner - .owner_claim_local_reserve_slot_lease(value_len, req.items.len()) - .await - { - Ok(slot_lease) => slot_lease, - Err(err) => { - external_local_first_release_keys(inner, &reserved_keys); - return Err(err); - } - }; - let self_node_id = inner.view.cluster_manager().get_self_info().id.clone(); + // Finish every fallible, purely logical derivation before claiming + // physical slots. The per-key fences above are RAII-owned, so any + // error or cancellation before cache insertion releases both counters. let put_ids = req .items .iter() @@ -1836,11 +2948,29 @@ impl HandlerForExternalClient for ClientKvApi { let atomic_groups = build_put_atomic_group_assignments(&keys_and_put_ids, &atomic_group_lens) .map_err(|detail| KvError::Api(ApiError::InvalidArgument { detail }))?; + + let slot_lease = match inner + .owner_claim_local_reserve_slot_lease(value_len, req.items.len()) + .await + { + Ok(slot_lease) => slot_lease, + Err(err) => return Err(err), + }; + let self_node_id = inner.view.cluster_manager().get_self_info().id.clone(); + let slot_size = slot_lease.slot_size; + for (slot_ref, pending_fence) in slot_lease.slots.iter().zip(&pending_fences) { + pending_fence.attach_local_slot_lease(OwnerLocalReserveSlotLease { + value_len, + slot_size, + slots: vec![slot_ref.clone()], + }); + } let mut items = Vec::with_capacity(req.items.len()); - for (idx, (req_item, slot_ref)) in req + for (idx, ((req_item, slot_ref), pending_fence)) in req .items .into_iter() .zip(slot_lease.slots.into_iter()) + .zip(pending_fences.into_iter()) .enumerate() { let put_id = put_ids[idx]; @@ -1857,8 +2987,9 @@ impl HandlerForExternalClient for ClientKvApi { preferred_sub_cluster: req_item.preferred_sub_cluster.clone(), replica_target: None, local_reserve_slot: Some(slot_ref.clone()), - local_reserve_slot_size: Some(slot_lease.slot_size), + local_reserve_slot_size: Some(slot_size), atomic_group: atomic_groups[idx].clone(), + _pending_fence: pending_fence, }, ); tracing::debug!( @@ -1914,45 +3045,53 @@ impl HandlerForExternalClient for ClientKvApi { return Ok(ExternalPutTransferEndResp::from_error(&err)); }; - let pending_ctx = inner - .external_pending_puts - .get(&(req.key.clone(), put_id.0, put_id.1)) - .map(|ctx| ctx.clone()); - let replica_target = pending_ctx - .as_ref() - .and_then(|ctx| ctx.replica_target.clone()); - let admitted_replica_task = pending_ctx - .as_ref() - .map(|ctx| ctx.make_replica_task) - .unwrap_or(false); + let pending_ctx = match require_external_pending_put_ctx( + inner, + "external_put_transfer_end", + &req.key, + put_id, + ) { + Ok(ctx) => ctx, + Err(err) => { + best_effort_revoke_missing_external_pending_ctx( + inner, + "external_put_transfer_end", + &req.key, + put_id, + ) + .await; + return Ok(ExternalPutTransferEndResp::from_error(&err)); + } + }; + let replica_target = pending_ctx.replica_target.clone(); + let admitted_replica_task = pending_ctx.make_replica_task; let self_node_id = inner.view.cluster_manager().get_self_info().id.clone(); let req_remote_target = req .peer_id .as_deref() .is_some_and(|peer| peer != self_node_id.as_str()); - let has_remote_target = pending_ctx - .as_ref() - .and_then(|ctx| ctx.peer_id.as_ref()) - .is_some(); - if pending_ctx.is_some() && req_remote_target != has_remote_target { + let has_remote_target = pending_ctx.peer_id.is_some(); + if req_remote_target != has_remote_target { let err = KvError::Api(ApiError::InvalidArgument { detail: format!( "external_put_transfer_end peer_id mismatches pending ctx: key={} put_id=({},{}) req_remote_target={} ctx_remote_target={}", req.key, put_id.0, put_id.1, req_remote_target, has_remote_target ), }); - if let Err(revoke_err) = inner.put_revoke(&req.key, put_id).await { - tracing::warn!( - "external_put_transfer_end put_revoke failed after peer_id mismatch: key={} put_id=({},{}) err={}", + match inner.put_revoke(&req.key, put_id).await { + Ok(_) => { + inner + .external_pending_puts + .invalidate(&(req.key.clone(), put_id.0, put_id.1)) + } + Err(revoke_err) => tracing::warn!( + "external_put_transfer_end put_revoke failed after peer_id mismatch; pending fence retained: key={} put_id=({},{}) err={}", req.key, put_id.0, put_id.1, revoke_err - ); + ), } - inner - .external_pending_puts - .invalidate(&(req.key.clone(), put_id.0, put_id.1)); return Ok(ExternalPutTransferEndResp::from_error(&err)); } let put_transfer_total_us = 0; @@ -1993,24 +3132,26 @@ impl HandlerForExternalClient for ClientKvApi { "external_put_transfer_end", &req.key, put_id, - pending_ctx.as_ref(), + &pending_ctx, req.src_offset, req.len, ) { Ok(publish) => publish, Err(err) => { - if let Err(revoke_err) = inner.put_revoke(&req.key, put_id).await { - tracing::warn!( - "external_put_transfer_end put_revoke failed after local cache publish precheck error: key={} put_id=({},{}) err={}", + match inner.put_revoke(&req.key, put_id).await { + Ok(_) => inner.external_pending_puts.invalidate(&( + req.key.clone(), + put_id.0, + put_id.1, + )), + Err(revoke_err) => tracing::warn!( + "external_put_transfer_end put_revoke failed after local cache publish precheck error; pending fence retained: key={} put_id=({},{}) err={}", req.key, put_id.0, put_id.1, revoke_err - ); + ), } - inner - .external_pending_puts - .invalidate(&(req.key.clone(), put_id.0, put_id.1)); return Ok(crate::rpcresp_kvresult_convert::FromError::from_error(&err)); } }; @@ -2021,9 +3162,12 @@ impl HandlerForExternalClient for ClientKvApi { Ok(end) => end, Err(e) => { tracing::error!("Failed to end put operation: {}", e); - inner - .external_pending_puts - .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + tracing::warn!( + "external_put_transfer_end PutDone was not terminal; pending fence retained for retry: key={} put_id=({},{})", + req.key, + put_id.0, + put_id.1 + ); return Ok(crate::rpcresp_kvresult_convert::FromError::from_error(&e)); } }; @@ -2037,9 +3181,12 @@ impl HandlerForExternalClient for ClientKvApi { req.key, put_id.0, put_id.1 ), }); - inner - .external_pending_puts - .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + tracing::warn!( + "external_put_transfer_end retained pending fence after terminal response omitted local holder: key={} put_id=({},{})", + req.key, + put_id.0, + put_id.1 + ); return Ok(crate::rpcresp_kvresult_convert::FromError::from_error(&err)); }; inner @@ -2128,12 +3275,17 @@ impl HandlerForExternalClient for ClientKvApi { local_cache_publish: LocalCommittedCachePublish, make_replica_task: bool, replica_target: Option, + // Keep the per-key reclaim fence alive until the master's terminal + // response has been applied to the owner-local index. + _pending_ctx: ExternalPendingPutCtx, } let mut results: Vec> = (0..req.items.len()).map(|_| None).collect(); let mut done_pending = Vec::new(); let mut revoke_pending = Vec::new(); + let mut local_publish_items = Vec::new(); + let mut local_publish_contexts = Vec::new(); for (idx, item) in req.items.into_iter().enumerate() { let Some(put_id) = item.put_id else { @@ -2148,81 +3300,99 @@ impl HandlerForExternalClient for ClientKvApi { results[idx] = Some(ExternalBatchPutTransferEndItemResp::from_error(&err)); continue; }; - - let pending_ctx = inner - .external_pending_puts - .get(&(item.key.clone(), put_id.0, put_id.1)) - .map(|ctx| ctx.clone()); - if let Some(ctx) = pending_ctx.as_ref() { - if ctx.local_reserve_slot.is_some() { - if item.peer_id.is_some() { - let err = KvError::Api(ApiError::InvalidArgument { - detail: format!( - "external_batch_put_transfer_end local-first item must be local target: key={} put_id=({},{})", - item.key, put_id.0, put_id.1 - ), - }); - results[idx] = Some(ExternalBatchPutTransferEndItemResp::from_error(&err)); + + let pending_ctx = match require_external_pending_put_ctx( + inner, + "external_batch_put_transfer_end", + &item.key, + put_id, + ) { + Ok(ctx) => ctx, + Err(err) => { + results[idx] = Some(ExternalBatchPutTransferEndItemResp::from_error(&err)); + revoke_pending.push(BatchPutRevokeItemReq { + key: item.key.clone(), + put_id, + }); + continue; + } + }; + if pending_ctx.local_reserve_slot.is_some() { + if item.peer_id.is_some() { + let err = KvError::Api(ApiError::InvalidArgument { + detail: format!( + "external_batch_put_transfer_end local-first item must be local target: key={} put_id=({},{})", + item.key, put_id.0, put_id.1 + ), + }); + results[idx] = Some(ExternalBatchPutTransferEndItemResp::from_error(&err)); + release_external_local_first_pending_slot( + inner, + &pending_ctx, + "external_batch_put_transfer_end", + &item.key, + put_id, + ) + .await; + inner + .external_pending_puts + .invalidate(&(item.key.clone(), put_id.0, put_id.1)); + continue; + } + match commit_external_local_first_pending( + inner, + &item.key, + put_id, + &pending_ctx, + item.src_offset, + item.len, + "external_batch_put_transfer_end", + ) + .await + { + Ok(committed_slot) => { + inner.record_put_locality(false, item.len, 0); inner.external_pending_puts.invalidate(&( item.key.clone(), put_id.0, put_id.1, )); - inner.release_external_local_first_put_key(&item.key); - continue; + local_publish_items.push(OwnerLocalPublishItem { + key: item.key.clone(), + put_id, + value_len: item.len, + lease_id: item.lease_id, + committed_slot, + make_replica_task: pending_ctx.make_replica_task, + preferred_sub_cluster: pending_ctx.preferred_sub_cluster.clone(), + atomic_group: pending_ctx.atomic_group.clone(), + }); + local_publish_contexts.push(pending_ctx); + results[idx] = Some(ExternalBatchPutTransferEndItemResp { + error_code: OK, + error_json: String::new(), + }); } - match commit_external_local_first_pending( - inner, - &item.key, - put_id, - ctx, - item.src_offset, - item.len, - "external_batch_put_transfer_end", - ) - .await - { - Ok(committed_slot) => { - inner.record_put_locality(false, item.len, 0); - inner.external_pending_puts.invalidate(&( - item.key.clone(), - put_id.0, - put_id.1, - )); - inner.release_external_local_first_put_key(&item.key); - spawn_external_local_first_publish( - inner, - item.key.clone(), - put_id, - item.lease_id, - committed_slot, - ctx.make_replica_task, - ctx.preferred_sub_cluster.clone(), - ctx.atomic_group.clone(), - ); - results[idx] = Some(ExternalBatchPutTransferEndItemResp { - error_code: OK, - error_json: String::new(), - }); - } - Err(err) => { - inner.external_pending_puts.invalidate(&( - item.key.clone(), - put_id.0, - put_id.1, - )); - inner.release_external_local_first_put_key(&item.key); - results[idx] = - Some(ExternalBatchPutTransferEndItemResp::from_error(&err)); - } + Err(err) => { + release_external_local_first_pending_slot( + inner, + &pending_ctx, + "external_batch_put_transfer_end", + &item.key, + put_id, + ) + .await; + inner.external_pending_puts.invalidate(&( + item.key.clone(), + put_id.0, + put_id.1, + )); + results[idx] = Some(ExternalBatchPutTransferEndItemResp::from_error(&err)); } - continue; } + continue; } - let has_remote_append = pending_ctx - .as_ref() - .and_then(|ctx| ctx.peer_id.as_ref()) - .is_some(); + let has_remote_append = pending_ctx.peer_id.is_some(); if item.peer_id.is_some() || has_remote_append { let err = KvError::Api(ApiError::InvalidArgument { detail: format!( @@ -2239,16 +3409,13 @@ impl HandlerForExternalClient for ClientKvApi { key: item.key.clone(), put_id, }); - inner - .external_pending_puts - .invalidate(&(item.key.clone(), put_id.0, put_id.1)); continue; } let local_cache_publish = match local_committed_cache_publish( "external_batch_put_transfer_end", &item.key, put_id, - pending_ctx.as_ref(), + &pending_ctx, item.src_offset, item.len, ) { @@ -2259,9 +3426,6 @@ impl HandlerForExternalClient for ClientKvApi { key: item.key.clone(), put_id, }); - inner - .external_pending_puts - .invalidate(&(item.key.clone(), put_id.0, put_id.1)); continue; } }; @@ -2273,22 +3437,42 @@ impl HandlerForExternalClient for ClientKvApi { len: item.len, put_locality: Some((false, 0)), local_cache_publish, - make_replica_task: pending_ctx - .as_ref() - .map(|ctx| ctx.make_replica_task) - .unwrap_or(false), - replica_target: pending_ctx - .as_ref() - .and_then(|ctx| ctx.replica_target.clone()), + make_replica_task: pending_ctx.make_replica_task, + replica_target: pending_ctx.replica_target.clone(), + _pending_ctx: pending_ctx, }); } + if !local_publish_items.is_empty() { + spawn_external_local_first_publish(inner, local_publish_items, local_publish_contexts); + } + if !revoke_pending.is_empty() { - if let Err(err) = inner.batch_put_revoke(revoke_pending).await { - tracing::warn!( - "external_batch_put_transfer_end batch_put_revoke failed after precheck errors: {}", + let requested = revoke_pending.clone(); + match inner.batch_put_revoke(revoke_pending).await { + Ok(response) if response.items.len() == requested.len() => { + for (request, response) in requested.into_iter().zip(response.items) { + if response.key == request.key + && response.put_id == request.put_id + && response.error_code == OK + { + inner.external_pending_puts.invalidate(&( + request.key, + request.put_id.0, + request.put_id.1, + )); + } + } + } + Ok(response) => tracing::warn!( + "external_batch_put_transfer_end batch_put_revoke response length mismatch: expected={} got={}", + requested.len(), + response.items.len() + ), + Err(err) => tracing::warn!( + "external_batch_put_transfer_end batch_put_revoke failed after precheck errors; pending fences retained for retry: {}", err - ); + ), } } @@ -2348,11 +3532,6 @@ impl HandlerForExternalClient for ClientKvApi { } for (pending, done_item) in done_pending.into_iter().zip(done_resp.items.into_iter()) { - inner.external_pending_puts.invalidate(&( - pending.key.clone(), - pending.put_id.0, - pending.put_id.1, - )); if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( done_item.error_code, done_item.error_json.clone(), @@ -2380,6 +3559,11 @@ impl HandlerForExternalClient for ClientKvApi { holder_id, ) .await?; + inner.external_pending_puts.invalidate(&( + pending.key.clone(), + pending.put_id.0, + pending.put_id.1, + )); if pending.make_replica_task { let target = pending .replica_target @@ -2436,14 +3620,25 @@ impl HandlerForExternalClient for ClientKvApi { ); return Ok(ExternalPutCommitResp::from_error(&err)); }; - let pending_ctx = inner - .external_pending_puts - .get(&(req.key.clone(), put_id.0, put_id.1)) - .map(|ctx| ctx.clone()); - let has_remote_append = pending_ctx - .as_ref() - .and_then(|ctx| ctx.peer_id.as_ref()) - .is_some(); + let pending_ctx = match require_external_pending_put_ctx( + inner, + "external_put_commit", + &req.key, + put_id, + ) { + Ok(ctx) => ctx, + Err(err) => { + best_effort_revoke_missing_external_pending_ctx( + inner, + "external_put_commit", + &req.key, + put_id, + ) + .await; + return Ok(ExternalPutCommitResp::from_error(&err)); + } + }; + let has_remote_append = pending_ctx.peer_id.is_some(); if req.remote_target || has_remote_append { let err = KvError::Api(ApiError::InvalidArgument { detail: format!( @@ -2451,51 +3646,50 @@ impl HandlerForExternalClient for ClientKvApi { req.key, put_id.0, put_id.1, req.remote_target, has_remote_append ), }); - if let Err(revoke_err) = inner.put_revoke(&req.key, put_id).await { - tracing::warn!( - "external_put_commit put_revoke failed after remote primary target: key={} put_id=({},{}) err={}", + match inner.put_revoke(&req.key, put_id).await { + Ok(_) => { + inner + .external_pending_puts + .invalidate(&(req.key.clone(), put_id.0, put_id.1)) + } + Err(revoke_err) => tracing::warn!( + "external_put_commit put_revoke failed after remote primary target; pending fence retained: key={} put_id=({},{}) err={}", req.key, put_id.0, put_id.1, revoke_err - ); + ), } - inner - .external_pending_puts - .invalidate(&(req.key.clone(), put_id.0, put_id.1)); return Ok(ExternalPutCommitResp::from_error(&err)); } - let replica_target = pending_ctx - .as_ref() - .and_then(|ctx| ctx.replica_target.clone()); - let admitted_replica_task = pending_ctx - .as_ref() - .map(|ctx| ctx.make_replica_task) - .unwrap_or(false); + let replica_target = pending_ctx.replica_target.clone(); + let admitted_replica_task = pending_ctx.make_replica_task; let end_started_at = Instant::now(); let local_cache_publish = match local_committed_cache_publish( "external_put_commit", &req.key, put_id, - pending_ctx.as_ref(), + &pending_ctx, req.src_offset, req.len, ) { Ok(publish) => publish, Err(err) => { - if let Err(revoke_err) = inner.put_revoke(&req.key, put_id).await { - tracing::warn!( - "external_put_commit put_revoke failed after local cache publish precheck error: key={} put_id=({},{}) err={}", + match inner.put_revoke(&req.key, put_id).await { + Ok(_) => inner.external_pending_puts.invalidate(&( + req.key.clone(), + put_id.0, + put_id.1, + )), + Err(revoke_err) => tracing::warn!( + "external_put_commit put_revoke failed after local cache publish precheck error; pending fence retained: key={} put_id=({},{}) err={}", req.key, put_id.0, put_id.1, revoke_err - ); + ), } - inner - .external_pending_puts - .invalidate(&(req.key.clone(), put_id.0, put_id.1)); return Ok(ExternalPutCommitResp::from_error(&err)); } }; @@ -2505,9 +3699,13 @@ impl HandlerForExternalClient for ClientKvApi { { Ok(end) => end, Err(e) => { - inner - .external_pending_puts - .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + tracing::warn!( + "external_put_commit PutDone was not terminal; pending fence retained for retry: key={} put_id=({},{}) err={}", + req.key, + put_id.0, + put_id.1, + e + ); return Ok(ExternalPutCommitResp::from_error(&e)); } }; @@ -2520,9 +3718,12 @@ impl HandlerForExternalClient for ClientKvApi { req.key, put_id.0, put_id.1 ), }); - inner - .external_pending_puts - .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + tracing::warn!( + "external_put_commit retained pending fence after terminal response omitted local holder: key={} put_id=({},{})", + req.key, + put_id.0, + put_id.1 + ); return Ok(ExternalPutCommitResp::from_error(&err)); }; inner @@ -2602,12 +3803,15 @@ impl HandlerForExternalClient for ClientKvApi { local_cache_publish: LocalCommittedCachePublish, make_replica_task: bool, replica_target: Option, + _pending_ctx: ExternalPendingPutCtx, } let mut results: Vec> = (0..req.items.len()).map(|_| None).collect(); let mut done_pending = Vec::new(); let mut revoke_pending = Vec::new(); + let mut local_publish_items = Vec::new(); + let mut local_publish_contexts = Vec::new(); for (idx, item) in req.items.into_iter().enumerate() { let Some(put_id) = item.put_id else { @@ -2622,79 +3826,98 @@ impl HandlerForExternalClient for ClientKvApi { results[idx] = Some(ExternalBatchPutCommitItemResp::from_error(&err)); continue; }; - let pending_ctx = inner - .external_pending_puts - .get(&(item.key.clone(), put_id.0, put_id.1)) - .map(|ctx| ctx.clone()); - if let Some(ctx) = pending_ctx.as_ref() { - if ctx.local_reserve_slot.is_some() { - if item.remote_target { - let err = KvError::Api(ApiError::InvalidArgument { - detail: format!( - "external_batch_put_commit local-first item must be local target: key={} put_id=({},{})", - item.key, put_id.0, put_id.1 - ), - }); - results[idx] = Some(ExternalBatchPutCommitItemResp::from_error(&err)); + let pending_ctx = match require_external_pending_put_ctx( + inner, + "external_batch_put_commit", + &item.key, + put_id, + ) { + Ok(ctx) => ctx, + Err(err) => { + results[idx] = Some(ExternalBatchPutCommitItemResp::from_error(&err)); + revoke_pending.push(BatchPutRevokeItemReq { + key: item.key.clone(), + put_id, + }); + continue; + } + }; + if pending_ctx.local_reserve_slot.is_some() { + if item.remote_target { + let err = KvError::Api(ApiError::InvalidArgument { + detail: format!( + "external_batch_put_commit local-first item must be local target: key={} put_id=({},{})", + item.key, put_id.0, put_id.1 + ), + }); + results[idx] = Some(ExternalBatchPutCommitItemResp::from_error(&err)); + release_external_local_first_pending_slot( + inner, + &pending_ctx, + "external_batch_put_commit", + &item.key, + put_id, + ) + .await; + inner + .external_pending_puts + .invalidate(&(item.key.clone(), put_id.0, put_id.1)); + continue; + } + match commit_external_local_first_pending( + inner, + &item.key, + put_id, + &pending_ctx, + item.src_offset, + item.len, + "external_batch_put_commit", + ) + .await + { + Ok(committed_slot) => { + inner.record_put_locality(false, item.len, 0); inner.external_pending_puts.invalidate(&( item.key.clone(), put_id.0, put_id.1, )); - inner.release_external_local_first_put_key(&item.key); - continue; + local_publish_items.push(OwnerLocalPublishItem { + key: item.key.clone(), + put_id, + value_len: item.len, + lease_id: item.lease_id, + committed_slot, + make_replica_task: pending_ctx.make_replica_task, + preferred_sub_cluster: pending_ctx.preferred_sub_cluster.clone(), + atomic_group: pending_ctx.atomic_group.clone(), + }); + local_publish_contexts.push(pending_ctx); + results[idx] = Some(ExternalBatchPutCommitItemResp { + error_code: OK, + error_json: String::new(), + }); } - match commit_external_local_first_pending( - inner, - &item.key, - put_id, - ctx, - item.src_offset, - item.len, - "external_batch_put_commit", - ) - .await - { - Ok(committed_slot) => { - inner.record_put_locality(false, item.len, 0); - inner.external_pending_puts.invalidate(&( - item.key.clone(), - put_id.0, - put_id.1, - )); - inner.release_external_local_first_put_key(&item.key); - spawn_external_local_first_publish( - inner, - item.key.clone(), - put_id, - item.lease_id, - committed_slot, - ctx.make_replica_task, - ctx.preferred_sub_cluster.clone(), - ctx.atomic_group.clone(), - ); - results[idx] = Some(ExternalBatchPutCommitItemResp { - error_code: OK, - error_json: String::new(), - }); - } - Err(err) => { - inner.external_pending_puts.invalidate(&( - item.key.clone(), - put_id.0, - put_id.1, - )); - inner.release_external_local_first_put_key(&item.key); - results[idx] = Some(ExternalBatchPutCommitItemResp::from_error(&err)); - } + Err(err) => { + release_external_local_first_pending_slot( + inner, + &pending_ctx, + "external_batch_put_commit", + &item.key, + put_id, + ) + .await; + inner.external_pending_puts.invalidate(&( + item.key.clone(), + put_id.0, + put_id.1, + )); + results[idx] = Some(ExternalBatchPutCommitItemResp::from_error(&err)); } - continue; } + continue; } - let has_remote_append = pending_ctx - .as_ref() - .and_then(|ctx| ctx.peer_id.as_ref()) - .is_some(); + let has_remote_append = pending_ctx.peer_id.is_some(); if item.remote_target || has_remote_append { let err = KvError::Api(ApiError::InvalidArgument { detail: format!( @@ -2707,16 +3930,13 @@ impl HandlerForExternalClient for ClientKvApi { key: item.key.clone(), put_id, }); - inner - .external_pending_puts - .invalidate(&(item.key.clone(), put_id.0, put_id.1)); continue; }; let local_cache_publish = match local_committed_cache_publish( "external_batch_put_commit", &item.key, put_id, - pending_ctx.as_ref(), + &pending_ctx, item.src_offset, item.len, ) { @@ -2727,9 +3947,6 @@ impl HandlerForExternalClient for ClientKvApi { key: item.key.clone(), put_id, }); - inner - .external_pending_puts - .invalidate(&(item.key.clone(), put_id.0, put_id.1)); continue; } }; @@ -2739,22 +3956,42 @@ impl HandlerForExternalClient for ClientKvApi { put_id, lease_id: item.lease_id, local_cache_publish, - make_replica_task: pending_ctx - .as_ref() - .map(|ctx| ctx.make_replica_task) - .unwrap_or(false), - replica_target: pending_ctx - .as_ref() - .and_then(|ctx| ctx.replica_target.clone()), + make_replica_task: pending_ctx.make_replica_task, + replica_target: pending_ctx.replica_target.clone(), + _pending_ctx: pending_ctx, }); } + if !local_publish_items.is_empty() { + spawn_external_local_first_publish(inner, local_publish_items, local_publish_contexts); + } + if !revoke_pending.is_empty() { - if let Err(err) = inner.batch_put_revoke(revoke_pending).await { - tracing::warn!( - "external_batch_put_commit batch_put_revoke failed after local cache publish precheck errors: {}", + let requested = revoke_pending.clone(); + match inner.batch_put_revoke(revoke_pending).await { + Ok(response) if response.items.len() == requested.len() => { + for (request, response) in requested.into_iter().zip(response.items) { + if response.key == request.key + && response.put_id == request.put_id + && response.error_code == OK + { + inner.external_pending_puts.invalidate(&( + request.key, + request.put_id.0, + request.put_id.1, + )); + } + } + } + Ok(response) => tracing::warn!( + "external_batch_put_commit batch_put_revoke response length mismatch: expected={} got={}", + requested.len(), + response.items.len() + ), + Err(err) => tracing::warn!( + "external_batch_put_commit batch_put_revoke failed after precheck errors; pending fences retained for retry: {}", err - ); + ), } } @@ -2811,11 +4048,6 @@ impl HandlerForExternalClient for ClientKvApi { } for (pending, done_item) in done_pending.into_iter().zip(done_resp.items.into_iter()) { - inner.external_pending_puts.invalidate(&( - pending.key.clone(), - pending.put_id.0, - pending.put_id.1, - )); if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( done_item.error_code, done_item.error_json.clone(), @@ -2840,6 +4072,11 @@ impl HandlerForExternalClient for ClientKvApi { holder_id, ) .await?; + inner.external_pending_puts.invalidate(&( + pending.key.clone(), + pending.put_id.0, + pending.put_id.1, + )); if pending.make_replica_task { let target = pending .replica_target @@ -2896,37 +4133,52 @@ impl HandlerForExternalClient for ClientKvApi { ); return Ok(ExternalPutRevokeResp::from_error(&err)); }; - let pending_ctx = inner - .external_pending_puts - .get(&(req.key.clone(), put_id.0, put_id.1)) - .map(|ctx| ctx.clone()); - inner - .external_pending_puts - .invalidate(&(req.key.clone(), put_id.0, put_id.1)); - if let Some(ctx) = pending_ctx { - if let (Some(slot_ref), Some(slot_size)) = - (ctx.local_reserve_slot, ctx.local_reserve_slot_size) + let pending_ctx = match require_external_pending_put_ctx( + inner, + "external_put_revoke", + &req.key, + put_id, + ) { + Ok(ctx) => ctx, + Err(err) => { + best_effort_revoke_missing_external_pending_ctx( + inner, + "external_put_revoke", + &req.key, + put_id, + ) + .await; + return Ok(ExternalPutRevokeResp::from_error(&err)); + } + }; + if pending_ctx.local_reserve_slot.is_some() { + return match pending_ctx + ._pending_fence + .release_local_slot_lease_now(inner) + .await { - inner.release_external_local_first_put_key(&req.key); - let lease = client_kv_api::OwnerLocalReserveSlotLease { - value_len: ctx.len, - slot_size, - slots: vec![slot_ref], - }; - return match inner.owner_release_local_reserve_slot_lease(lease).await { - Ok(_) => Ok(ExternalPutRevokeResp { + Ok(_) => { + inner + .external_pending_puts + .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + Ok(ExternalPutRevokeResp { error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, error_json: String::new(), - }), - Err(e) => Ok(ExternalPutRevokeResp::from_error(&e)), - }; - } + }) + } + Err(e) => Ok(ExternalPutRevokeResp::from_error(&e)), + }; } match inner.put_revoke(&req.key, put_id).await { - Ok(_) => Ok(ExternalPutRevokeResp { - error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, - error_json: String::new(), - }), + Ok(_) => { + inner + .external_pending_puts + .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + Ok(ExternalPutRevokeResp { + error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, + error_json: String::new(), + }) + } Err(e) => Ok(ExternalPutRevokeResp::from_error(&e)), } } diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs index 363c443..874107a 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs @@ -1,4 +1,7 @@ -use super::{ClientKvApiInner, KvMetrics}; +use super::{ + ClientKvApiInner, ClientKvApiView, KvMetrics, OwnerLocalReserveSlotLease, + OwnerLocalReserveSlotRef, +}; use crate::cluster_manager::app_logic_ext::ClusterManagerAppLogicExt; use crate::memholder::{MemoryInfo, UserMemHolder, UserMemHolderExposeKind}; // no StageScope; timestamps-based metrics only @@ -13,19 +16,186 @@ use crate::{ master_kv_router::msg_pack::{ BatchGetDoneReq, BatchGetDoneResp, BatchGetRevokeReq, BatchGetRevokeResp, BatchGetStartItemResp, BatchGetStartReq, BatchGetStartResp, BatchIsExistReq, - GetAllocationMode, GetDoneReq, GetDoneResp, GetMetaReq, GetMetaResp, GetRevokeReq, - GetStartReq, GetStartResp, + GetAllocationMode, GetDoneReq, GetDoneResp, GetMetaReq, GetMetaResp, + GetPreparedLocalReserveTarget, GetRevokeReq, GetStartReq, GetStartResp, }, p2p::msg_pack::MsgPack, rpcresp_kvresult_convert::msg_and_error::codes_api, rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, KvResult, OK}, }; +use ::tokio::sync::Semaphore; use chrono::Utc; use futures::stream::{self, StreamExt}; use limit_thirdparty::tokio; use std::sync::Arc; +use std::sync::OnceLock; +use std::time::Duration; use std::time::Instant; +const BATCH_GET_DONE_MAX_INFLIGHT: usize = 4; + +fn batch_get_done_rpc_limiter() -> &'static Semaphore { + static LIMITER: OnceLock = OnceLock::new(); + LIMITER.get_or_init(|| Semaphore::new(BATCH_GET_DONE_MAX_INFLIGHT)) +} + +async fn release_prepared_get_target( + inner: &ClientKvApiInner, + target: &GetPreparedLocalReserveTarget, +) -> KvResult<()> { + inner + .owner_release_local_reserve_slot_lease(OwnerLocalReserveSlotLease { + value_len: target.slot_size, + slot_size: target.slot_size, + slots: vec![OwnerLocalReserveSlotRef { + grant_id: target.grant_id, + slot_index: target.slot_index, + ptr: target.addr, + base_addr: target.base_addr, + }], + }) + .await +} + +fn batch_get_done_response_matches(get_ids: &[u64], response: &BatchGetDoneResp) -> bool { + response.items.len() == get_ids.len() + && response + .items + .iter() + .zip(get_ids) + .all(|(item, expected_get_id)| item.get_id == *expected_get_id) +} + +#[derive(Clone)] +pub(crate) struct StartedGetRevokeCleanup { + pub(crate) get_id: u64, + pub(crate) prepared_target: Option, +} + +async fn run_started_get_revoke_cleanup( + view: ClientKvApiView, + pending: Vec, + context: &'static str, +) { + if pending.is_empty() { + return; + } + let mut attempt = 1u32; + loop { + let get_ids = pending.iter().map(|item| item.get_id).collect::>(); + let response = view.client_kv_api().inner().batch_get_revoke(get_ids).await; + let resp = match response { + Ok(resp) + if resp.items.len() == pending.len() + && resp + .items + .iter() + .zip(&pending) + .all(|(resp, expected)| resp.get_id == expected.get_id) => + { + resp + } + Ok(resp) => { + tracing::warn!( + "{} Revoke response shape/identity mismatch; retaining prepared slots for retry: expected={} got={} attempt={}", + context, + pending.len(), + resp.items.len(), + attempt + ); + tokio::time::sleep(Duration::from_millis( + (50u64.saturating_mul(1u64 << attempt.min(6))).min(2_000), + )) + .await; + attempt = attempt.saturating_add(1); + continue; + } + Err(err) => { + if matches!(&err, KvError::Api(ApiError::SystemShutdown { .. })) { + tracing::warn!( + "{} Revoke cleanup stopped during owner shutdown: items={}", + context, + pending.len() + ); + return; + } + tracing::warn!( + "{} Revoke uncertain; retaining get ids and prepared slots for retry: items={} attempt={} err={}", + context, + pending.len(), + attempt, + err + ); + tokio::time::sleep(Duration::from_millis( + (50u64.saturating_mul(1u64 << attempt.min(6))).min(2_000), + )) + .await; + attempt = attempt.saturating_add(1); + continue; + } + }; + + for (expected, item_resp) in pending.iter().zip(resp.items) { + if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( + item_resp.error_code, + item_resp.error_json, + ) { + // A terminal Done may have won. Never release a possibly + // committed slot from the losing Revoke path. + tracing::warn!( + "{} Revoke reached non-releasable terminal: get_id={} err={}", + context, + expected.get_id, + err + ); + continue; + } + let Some(target) = expected.prepared_target.as_ref() else { + continue; + }; + let mut release_attempt = 1u32; + loop { + match release_prepared_get_target(view.client_kv_api().inner(), target).await { + Ok(()) => break, + Err(err) => { + tracing::error!( + "{} Revoke confirmed but prepared slot release failed; retrying: get_id={} attempt={} err={}", + context, + expected.get_id, + release_attempt, + err + ); + tokio::time::sleep(Duration::from_secs(1)).await; + release_attempt = release_attempt.saturating_add(1); + } + } + } + } + return; + } +} + +/// Move cleanup ownership to a registered task before awaiting it. If the +/// caller future is cancelled, the task still drives Revoke to a definite +/// terminal and releases only confirmed-uncommitted prepared slots. +pub(crate) async fn finish_started_get_revoke_cleanup( + inner: &ClientKvApiInner, + pending: Vec, + context: &'static str, +) { + if pending.is_empty() { + return; + } + let (done_tx, done_rx) = ::tokio::sync::oneshot::channel::<()>(); + let spawn_view = inner.view.clone_view(); + let worker_view = spawn_view.clone(); + spawn_view.spawn("started_get_revoke_cleanup", async move { + run_started_get_revoke_cleanup(worker_view, pending, context).await; + let _ = done_tx.send(()); + }); + let _ = done_rx.await; +} + #[derive(Debug, Clone)] pub struct RemoteGetInfo { get_id: u64, @@ -94,6 +264,7 @@ impl ClientKvApiInner { start_item: BatchGetStartItemResp, peer_is_remote: bool, transfer_us: i64, + prepared_memory_info: Option>, } let transfer_concurrency = transfer_concurrency.max(1); @@ -106,11 +277,14 @@ impl ClientKvApiInner { Option, Option)>>>, > = (0..keys.len()).map(|_| None).collect(); let mut done_pending = Vec::new(); - let mut revoke_get_ids = Vec::new(); + let mut transfer_error_cleanup = Vec::new(); let mut transfer_futures = Vec::new(); for (idx, (key, start_item)) in keys.into_iter().zip(start_items.into_iter()).enumerate() { if start_item.error_code == codes_api::API_KEY_NOT_FOUND { + if let Some(target) = start_item.prepared_target.as_ref() { + release_prepared_get_target(self, target).await?; + } results[idx] = Some(Ok(None)); continue; } @@ -118,6 +292,9 @@ impl ClientKvApiInner { start_item.error_code, start_item.error_json.clone(), ) { + if let Some(target) = start_item.prepared_target.as_ref() { + release_prepared_get_target(self, target).await?; + } results[idx] = Some(Err(err)); continue; } @@ -140,6 +317,7 @@ impl ClientKvApiInner { start_item, peer_is_remote, transfer_us: 0, + prepared_memory_info: None, }); continue; } @@ -186,50 +364,156 @@ impl ClientKvApiInner { start_item, peer_is_remote, transfer_us, + prepared_memory_info: None, }); } - (idx, _key, _start_item, _peer_is_remote, get_id, _transfer_us, Err(err)) => { + (idx, _key, start_item, _peer_is_remote, get_id, _transfer_us, Err(err)) => { results[idx] = Some(Err(err)); - revoke_get_ids.push(get_id); + transfer_error_cleanup.push(StartedGetRevokeCleanup { + get_id, + prepared_target: start_item.prepared_target, + }); } } } - if !revoke_get_ids.is_empty() { - if let Err(err) = self.batch_get_revoke(revoke_get_ids).await { - tracing::warn!("batch_get_revoke failed after transfer errors: {}", err); + finish_started_get_revoke_cleanup( + self, + transfer_error_cleanup, + "batch_get transfer failure", + ) + .await; + + let mut ready_done_pending = Vec::with_capacity(done_pending.len()); + let mut install_failed_cleanup = Vec::new(); + for mut pending in done_pending { + let install_result = if let Some(target) = pending.start_item.prepared_target.as_ref() { + match u32::try_from(pending.start_item.len) { + Ok(len) => self + .install_hidden_pending_local_get( + &pending.key, + pending.start_item.get_id, + pending.start_item.put_id, + target.addr, + target.base_addr, + len, + target.slot_size, + target.grant_id, + target.slot_index, + ) + .map(Some), + Err(_) => Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "local-reserve Get value length exceeds u32: key={} len={}", + pending.key, pending.start_item.len + ), + })), + } + } else { + Ok(None) + }; + match install_result { + Ok(memory_info) => { + pending.prepared_memory_info = memory_info; + ready_done_pending.push(pending); + } + Err(err) => { + install_failed_cleanup.push(StartedGetRevokeCleanup { + get_id: pending.start_item.get_id, + prepared_target: pending.start_item.prepared_target.clone(), + }); + results[pending.idx] = Some(Err(err)); + } } } + done_pending = ready_done_pending; - let done_resp = self - .batch_get_done( - done_pending - .iter() - .map(|pending| pending.start_item.get_id) - .collect(), - ) - .await?; - if done_resp.items.len() != done_pending.len() { - return Err(KvError::Api(ApiError::Unknown { - detail: format!( - "batch_get_done response length mismatch: expected={} got={}", - done_pending.len(), - done_resp.items.len() - ), - })); - } + finish_started_get_revoke_cleanup( + self, + install_failed_cleanup, + "batch_get pending install failure", + ) + .await; + + let done_get_ids = done_pending + .iter() + .map(|pending| pending.start_item.get_id) + .collect::>(); + let done_first_get_id = done_get_ids.first().copied(); + let done_last_get_id = done_get_ids.last().copied(); + let mut done_attempt = 1u32; + let done_resp = loop { + match self.batch_get_done(done_get_ids.clone()).await { + Ok(resp) if batch_get_done_response_matches(&done_get_ids, &resp) => break resp, + Ok(resp) => { + tracing::warn!( + "batch_get_done response shape/identity mismatch; retaining pending-visible slots and retrying the same idempotent get_ids: items={} first_get_id={:?} last_get_id={:?} got_items={} got_first_get_id={:?} got_last_get_id={:?} attempt={}", + done_get_ids.len(), + done_first_get_id, + done_last_get_id, + resp.items.len(), + resp.items.first().map(|item| item.get_id), + resp.items.last().map(|item| item.get_id), + done_attempt + ); + } + Err(err) => { + if matches!(&err, KvError::Api(ApiError::SystemShutdown { .. })) { + return Err(err); + } + tracing::warn!( + "batch_get_done transport uncertain; retaining pending-visible slots and retrying the same idempotent get_ids: items={} first_get_id={:?} last_get_id={:?} attempt={} err={}", + done_get_ids.len(), + done_first_get_id, + done_last_get_id, + done_attempt, + err + ); + } + } + tokio::time::sleep(Duration::from_millis( + (10u64.saturating_mul(1u64 << done_attempt.min(8))).min(2_000), + )) + .await; + done_attempt = done_attempt.saturating_add(1); + }; let master_node_id: NodeID = self .view .cluster_manager() .find_or_wait_master_node() .await? .into(); + let mut local_hot_admissions = Vec::new(); for (pending, done_item) in done_pending.into_iter().zip(done_resp.items.into_iter()) { if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( done_item.error_code, done_item.error_json.clone(), ) { + if let Some(target) = pending.start_item.prepared_target.as_ref() { + self.abort_hidden_pending_local_get(&pending.key, pending.start_item.get_id); + let canonical = self.local_committed_mem_holder_for_put_id( + &pending.key, + pending.start_item.put_id, + ); + if let Err(release_err) = release_prepared_get_target(self, target).await { + results[pending.idx] = Some(Err(release_err)); + continue; + } + // A same-version PutDone/GetDone may have won while this + // transfer was in flight. Converge on the owner's + // canonical local backing instead of turning an already + // available KV page into a prefix miss. + if let Some(memory_info) = canonical { + let user_mem_holder = Arc::new(UserMemHolder::new( + memory_info, + self.get_or_init_all_memholder_refcount(), + UserMemHolderExposeKind::SegPtr, + )); + results[pending.idx] = Some(Ok(Some((user_mem_holder, None)))); + continue; + } + } results[pending.idx] = Some(Err(err)); continue; } @@ -238,7 +522,6 @@ impl ClientKvApiInner { } else { UserMemHolderExposeKind::SegPtr }; - let offset = pending.start_item.target_addr - pending.start_item.target_base_addr; let data_len = pending.start_item.len as usize; metrics.record_l2_hit_locality(pending.peer_is_remote, data_len as u64); metrics.record_get_io_locality( @@ -246,37 +529,88 @@ impl ClientKvApiInner { data_len as u64, pending.transfer_us, ); - let memory_info = Arc::new( - MemoryInfo::new( - offset, - pending.start_item.len as u32, - done_item.holder_id, - pending.key.clone(), - master_node_id.clone(), - self.view.clone(), - ) - .await, - ); - let get_info = RemoteGetInfo { - get_id: pending.start_item.get_id, - data_len, - src_addr: pending.start_item.src_addr, - target_addr: pending.start_item.target_addr, - node_id: pending.start_item.node_id.clone().into(), - peer_is_src_or_target: pending.peer_is_remote, - }; - if done_item.allocation_mode != GetAllocationMode::Temporary { - if self.install_get_cached_info_if_unfenced( + let memory_info = if pending.start_item.prepared_target.is_some() { + if done_item.allocation_mode != GetAllocationMode::LocalCommittedSlot { + self.abort_hidden_pending_local_get(&pending.key, pending.start_item.get_id); + results[pending.idx] = Some(Err(KvError::Api(ApiError::Unknown { + detail: format!( + "prepared local-reserve Get completed with unexpected allocation mode: key={} mode={:?}", + pending.key, done_item.allocation_mode + ), + }))); + continue; + } + let memory_info = match self.promote_hidden_pending_local_get( &pending.key, + pending.start_item.get_id, pending.start_item.put_id, - memory_info.clone(), ) { + Ok(memory_info) => memory_info, + Err(err) => { + results[pending.idx] = Some(Err(err)); + continue; + } + }; + if let Some(prepared) = pending.prepared_memory_info.as_ref() { + assert!( + Arc::ptr_eq(prepared, &memory_info), + "Get promotion must retain the unique prepared MemoryInfo" + ); + } + local_hot_admissions.push(( + pending.key.clone(), + pending.start_item.put_id, + memory_info.clone(), + pending.start_item.atomic_group.clone(), + )); + memory_info + } else { + if done_item.allocation_mode == GetAllocationMode::LocalCommittedSlot { + results[pending.idx] = Some(Err(KvError::Api(ApiError::Unknown { + detail: format!( + "master returned local committed-slot mode without a prepared target: key={}", + pending.key + ), + }))); + continue; + } + let offset = pending.start_item.target_addr - pending.start_item.target_base_addr; + let memory_info = Arc::new( + MemoryInfo::new( + offset, + pending.start_item.len as u32, + done_item.holder_id, + pending.key.clone(), + master_node_id.clone(), + self.view.clone(), + ) + .await, + ); + if done_item.allocation_mode != GetAllocationMode::Temporary + && self.install_get_cached_info_if_unfenced( + &pending.key, + pending.start_item.put_id, + memory_info.clone(), + ) + { metrics.observe_cache_value_size( &client_id, node_role.as_str(), data_len as u64, ); } + memory_info + }; + let get_info = RemoteGetInfo { + get_id: pending.start_item.get_id, + data_len, + src_addr: pending.start_item.src_addr, + target_addr: pending.start_item.target_addr, + node_id: pending.start_item.node_id.clone().into(), + peer_is_src_or_target: pending.peer_is_remote, + }; + if done_item.allocation_mode == GetAllocationMode::LocalCommittedSlot { + metrics.observe_cache_value_size(&client_id, node_role.as_str(), data_len as u64); } let user_mem_holder = Arc::new(UserMemHolder::new( memory_info, @@ -286,6 +620,12 @@ impl ClientKvApiInner { results[pending.idx] = Some(Ok(Some((user_mem_holder, Some(get_info))))); } + // All members are in get_cached_info before any hot admission can evict one of them. + // This keeps atomic/TP cohort write-back decisions complete. + for (key, put_id, memory_info, atomic_group) in local_hot_admissions { + self.owner_hot_track_committed(&key, put_id, &memory_info, atomic_group.as_ref()); + } + Ok(results .into_iter() .map(|item| { @@ -994,6 +1334,7 @@ impl ClientKvApiInner { let req = MsgPack { serialize_part: GetStartReq { key: key.to_string(), + prepared_target: None, }, raw_bytes: Vec::new(), }; @@ -1016,13 +1357,25 @@ impl ClientKvApiInner { } pub async fn batch_get_start(&self, keys: Vec) -> KvResult { + self.batch_get_start_with_prepared_targets(keys, Vec::new()) + .await + } + + pub(crate) async fn batch_get_start_with_prepared_targets( + &self, + keys: Vec, + prepared_targets: Vec>, + ) -> KvResult { if !self.view.register_shutdown_poller().is_running() { return Err(KvError::Api(ApiError::SystemShutdown { detail: "ClientKvApi is shutting down; rejecting batch_get_start".to_string(), })); } let req = MsgPack { - serialize_part: BatchGetStartReq { keys }, + serialize_part: BatchGetStartReq { + keys, + prepared_targets, + }, raw_bytes: Vec::new(), }; let master_node_id = self @@ -1074,6 +1427,11 @@ impl ClientKvApiInner { error_json: String::new(), }); } + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting batch_get_revoke".to_string(), + })); + } let req = MsgPack { serialize_part: BatchGetRevokeReq { get_ids }, raw_bytes: Vec::new(), @@ -1128,6 +1486,20 @@ impl ClientKvApiInner { server_process_us: 0, }); } + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting batch_get_done".to_string(), + })); + } + // The master performs synchronous Moka policy work before acknowledging + // committed-slot Done. Bound the number of callers entering that path + // so a capacity scan cannot park every master Tokio worker on Moka's + // blocking housekeeper lock. The permit covers one RPC attempt only; + // idempotent retry backoff releases it and lets other cohorts converge. + let _done_rpc_permit = batch_get_done_rpc_limiter() + .acquire() + .await + .expect("the process-wide BatchGetDone limiter is never closed"); let req = MsgPack { serialize_part: BatchGetDoneReq { get_ids }, raw_bytes: Vec::new(), @@ -1139,7 +1511,7 @@ impl ClientKvApiInner { .await?; let resp = self .rpc_caller_batch_get_done - .call(self.view.p2p_module(), master_node_id.into(), req, None, 0) + .call(self.view.p2p_module(), master_node_id.into(), req, None, 2) .await .map_err(KvError::from)?; crate::rpcresp_kvresult_convert::try_from_code( @@ -1149,3 +1521,38 @@ impl ClientKvApiInner { Ok(resp.serialize_part) } } + +#[cfg(test)] +mod tests { + use super::batch_get_done_response_matches; + use crate::master_kv_router::msg_pack::{BatchGetDoneItemResp, BatchGetDoneResp}; + + fn response(get_ids: &[u64]) -> BatchGetDoneResp { + BatchGetDoneResp { + items: get_ids + .iter() + .map(|get_id| BatchGetDoneItemResp { + get_id: *get_id, + ..Default::default() + }) + .collect(), + ..Default::default() + } + } + + #[test] + fn batch_get_done_requires_exact_response_identity() { + assert!(batch_get_done_response_matches( + &[11, 22], + &response(&[11, 22]) + )); + assert!(!batch_get_done_response_matches( + &[11, 22], + &response(&[22, 11]) + )); + assert!(!batch_get_done_response_matches( + &[11, 22], + &response(&[11]) + )); + } +} diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/local_reserve_rebalance.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/local_reserve_rebalance.rs index cbe5467..08ad95e 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/local_reserve_rebalance.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/local_reserve_rebalance.rs @@ -10,10 +10,17 @@ const OWNER_LOCAL_RESERVE_REBALANCE_INTERVAL: Duration = Duration::from_millis(2 const OWNER_LOCAL_RESERVE_SHRINK_IDLE_COOLDOWN: Duration = Duration::from_secs(5); const OWNER_LOCAL_RESERVE_SHRINK_GROW_COOLDOWN: Duration = Duration::from_secs(1); const OWNER_LOCAL_RESERVE_DEFAULT_SOFT_WAIT_TIMEOUT: Duration = Duration::from_millis(10); -const OWNER_LOCAL_RESERVE_DEFAULT_HARD_TIMEOUT: Duration = Duration::from_secs(10); +// Cohort-safe master route deletion plus owner slot release is asynchronous. +// Thirty seconds turns a recoverable pressure burst into a storage exception that +// can wedge SGLang's detokenizer. This remains well below the external request +// timeout while allowing bounded backpressure to finish reclaiming slots. +const OWNER_LOCAL_RESERVE_DEFAULT_HARD_TIMEOUT: Duration = Duration::from_secs(30); const OWNER_LOCAL_RESERVE_MIN_GRANTS_PER_CLASS: usize = 0; const OWNER_LOCAL_RESERVE_REPORT_INTERVAL: Duration = Duration::from_secs(30); const OWNER_LOCAL_RESERVE_FREE_SLOT_HEADROOM_GRANTS: usize = 4; +const OWNER_SLOT_PRESSURE_INTERVAL: Duration = Duration::from_millis(10); +const OWNER_SLOT_PRESSURE_MIN_KICK_INTERVAL: Duration = Duration::from_millis(200); +const OWNER_SLOT_PRESSURE_MAX_EVICT_BYTES: u64 = 256 * 1024 * 1024; #[derive(Debug, Clone, Copy)] struct ExpectedCapacityLayout { @@ -32,6 +39,7 @@ struct RebalanceClassSnapshot { free_slots: usize, grant_count: usize, pending_slot_demand: usize, + max_observed_claim_slots: usize, expected_grant_count: usize, } @@ -49,7 +57,43 @@ fn owner_local_reserve_target_grant_count( let slots_per_grant = slots_per_grant as usize; let demand_grants = required_slots / slots_per_grant + usize::from(required_slots % slots_per_grant != 0); - demand_grants.max(expected_grant_count) + if expected_grant_count == 0 { + demand_grants + } else { + // A configured expected capacity is the owner's physical slot budget, + // not a minimum that demand may grow past. Once all expected grants + // are installed, additional demand must be served by owner-local + // source eviction/reclaim; asking the master for another grant silently + // changes the configured owner capacity and can starve the remote + // allocation domain. + expected_grant_count + } +} + +fn owner_slot_pressure_request_bytes( + snapshot: RebalanceClassSnapshot, + outstanding_selection_debt_bytes: u64, +) -> u64 { + let low_watermark = (snapshot.slots_per_grant as usize) + .saturating_mul(2) + .max(snapshot.max_observed_claim_slots); + let high_watermark = (snapshot.slots_per_grant as usize) + .saturating_mul(OWNER_LOCAL_RESERVE_FREE_SLOT_HEADROOM_GRANTS); + let projected_eviction_slots = + usize::try_from(outstanding_selection_debt_bytes / snapshot.slot_size.max(1)) + .unwrap_or(usize::MAX); + let projected_free_slots = snapshot.free_slots.saturating_add(projected_eviction_slots); + let pressure_active = + snapshot.pending_slot_demand > snapshot.free_slots || projected_free_slots < low_watermark; + if !pressure_active { + return 0; + } + let desired_free_slots = snapshot.pending_slot_demand.saturating_add(high_watermark); + let selection_slots = desired_free_slots.saturating_sub(projected_free_slots); + u64::try_from(selection_slots) + .unwrap_or(u64::MAX) + .saturating_mul(snapshot.slot_size) + .min(OWNER_SLOT_PRESSURE_MAX_EVICT_BYTES) } fn owner_local_reserve_desired_free_slots(snapshot: RebalanceClassSnapshot) -> usize { @@ -111,6 +155,7 @@ fn snapshot_rebalance_classes(pool: &OwnerLocalReservePoolState) -> Vec= snapshot.expected_grant_count; let rpc_started_at = Instant::now(); - let outcome = match inner - .reserve_local_grant(snapshot.slot_size, required_free_slots, reclaim_before_grow) - .await - { + let outcome = match inner.reserve_local_grant().await { Ok(outcome) => { let rpc_latency = rpc_started_at.elapsed(); total_rpc_latency = total_rpc_latency.saturating_add(rpc_latency); @@ -197,22 +233,6 @@ async fn try_refill_once(inner: &ClientKvApiInner, snapshot: RebalanceClassSnaps base_addr, len, } => (grant_id, base_addr, addr, len), - ReserveLocalGrantOutcome::Reclaimed { - slot_size, - reclaimed_slots, - } => { - assert_eq!(slot_size, snapshot.slot_size); - tracing::info!( - "owner local reserve reused reclaimed slots: slot_size={} reclaimed_slots={} pending_slots={}", - slot_size, - reclaimed_slots, - snapshot.pending_slot_demand - ); - inner - .owner_local_reserve_rebalance_notify() - .notify_waiters(); - return; - } ReserveLocalGrantOutcome::None => { unreachable!("reserve_local_grant filters empty successful outcomes") } @@ -246,7 +266,7 @@ async fn try_refill_once(inner: &ClientKvApiInner, snapshot: RebalanceClassSnaps OwnerLocalReserveClassState::new(snapshot.slot_size, snapshot.slots_per_grant) }); class_state.last_grow_at = Some(Instant::now()); - class_state.grants.push(detached_grant); + class_state.install_grant(detached_grant); } added_grants += 1; inner @@ -272,16 +292,13 @@ async fn try_refill_once(inner: &ClientKvApiInner, snapshot: RebalanceClassSnaps fn detach_excess_fully_free_grant( class_state: &mut OwnerLocalReserveClassState, - get_target_pressure: bool, -) -> Option<(usize, super::OwnerLocalReserveGrantState)> { - if !get_target_pressure { - let grow_cooldown_ok = class_state - .last_grow_at - .map(|last_grow_at| last_grow_at.elapsed() >= OWNER_LOCAL_RESERVE_SHRINK_GROW_COOLDOWN) - .unwrap_or(true); - if !grow_cooldown_ok { - return None; - } +) -> Option { + let grow_cooldown_ok = class_state + .last_grow_at + .map(|last_grow_at| last_grow_at.elapsed() >= OWNER_LOCAL_RESERVE_SHRINK_GROW_COOLDOWN) + .unwrap_or(true); + if !grow_cooldown_ok { + return None; } let shrink_keep_grants = owner_local_reserve_target_grant_count( class_state.slots_per_grant, @@ -290,30 +307,19 @@ fn detach_excess_fully_free_grant( class_state.expected_grant_count, ) .max(OWNER_LOCAL_RESERVE_MIN_GRANTS_PER_CLASS); - if class_state.grants.len() <= shrink_keep_grants { + if class_state.grant_count() <= shrink_keep_grants { return None; } - let candidate_index = if get_target_pressure { - // A physical Get-target allocation can be blocked while reclaimed slots remain trapped in - // a detached 512-MiB reserve grant. Under explicit pressure, any fully-free excess grant is - // safe to return; restricting the actor to the tail would leave allocator space stranded. - class_state - .grants - .iter() - .rposition(super::OwnerLocalReserveGrantState::is_fully_free) - } else { - let tail_index = class_state.grants.len().checked_sub(1)?; - class_state.grants.get(tail_index).and_then(|grant| { - (grant.is_fully_free() - && grant - .fully_free_since - .map(|since| since.elapsed() >= OWNER_LOCAL_RESERVE_SHRINK_IDLE_COOLDOWN) - .unwrap_or(false)) - .then_some(tail_index) - }) - }?; - Some((candidate_index, class_state.grants.remove(candidate_index))) + let candidate_grant_id = class_state.grants.last().and_then(|grant| { + (grant.is_fully_free() + && grant + .fully_free_since + .map(|since| since.elapsed() >= OWNER_LOCAL_RESERVE_SHRINK_IDLE_COOLDOWN) + .unwrap_or(false)) + .then_some(grant.grant_id) + })?; + class_state.detach_fully_free_grant(candidate_grant_id) } async fn try_shrink_once(inner: &ClientKvApiInner, snapshot: RebalanceClassSnapshot) { @@ -322,10 +328,10 @@ async fn try_shrink_once(inner: &ClientKvApiInner, snapshot: RebalanceClassSnaps let Some(class_state) = pool.classes.get_mut(&snapshot.slot_size) else { return; }; - detach_excess_fully_free_grant(class_state, false) + detach_excess_fully_free_grant(class_state) }; - let Some((grant_index, grant)) = detached else { + let Some(grant) = detached else { return; }; @@ -339,9 +345,7 @@ async fn try_shrink_once(inner: &ClientKvApiInner, snapshot: RebalanceClassSnaps let class_state = pool.classes.entry(snapshot.slot_size).or_insert_with(|| { OwnerLocalReserveClassState::new(snapshot.slot_size, snapshot.slots_per_grant) }); - class_state - .grants - .insert(grant_index.min(class_state.grants.len()), grant); + class_state.install_grant(grant); } else { tracing::info!( "owner local reserve released excess grant: slot_size={} grant_id={} pending_slots={}", @@ -352,71 +356,9 @@ async fn try_shrink_once(inner: &ClientKvApiInner, snapshot: RebalanceClassSnaps } } -/// Return one fully-free reserve grant immediately when an ordinary local Get-target allocation -/// reports physical NoSpace. This never shrinks below the configured/active reserve target and does -/// not evict a live slot; it only makes already-free physical capacity visible to the master -/// allocator without waiting for the periodic idle cooldown. -pub(crate) async fn release_one_excess_reserve_grant_for_get_target_pressure( - inner: &ClientKvApiInner, -) -> bool { - let detached = { - let mut pool = inner.owner_local_reserve_pool.lock(); - let mut detached = None; - for class_state in pool.classes.values_mut() { - if let Some((grant_index, grant)) = detach_excess_fully_free_grant(class_state, true) { - detached = Some(( - class_state.slot_size, - class_state.slots_per_grant, - class_state.pending_slot_demand, - grant_index, - grant, - )); - break; - } - } - detached - }; - let Some((slot_size, slots_per_grant, pending_slots, grant_index, grant)) = detached else { - return false; - }; - let grant_id = grant.grant_id; - - if let Err(err) = inner.release_local_grant(grant_id).await { - tracing::warn!( - "owner local reserve get-target pressure failed to release grant_id={} err={}", - grant_id, - err - ); - let mut pool = inner.owner_local_reserve_pool.lock(); - let class_state = pool - .classes - .entry(slot_size) - .or_insert_with(|| OwnerLocalReserveClassState::new(slot_size, slots_per_grant)); - class_state - .grants - .insert(grant_index.min(class_state.grants.len()), grant); - inner - .owner_local_reserve_rebalance_notify() - .notify_waiters(); - false - } else { - tracing::info!( - "owner local reserve released excess grant for get-target pressure: slot_size={} grant_id={} pending_slots={}", - slot_size, - grant_id, - pending_slots - ); - inner - .owner_local_reserve_rebalance_notify() - .notify_waiters(); - true - } -} - #[cfg(test)] mod tests { use super::*; - use crate::client_kv_api::OwnerLocalReserveGrantState; const SLOT_SIZE: u64 = 8 * 1024 * 1024; @@ -456,10 +398,10 @@ mod tests { } #[test] - fn default_hard_timeout_covers_pressure_reclaim_transaction() { + fn default_hard_timeout_covers_owner_source_eviction_transaction() { assert_eq!( OWNER_LOCAL_RESERVE_DEFAULT_HARD_TIMEOUT, - Duration::from_secs(10) + Duration::from_secs(30) ); assert!( OWNER_LOCAL_RESERVE_DEFAULT_HARD_TIMEOUT > OWNER_LOCAL_RESERVE_SHRINK_IDLE_COOLDOWN @@ -475,6 +417,7 @@ mod tests { free_slots: 64 * 4, grant_count: 232, pending_slot_demand: 0, + max_observed_claim_slots: 0, expected_grant_count: 232, }; assert_eq!(owner_local_reserve_desired_free_slots(snapshot), 64 * 4); @@ -500,62 +443,71 @@ mod tests { owner_local_reserve_desired_free_slots(pressured), pressured.expected_grant_count, ), - 233 + 232 ); } #[test] - fn get_target_pressure_can_detach_a_non_tail_fully_free_excess_grant() { - let mut class_state = OwnerLocalReserveClassState::new(SLOT_SIZE, 2); - class_state.expected_grant_count = 1; - for grant_id in 1..=3 { - class_state.grants.push(OwnerLocalReserveGrantState::new( - grant_id, - 0, - grant_id * 1024, - 1024, - SLOT_SIZE, - 2, - )); - } - class_state.grants[0] - .claim_prepared_slot() - .expect("first grant must have a slot"); - class_state.grants[2] - .claim_prepared_slot() - .expect("tail grant must have a slot"); - - assert!(detach_excess_fully_free_grant(&mut class_state, false).is_none()); - let (index, grant) = detach_excess_fully_free_grant(&mut class_state, true) - .expect("pressure shrink must find the free middle grant"); - assert_eq!(index, 1); - assert_eq!(grant.grant_id, 2); - assert_eq!(class_state.grants.len(), 2); + fn configured_expected_grants_are_a_hard_upper_bound() { + assert_eq!( + owner_local_reserve_target_grant_count(64, 64 * 300, 64, 232), + 232 + ); + assert_eq!( + owner_local_reserve_target_grant_count(64, 64 * 300, 64, 0), + 301 + ); } #[test] - fn get_target_pressure_never_shrinks_below_active_or_expected_target() { - let mut class_state = OwnerLocalReserveClassState::new(SLOT_SIZE, 2); - class_state.expected_grant_count = 2; - for grant_id in 1..=2 { - class_state.grants.push(OwnerLocalReserveGrantState::new( - grant_id, + fn owner_slot_pressure_targets_pending_plus_high_watermark() { + let snapshot = RebalanceClassSnapshot { + slot_size: 1024 * 1024, + slots_per_grant: 4, + used_slots: 4, + free_slots: 1, + grant_count: 1, + pending_slot_demand: 3, + max_observed_claim_slots: 3, + expected_grant_count: 1, + }; + assert_eq!( + owner_slot_pressure_request_bytes(snapshot, 0), + 18 * 1024 * 1024, + "3 pending slots plus 16 slots of retained headroom minus one physical Free" + ); + assert_eq!( + owner_slot_pressure_request_bytes(snapshot, 10 * 1024 * 1024), + 8 * 1024 * 1024, + "exact selected debt contributes projected slots of the same class" + ); + assert_eq!( + owner_slot_pressure_request_bytes( + RebalanceClassSnapshot { + free_slots: 16, + pending_slot_demand: 0, + ..snapshot + }, 0, - grant_id * 1024, - 1024, - SLOT_SIZE, - 2, - )); - } - assert!(detach_excess_fully_free_grant(&mut class_state, true).is_none()); + ), + 0, + "pressure stops after the high watermark is physically available" + ); - class_state.expected_grant_count = 0; - for grant in &mut class_state.grants { - grant - .claim_prepared_slot() - .expect("each grant must have a slot"); - } - assert!(detach_excess_fully_free_grant(&mut class_state, true).is_none()); + let clamped = RebalanceClassSnapshot { + slot_size: 8 * 1024 * 1024, + slots_per_grant: 64, + used_slots: 64, + free_slots: 1, + grant_count: 1, + pending_slot_demand: 100, + max_observed_claim_slots: 100, + expected_grant_count: 1, + }; + assert_eq!( + owner_slot_pressure_request_bytes(clamped, 0), + OWNER_SLOT_PRESSURE_MAX_EVICT_BYTES + ); } } @@ -650,6 +602,107 @@ pub fn spawn_owner_local_reserve_rebalance_actor(view: ClientKvApiView) { }); } +/// Drive owner slot pressure outside RPC handlers and outside Tokio's worker +/// threads. This is the sole production call site for Moka's synchronous +/// `evict_some`: selection is deliberately bounded, and the returned weight +/// means only "source-eviction candidates selected", never "slots reclaimed". +pub fn spawn_owner_slot_pressure_actor(view: ClientKvApiView) { + let view_task = view.clone(); + view.spawn("owner_slot_pressure_actor", async move { + let shutdown_poller = view_task.register_shutdown_poller(); + let mut shutdown_waiter = view_task.register_shutdown_waiter(); + let notify = view_task + .client_kv_api() + .inner() + .owner_local_reserve_rebalance_notify(); + let mut tick = tokio::time::interval(OWNER_SLOT_PRESSURE_INTERVAL); + let mut last_kick_at: Option = None; + let mut last_unsupported_class_report_at: Option = None; + + loop { + tokio::select! { + biased; + _ = shutdown_waiter.wait() => { + tracing::info!("owner slot pressure actor stopped by shutdown"); + return; + } + _ = tick.tick() => {} + _ = notify.notified() => {} + } + if !shutdown_poller.is_running() { + return; + } + + let inner = view_task.client_kv_api().inner(); + if last_kick_at + .is_some_and(|last| last.elapsed() < OWNER_SLOT_PRESSURE_MIN_KICK_INTERVAL) + { + continue; + } + let outstanding_selection_debt_bytes = inner + .owner_hot_counters + .selection_debt_bytes + .load(std::sync::atomic::Ordering::Acquire); + let requested_bytes = { + let pool = inner.owner_local_reserve_pool.lock(); + let snapshots = snapshot_rebalance_classes(&pool); + match snapshots.as_slice() { + // No local allocation class has been observed yet. This is + // the normal idle state, not a configuration error. + [] => 0, + [snapshot] => owner_slot_pressure_request_bytes( + *snapshot, + outstanding_selection_debt_bytes, + ), + _ => { + // Selection is intentionally disabled until the victim + // cache is class-indexed. Rate-limit the diagnostic so + // an unsupported configuration cannot become a 100 Hz + // logging/CPU loop. + if last_unsupported_class_report_at.is_none_or(|last| { + last.elapsed() >= OWNER_LOCAL_RESERVE_REPORT_INTERVAL + }) { + tracing::error!( + active_classes = snapshots.len(), + "owner slot pressure requires a class-indexed victim domain when more than one size class is active" + ); + last_unsupported_class_report_at = Some(Instant::now()); + } + 0 + } + } + }; + if requested_bytes == 0 { + continue; + } + let Some(cache) = inner.owner_hot_cache.clone() else { + continue; + }; + let selected_bytes = match limit_thirdparty::tokio::task::spawn_blocking(move || { + cache.evict_some(requested_bytes) + }) + .await + { + Ok(selected_bytes) => selected_bytes, + Err(err) => { + tracing::warn!( + requested_bytes, + err = ?err, + "owner slot pressure Moka selection task failed" + ); + continue; + } + }; + last_kick_at = Some(Instant::now()); + tracing::debug!( + requested_bytes, + selected_bytes, + "owner slot pressure selected bounded source-eviction candidates" + ); + } + }); +} + pub async fn wait_owner_local_reserve_ready( inner: &ClientKvApiInner, slot_size: u64, diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs index 898172b..d5843c4 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs @@ -1,5 +1,7 @@ use crate::client_kv_api::delete::handle_batch_delete_client_kv_meta_cache; -use crate::client_kv_api::local_reserve_rebalance::spawn_owner_local_reserve_rebalance_actor; +use crate::client_kv_api::local_reserve_rebalance::{ + spawn_owner_local_reserve_rebalance_actor, spawn_owner_slot_pressure_actor, +}; use crate::client_kv_api::msg_pack::{ ExternalBatchGetCancelReq, ExternalBatchGetCancelResp, ExternalBatchGetReq, ExternalBatchGetResp, ExternalBatchGetStartReq, ExternalBatchGetStartResp, @@ -18,10 +20,11 @@ use crate::cluster_manager::{NodeID, NodeIDString}; use crate::config::TestSpecConfig; use crate::master_kv_router::msg_pack::{ BatchDeleteAckReq, BatchDeleteClientKvMetaCacheReq, BatchEnqueueReplicaTaskReq, - BatchGetDoneReq, BatchGetRevokeReq, BatchGetStartItemResp, BatchGetStartReq, BatchIsExistReq, - BatchOwnerReclaimReq, BatchPreparePutKeysReq, BatchPutDoneReq, BatchPutRevokeReq, - BatchPutStartReq, BatchReleasePutKeyReservationsReq, CountPrefixReq, - DeleteClientKvMetaCacheItem, GroupedBatchPutDoneReq, + BatchEvictOwnerSourceReq, BatchGetDoneReq, BatchGetRevokeReq, BatchGetStartItemResp, + BatchGetStartReq, BatchIsExistReq, BatchOwnerReclaimReq, BatchPreparePutKeysReq, + BatchPutAppendDoneReq, BatchPutAppendStartReq, BatchPutDoneReq, BatchPutRevokeReq, + BatchPutStartReq, BatchReleasePutKeyReservationsReq, DeleteClientKvMetaCacheItem, + GroupedBatchPutDoneReq, }; use crate::master_lease_manager::msg_pack::{AllocateClientLeaseReq, ClientLeaseKeepaliveReq}; use crate::memholder::{AllMemholderRefCount, ExternalMemHolderInfo, MemoryInfo, UserMemHolder}; @@ -32,14 +35,11 @@ use crate::memholder::{ use crate::{ client_seg_pool::{ClientSegPool, ClientSegPoolAccessTrait, ResolveSideTransferLaneReq}, client_transfer_engine::{ClientTransferEngine, ClientTransferEngineAccessTrait}, - cluster_manager::{ - ClusterEvent, ClusterManager, ClusterManagerAccessTrait, - app_logic_ext::{ClusterManagerAppLogicExt, ClusterManagerExtError}, - }, + cluster_manager::{ClusterEvent, ClusterManager, ClusterManagerAccessTrait}, master_kv_router::msg_pack::{ - DeleteAckReq, DeleteReq, GetDoneReq, GetMetaReq, GetRevokeReq, GetStartReq, - MemHolderKeepAliveReq, PutAppendDoneReq, PutAppendRevokeReq, PutAppendStartReq, PutDoneReq, - PutRevokeReq, PutStartReq, ReleaseLocalGrantReq, ReserveLocalGrantReq, + DeleteReq, GetDoneReq, GetMetaReq, GetRevokeReq, GetStartReq, PutAppendDoneReq, + PutAppendRevokeReq, PutAppendStartReq, PutDoneReq, PutRevokeReq, PutStartReq, + ReleaseLocalGrantReq, ReserveLocalGrantReq, }, metric_reporter::{MetricReporter, MetricReporterAccessTrait}, metrics::{KvLocalitySnapshot, MetricsHandle, OperationKind, RequestStage}, @@ -50,17 +50,16 @@ use crate::{ rpcresp_kvresult_convert::msg_and_error::{ApiError, ErrorCode, KvError, KvResult}, }; use async_trait::async_trait; -use crossbeam::queue::SegQueue; -use dashmap::{DashMap, DashSet}; +use dashmap::DashMap; use fluxon_framework::{LogicalModule, define_module}; -use fluxon_framework_compiled::upgrade_view_guard::UpgradeViewGuard; use fluxon_util::map_lock::AMapLock; use limit_thirdparty::tokio; use moka::notification::RemovalCause; use moka::ops::compute::Op as MokaComputeOp; -use parking_lot::{Mutex, RwLock}; +use parking_lot::Mutex; +use std::collections::BTreeSet; use std::collections::HashMap; -use std::collections::HashSet; +use std::hash::{Hash, Hasher}; use std::sync::Weak; use std::sync::atomic::{AtomicU32, AtomicU64, Ordering}; use std::sync::{Arc, OnceLock}; @@ -71,7 +70,6 @@ const REPLICA_TASK_QUEUE_CAPACITY: usize = 128; // Queue only weak source references. This preserves a deep policy backlog without turning queued // write-back work into non-reclaimable owner memory; the dispatcher pins a still-current source // immediately before handing it to the bounded replica-task actor. -const OWNER_HOT_EVICTION_QUEUE_CAPACITY: usize = 4096; const OWNER_LOCAL_PUBLISH_QUEUE_CAPACITY: usize = 4096; const OWNER_LOCAL_PUBLISH_MAX_INFLIGHT: usize = 64; @@ -80,6 +78,10 @@ const OWNER_LOCAL_PUBLISH_MAX_INFLIGHT: usize = 64; pub struct ExternalHoldingGetInfo { pub key: String, pub req_node_id: String, + /// Requester membership generation observed when this holding was + /// installed. Unknown generations are never removed by generation-scoped + /// MemberLeft cleanup. + pub requester_node_start_time: Option, pub memory_info: Arc, // The actual memholder being held } @@ -87,25 +89,35 @@ pub struct ExternalHoldingGetInfo { pub struct OwnerRuntimeObserveSnapshot { pub external_get_holding_entries: u64, pub external_get_holding_bytes: u64, + pub external_get_start_handles: u64, + pub external_get_flights: u64, + pub external_get_flights_starting: u64, + pub external_get_flights_finishing: u64, + pub external_get_flights_revoking: u64, + pub external_get_undecided_interests: u64, + pub external_get_retained_interests: u64, pub external_pending_put_entries: u64, + pub local_reserve_slots_free: u64, + pub local_reserve_slots_prepared: u64, + pub local_reserve_slots_pending_visible: u64, + pub local_reserve_slots_committed: u64, pub hot_cache_capacity_bytes: u64, pub hot_cache_entries: u64, pub hot_cache_weighted_bytes: u64, pub hot_size_evictions: u64, - pub hot_replica_enqueued: u64, - pub hot_replica_completed: u64, - pub hot_replica_already_satisfied: u64, - pub hot_replica_failed: u64, - pub hot_replica_obsolete: u64, - pub hot_replica_dispatch_failed: u64, - pub hot_replica_inflight: u64, + pub hot_source_evict_handoff_members: u64, + pub hot_source_evict_committed_members: u64, + pub hot_source_evict_restored_members: u64, + pub hot_source_evict_obsolete: u64, + pub hot_source_evict_dispatch_failed: u64, + pub hot_source_eviction_selected: u64, + pub hot_source_evict_retry_entries: u64, + pub hot_source_evict_retry_scheduled: u64, + pub hot_source_evict_retry_emitted: u64, + pub hot_selection_debt_bytes: u64, pub hot_eviction_skipped_stale: u64, pub hot_eviction_skipped_reclaim: u64, - pub hot_eviction_skipped_duplicate: u64, pub hot_group_registry_entries: u64, - pub hot_group_replica_triggered: u64, - pub hot_group_replica_triggers: u64, - pub hot_group_members_enqueued: u64, pub hot_group_trigger_duplicates: u64, pub hot_group_trigger_incomplete: u64, pub grouped_put_done_batches: u64, @@ -125,52 +137,94 @@ pub type ExternalGetStartTransferOutput = Vec, Option)>>>; pub enum ExternalGetStartOwnerItem { - Local { - memory_info: Arc, - }, - Started { - key: String, - item: BatchGetStartItemResp, - }, + Local { memory_info: Arc }, + Shared { interest: ExternalGetKeyInterest }, } -#[derive(Clone, Debug, Hash, PartialEq, Eq)] -pub struct ExternalGetStartDedupKey { - pub keys: Vec, - pub atomic_group_lens: Vec, - pub prefix_best_effort: bool, +/// One request's interest in a per-key Get flight. +/// +/// A pending prefix decision is owned by this guard, not by control flow. If +/// the request future is cancelled at any await point, Drop retires the +/// undecided count so the cohort task can still choose Finish or Revoke. +pub struct ExternalGetKeyInterest { + op: Arc, + decision_pending: bool, } -#[derive(Clone, Debug)] -pub struct ExternalGetStartPrefixResult { - pub raw_prefix_hit_len: usize, - pub transferable_len: usize, - pub first_miss_index: Option, - pub first_error_kind: Option, +impl ExternalGetKeyInterest { + pub fn new(op: Arc, decision_pending: bool) -> Self { + Self { + op, + decision_pending, + } + } + + pub fn op(&self) -> &Arc { + &self.op + } + + pub fn decide(&mut self, retain: bool) { + if !self.decision_pending { + return; + } + self.decision_pending = false; + + let wake = { + let mut state = self.op.state.lock(); + if state.undecided == 0 { + tracing::error!( + "external Get interest observed undecided underflow: key={}", + self.op.key + ); + return; + } + state.undecided -= 1; + if retain + && matches!( + state.phase, + ExternalGetKeySharedPhase::Starting | ExternalGetKeySharedPhase::Started { .. } + ) + { + state.retained = state + .retained + .checked_add(1) + .expect("external Get singleflight retained overflow"); + } + state.undecided == 0 + }; + if wake { + self.op.notify.notify_waiters(); + } + } } -#[derive(Clone)] -pub enum ExternalGetStartSharedItemResult { - Hit { - memholder: Arc, - }, - Miss, - Error { - error_code: ErrorCode, - error_json: String, - }, +impl Drop for ExternalGetKeyInterest { + fn drop(&mut self) { + self.decide(false); + } } -pub enum ExternalGetStartSharedPhase { +#[derive(Clone)] +pub enum ExternalGetKeySharedPhase { Starting, - Running { - prefix: ExternalGetStartPrefixResult, - keys: Vec, + Started { + item: BatchGetStartItemResp, + }, + /// At least one request plan's prefix retained this key. The leader cohort is + /// transferring/completing it and later publishes one canonical result. + Finishing { + item: BatchGetStartItemResp, + }, + /// No request plan's prefix retained this prepared Get. Keep the marker in + /// the owner key fence until BatchGetRevoke and local-slot release finish, + /// so a new overlapping batch cannot race the revoke. + Revoking { + /// Keep the exact master operation and prepared target reachable until + /// Revoke reaches a definite terminal response. + item: BatchGetStartItemResp, }, Ready { - prefix: ExternalGetStartPrefixResult, - keys: Vec, - items: Vec, + result: ExternalGetStartSharedItemResult, }, Failed { error_code: ErrorCode, @@ -178,38 +232,64 @@ pub enum ExternalGetStartSharedPhase { }, } -pub struct ExternalGetStartSharedState { - pub waiter_count: usize, - pub phase: ExternalGetStartSharedPhase, +pub struct ExternalGetKeySharedState { + /// Exact-batch operations which joined while the key was Starting/Started + /// and have not yet applied their own atomic-prefix decision. + pub undecided: usize, + /// Number of those operations whose transferable prefix retained the key. + pub retained: usize, + pub phase: ExternalGetKeySharedPhase, } -pub struct ExternalGetStartSharedOp { - pub dedup_key: ExternalGetStartDedupKey, - pub transfer_concurrency: usize, - /// Set only when every requested page is already owner-local. - pub inline_local_memory_infos: OnceLock>>, - pub state: Mutex, +pub struct ExternalGetKeySharedOp { + pub key: String, + pub state: Mutex, pub notify: Arc, } -impl ExternalGetStartSharedOp { - pub fn new(dedup_key: ExternalGetStartDedupKey, transfer_concurrency: usize) -> Self { +impl ExternalGetKeySharedOp { + pub fn new(key: String) -> Self { Self { - dedup_key, - transfer_concurrency, - inline_local_memory_infos: OnceLock::new(), - state: Mutex::new(ExternalGetStartSharedState { - waiter_count: 1, - phase: ExternalGetStartSharedPhase::Starting, + key, + state: Mutex::new(ExternalGetKeySharedState { + undecided: 1, + retained: 0, + phase: ExternalGetKeySharedPhase::Starting, }), notify: Arc::new(limit_thirdparty::tokio::sync::Notify::new()), } } } +#[derive(Clone, Debug)] +pub struct ExternalGetStartPrefixResult { + pub raw_prefix_hit_len: usize, + pub transferable_len: usize, + pub first_miss_index: Option, + pub first_error_kind: Option, +} + +#[derive(Clone)] +pub enum ExternalGetStartSharedItemResult { + Hit { + memholder: Arc, + }, + Miss, + Error { + error_code: ErrorCode, + error_json: String, + }, +} + pub struct ExternalGetStartEntry { pub req_node_id: String, - pub shared_op: Arc, + /// Requester membership generation observed when this handle was created. + /// `None` is retained only for compatibility with a temporarily incomplete + /// cluster cache; generation cleanup must never guess in that case. + pub requester_node_start_time: Option, + pub keys: Vec, + pub items: Vec, + pub created_at: Instant, } /// Optional arguments for put operations @@ -1133,6 +1213,13 @@ pub struct PrecommitLocalVisibleInfo { mem_holder: Arc, } +#[derive(Debug)] +pub(crate) struct PendingLocalGetInfo { + get_id: u64, + put_id: crate::master_kv_router::put::PutIDForAKey, + mem_holder: Arc, +} + #[derive(Debug)] pub(crate) struct LocalSnapshotInfo { put_time_ms: u64, @@ -1146,8 +1233,8 @@ struct OwnerHotCacheEntry { weight_bytes: u32, } -#[derive(Clone, Debug, Hash, PartialEq, Eq)] -struct OwnerHotReplicaIdentity { +#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub(crate) struct OwnerHotReplicaIdentity { key: String, put_time_ms: u64, put_version: u32, @@ -1166,17 +1253,16 @@ impl OwnerHotReplicaIdentity { #[derive(Default)] struct OwnerHotCacheCounters { size_evictions: AtomicU64, - replica_enqueued: AtomicU64, - replica_completed: AtomicU64, - replica_already_satisfied: AtomicU64, - replica_failed: AtomicU64, - replica_obsolete: AtomicU64, - replica_dispatch_failed: AtomicU64, + source_evict_handoff_members: AtomicU64, + source_evict_committed_members: AtomicU64, + source_evict_restored_members: AtomicU64, + source_evict_obsolete: AtomicU64, + source_evict_dispatch_failed: AtomicU64, + source_evict_retry_scheduled: AtomicU64, + source_evict_retry_emitted: AtomicU64, + selection_debt_bytes: Arc, skipped_stale: AtomicU64, skipped_reclaim: AtomicU64, - skipped_duplicate: AtomicU64, - group_replica_triggers: AtomicU64, - group_members_enqueued: AtomicU64, group_trigger_duplicates: AtomicU64, group_trigger_incomplete: AtomicU64, grouped_put_done_batches: AtomicU64, @@ -1185,128 +1271,224 @@ struct OwnerHotCacheCounters { legacy_put_done_items: AtomicU64, } -const OWNER_HOT_REPLICA_OUTCOME_PENDING: u32 = 0; -const OWNER_HOT_REPLICA_OUTCOME_RECORDED: u32 = 1; +struct OwnerHotSelectionDebt { + weight_bytes: u64, + outstanding_bytes: Arc, + released: AtomicU32, +} + +impl OwnerHotSelectionDebt { + fn new(weight_bytes: u64, outstanding_bytes: Arc) -> Arc { + outstanding_bytes.fetch_add(weight_bytes, Ordering::AcqRel); + Arc::new(Self { + weight_bytes, + outstanding_bytes, + released: AtomicU32::new(0), + }) + } + + fn release(&self) { + if self + .released + .compare_exchange(0, 1, Ordering::AcqRel, Ordering::Acquire) + .is_ok() + { + self.outstanding_bytes + .fetch_update(Ordering::AcqRel, Ordering::Acquire, |current| { + Some(current.saturating_sub(self.weight_bytes)) + }) + .expect("owner hot selection debt update cannot fail"); + } + } +} + +#[derive(Clone)] +pub(crate) struct OwnerHotEvictionEvent { + key: String, + put_id: crate::master_kv_router::put::PutIDForAKey, + memory_info: Weak, + selection_debt: Arc, + /// Retry events already own one exact source-delete cohort. + retry: bool, + /// Exact owner source-delete cohort retained across RPC retries. Once set, + /// retries never re-expand or re-pin the local cohort. + source_eviction_cohort: + Option>, + /// Failure count follows the event while it is dispatched, preserving + /// exponential backoff across queue take/reinsert cycles. + retry_failures: u32, +} + +pub(crate) enum OwnerHotEvictionPreparation { + Ready { + trigger: OwnerHotReplicaIdentity, + sources: Vec<(OwnerHotReplicaIdentity, Arc)>, + }, + RetryableReclaimFence, + RetryableIncompleteCohort, + Obsolete, +} + +struct OwnerHotRetryEntry { + event: OwnerHotEvictionEvent, + failures: u32, + next_attempt_at: Instant, + dispatched: bool, +} + +#[derive(Default)] +struct OwnerHotRetryState { + entries: HashMap, + /// Exactly one deadline for each non-dispatched entry. Unlike a lazy + /// generation heap, rescheduling replaces the old tuple, so both memory + /// and lock-held work are bounded by the live retry set, not its history. + deadlines: BTreeSet<(Instant, OwnerHotReplicaIdentity)>, +} -pub(crate) struct OwnerHotReplicaGuard { - identity: OwnerHotReplicaIdentity, - inflight: Arc>, +/// Exactly-once owner-local retry state. It is physically bounded by the +/// owner committed-slot pool: one identity can occupy at most one entry, and +/// obsolete identities are removed when their local version is invalidated. +/// The actor emits only a small due batch and applies exponential backoff. +struct OwnerHotRetryQueue { + state: Mutex, + notify: Arc, counters: Arc, - group_trigger: Option, - group_replica_triggered: Arc>, - outcome: AtomicU32, } -impl OwnerHotReplicaGuard { - fn new( - identity: OwnerHotReplicaIdentity, - inflight: Arc>, - counters: Arc, - group_trigger: Option, - group_replica_triggered: Arc>, - ) -> Self { +impl OwnerHotRetryQueue { + fn new(counters: Arc) -> Self { Self { - identity, - inflight, + state: Mutex::new(OwnerHotRetryState::default()), + notify: Arc::new(limit_thirdparty::tokio::sync::Notify::new()), counters, - group_trigger, - group_replica_triggered, - outcome: AtomicU32::new(OWNER_HOT_REPLICA_OUTCOME_PENDING), } } - fn release_group_trigger(&self) { - if let Some(group_trigger) = self.group_trigger.as_ref() { - self.group_replica_triggered.remove(group_trigger); - } + fn retry_delay(failures: u32) -> Duration { + let shift = failures.saturating_sub(1).min(8); + Duration::from_millis(25u64.saturating_mul(1u64 << shift)).min(Duration::from_secs(5)) } - pub(crate) fn mark_completed(&self) { - if self - .outcome - .compare_exchange( - OWNER_HOT_REPLICA_OUTCOME_PENDING, - OWNER_HOT_REPLICA_OUTCOME_RECORDED, - Ordering::Relaxed, - Ordering::Relaxed, - ) - .is_ok() - { - self.counters - .replica_completed - .fetch_add(1, Ordering::Relaxed); + fn schedule(&self, mut event: OwnerHotEvictionEvent, reason: &'static str) { + let identity = OwnerHotReplicaIdentity { + key: event.key.clone(), + put_time_ms: event.put_id.0, + put_version: event.put_id.1, + }; + let now = Instant::now(); + let mut state = self.state.lock(); + let previous_deadline = state + .entries + .get(&identity) + .and_then(|entry| (!entry.dispatched).then_some(entry.next_attempt_at)); + if let Some(previous_deadline) = previous_deadline { + state + .deadlines + .remove(&(previous_deadline, identity.clone())); } - } - - pub(crate) fn mark_already_satisfied(&self) { - if self - .outcome - .compare_exchange( - OWNER_HOT_REPLICA_OUTCOME_PENDING, - OWNER_HOT_REPLICA_OUTCOME_RECORDED, - Ordering::Relaxed, - Ordering::Relaxed, - ) - .is_ok() - { - self.counters - .replica_already_satisfied - .fetch_add(1, Ordering::Relaxed); + let entry = state + .entries + .entry(identity.clone()) + .or_insert_with(|| OwnerHotRetryEntry { + event: event.clone(), + failures: event.retry_failures, + next_attempt_at: now, + dispatched: false, + }); + if !Arc::ptr_eq(&entry.event.selection_debt, &event.selection_debt) { + entry.event.selection_debt.release(); } + if event.source_eviction_cohort.is_none() { + event.source_eviction_cohort = entry.event.source_eviction_cohort.clone(); + } + entry.failures = entry.failures.max(event.retry_failures).saturating_add(1); + event.retry = true; + event.retry_failures = entry.failures; + entry.event = event; + entry.next_attempt_at = now + Self::retry_delay(entry.failures); + entry.dispatched = false; + let next_attempt_at = entry.next_attempt_at; + let inserted = state.deadlines.insert((next_attempt_at, identity.clone())); + debug_assert!(inserted, "owner retry deadline must be unique per identity"); + drop(state); + self.counters + .source_evict_retry_scheduled + .fetch_add(1, Ordering::Relaxed); + tracing::debug!( + key = identity.key, + put_time_ms = identity.put_time_ms, + put_version = identity.put_version, + reason, + "owner writeback entered retryable local state" + ); + self.notify.notify_waiters(); } - pub(crate) fn mark_obsolete(&self) { - if self - .outcome - .compare_exchange( - OWNER_HOT_REPLICA_OUTCOME_PENDING, - OWNER_HOT_REPLICA_OUTCOME_RECORDED, - Ordering::Relaxed, - Ordering::Relaxed, - ) - .is_ok() - { - self.counters - .replica_obsolete - .fetch_add(1, Ordering::Relaxed); - self.release_group_trigger(); + fn take_due_batch(&self, now: Instant, limit: usize) -> Vec { + let mut state = self.state.lock(); + let mut due = Vec::with_capacity(limit); + while due.len() < limit { + let Some((deadline, identity)) = state.deadlines.iter().next().cloned() else { + break; + }; + if deadline > now { + break; + } + state.deadlines.remove(&(deadline, identity.clone())); + let Some(entry) = state.entries.get_mut(&identity) else { + debug_assert!(false, "owner retry deadline must reference a live entry"); + continue; + }; + if entry.dispatched || entry.next_attempt_at != deadline { + debug_assert!(false, "owner retry deadline and entry must agree"); + continue; + } + due.push(entry.event.clone()); + // Keep the authoritative retry record until the dispatcher has + // atomically pinned the source and installed an inflight guard, + // but emit it only once. A failed dispatcher attempt explicitly + // reschedules it with the next backoff. + entry.dispatched = true; } + due } - fn mark_dispatch_failed(&self) { - if self - .outcome - .compare_exchange( - OWNER_HOT_REPLICA_OUTCOME_PENDING, - OWNER_HOT_REPLICA_OUTCOME_RECORDED, - Ordering::Relaxed, - Ordering::Relaxed, - ) - .is_ok() - { - self.counters - .replica_dispatch_failed - .fetch_add(1, Ordering::Relaxed); - self.release_group_trigger(); + fn remove(&self, identity: &OwnerHotReplicaIdentity) { + let entry = { + let mut state = self.state.lock(); + let entry = state.entries.remove(identity); + if let Some(entry) = entry.as_ref() + && !entry.dispatched + { + state + .deadlines + .remove(&(entry.next_attempt_at, identity.clone())); + } + entry + }; + if let Some(entry) = entry { + entry.event.selection_debt.release(); } } -} -impl Drop for OwnerHotReplicaGuard { - fn drop(&mut self) { - if self.outcome.load(Ordering::Relaxed) == OWNER_HOT_REPLICA_OUTCOME_PENDING { - self.counters.replica_failed.fetch_add(1, Ordering::Relaxed); - self.release_group_trigger(); + fn take_for_inflight( + &self, + identity: &OwnerHotReplicaIdentity, + ) -> Option { + // The inflight guard takes over the same debt token; do not release it. + let mut state = self.state.lock(); + let entry = state.entries.remove(identity)?; + if !entry.dispatched { + state + .deadlines + .remove(&(entry.next_attempt_at, identity.clone())); } - self.inflight.remove(&self.identity); + Some(entry.event) } -} -pub(crate) struct OwnerHotEvictionEvent { - key: String, - put_id: crate::master_kv_router::put::PutIDForAKey, - memory_info: Weak, - guard: OwnerHotReplicaGuard, + fn len(&self) -> usize { + self.state.lock().entries.len() + } } pub(crate) struct OwnerPreparedReclaim { @@ -1317,32 +1499,237 @@ pub(crate) struct OwnerPreparedReclaim { pub(crate) enum OwnerReclaimRecord { Prepared(OwnerPreparedReclaim), + /// The local index is fenced and the Commit handler owns the detached + /// backing while it updates the slot pool. Keeping this marker in the + /// per-key table lets that O(1) pool update happen without nesting the + /// pool mutex under the key-shard mutex. + Releasing(crate::master_kv_router::msg_pack::OwnerReclaimItem), Committed(crate::master_kv_router::msg_pack::OwnerReclaimItem), } #[derive(Default)] pub(crate) struct OwnerKeyControlState { local_puts: u32, + /// External Put contexts that may still expose or commit owner-local + /// backing for this key. This counter is maintained by an Arc-backed + /// guard stored in every context, so cache invalidation cannot clear the + /// reclaim fence while a cloned context is still in use. + external_pending_puts: u32, reclaim: Option, + /// Per-key owner-side Get singleflight marker. It deliberately lives in + /// the same fence as local visibility and reclaim so `R ∩ local`, + /// `R ∩ inflight`, and new leaders are classified atomically. + external_get: Option>, } -fn resolve_local_visible_batch( - keys: &[String], - controls: &HashMap, - mut resolve_unfenced: impl FnMut(&str) -> Option, -) -> Vec> { - keys.iter() - .map(|key| { - if controls - .get(key) - .is_some_and(|state| state.reclaim.is_some()) - { - None - } else { - resolve_unfenced(key) +impl OwnerKeyControlState { + fn is_idle(&self) -> bool { + self.local_puts == 0 + && self.external_pending_puts == 0 + && self.reclaim.is_none() + && self.external_get.is_none() + } +} + +const OWNER_KEY_CONTROL_SHARDS: usize = 256; + +/// Per-key owner fencing without a process-wide mutex. +/// +/// Every operation for one key hashes to the same shard, so local index +/// publication, Get singleflight registration, and reclaim remain linearized. +/// Callers must hold a shard only for one key and must not await, perform RPC, +/// or walk a request batch while holding it. Unrelated keys normally proceed +/// on independent shards; a hash collision only adds a short O(1) critical +/// section and does not change correctness. +pub(crate) struct OwnerKeyControlTable { + shards: Box<[Mutex>]>, +} + +impl Default for OwnerKeyControlTable { + fn default() -> Self { + Self { + shards: (0..OWNER_KEY_CONTROL_SHARDS) + .map(|_| Mutex::new(HashMap::new())) + .collect(), + } + } +} + +impl OwnerKeyControlTable { + fn shard_index(key: &str) -> usize { + let mut hasher = std::collections::hash_map::DefaultHasher::new(); + key.hash(&mut hasher); + (hasher.finish() as usize) % OWNER_KEY_CONTROL_SHARDS + } + + pub(crate) fn lock_key( + &self, + key: &str, + ) -> parking_lot::MutexGuard<'_, HashMap> { + self.shards[Self::shard_index(key)].lock() + } +} + +pub(crate) struct ExternalPendingPutFenceGuard { + key: String, + owner_key_control: Arc, + owns_local_put: bool, + local_slot_cleanup_view: Option, + local_slot_lease: Mutex>, + local_slot_release_failed: std::sync::atomic::AtomicBool, +} + +impl std::fmt::Debug for ExternalPendingPutFenceGuard { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter + .debug_struct("ExternalPendingPutFenceGuard") + .field("key", &self.key) + .field("owns_local_put", &self.owns_local_put) + .finish_non_exhaustive() + } +} + +impl ExternalPendingPutFenceGuard { + pub(crate) fn attach_local_slot_lease(&self, lease: OwnerLocalReserveSlotLease) { + assert!( + self.owns_local_put, + "only local-first Put owns a slot lease" + ); + assert_eq!( + lease.slots.len(), + 1, + "a pending local-first Put fence must own exactly one slot" + ); + let mut current = self.local_slot_lease.lock(); + assert!( + current.is_none(), + "a pending local-first Put fence cannot replace its slot lease" + ); + *current = Some(lease); + } + + /// Transfer the prepared slot to the precommit/committed MemoryInfo. Once + /// disarmed, dropping the pending context must not return that resident slot + /// to the free list. + pub(crate) fn disarm_local_slot_lease(&self) { + assert!( + self.local_slot_lease.lock().take().is_some(), + "pending local-first Put slot lease is absent while committing" + ); + } + + pub(crate) async fn release_local_slot_lease_now( + &self, + inner: &ClientKvApiInner, + ) -> KvResult<()> { + let lease = self.local_slot_lease.lock().take(); + if let Some(lease) = lease { + if let Err(err) = inner.owner_release_local_reserve_slot_lease(lease).await { + // The lease object has been consumed and the physical state is + // now uncertain. Keep the per-key fence permanently rather + // than allow reclaim to cross a possibly-live prepared slot. + self.local_slot_release_failed + .store(true, Ordering::Release); + return Err(err); } - }) - .collect() + } + Ok(()) + } +} + +fn release_external_pending_put_counts( + owner_key_control: &Arc, + key: &str, + owns_local_put: bool, +) { + let mut controls = owner_key_control.lock_key(key); + let remove = { + let state = controls + .get_mut(key) + .expect("external pending Put fence state missing on release"); + state.external_pending_puts = state + .external_pending_puts + .checked_sub(1) + .expect("external pending Put fence counter underflow"); + if owns_local_put { + state.local_puts = state + .local_puts + .checked_sub(1) + .expect("owner local-first Put fence counter underflow"); + } + state.is_idle() + }; + if remove { + controls.remove(key); + } +} + +fn acquire_external_pending_put_fence_for_key( + owner_key_control: &Arc, + key: &str, +) -> KvResult> { + let mut controls = owner_key_control.lock_key(key); + if controls + .get(key) + .is_some_and(|state| state.reclaim.is_some()) + { + return Err(KvError::Api(ApiError::KeyBeingWritten { + key: key.to_string(), + })); + } + let state = controls.entry(key.to_string()).or_default(); + state.external_pending_puts = state + .external_pending_puts + .checked_add(1) + .expect("external pending Put fence counter overflow"); + Ok(Arc::new(ExternalPendingPutFenceGuard { + key: key.to_string(), + owner_key_control: owner_key_control.clone(), + owns_local_put: false, + local_slot_cleanup_view: None, + local_slot_lease: Mutex::new(None), + local_slot_release_failed: std::sync::atomic::AtomicBool::new(false), + })) +} + +impl Drop for ExternalPendingPutFenceGuard { + fn drop(&mut self) { + let abandoned_slot_lease = self.local_slot_lease.get_mut().take(); + if let Some(lease) = abandoned_slot_lease { + let view = self + .local_slot_cleanup_view + .as_ref() + .expect("local-first Put slot cleanup requires an attached owner view") + .clone(); + let worker_view = view.clone(); + let key = self.key.clone(); + let owner_key_control = self.owner_key_control.clone(); + let owns_local_put = self.owns_local_put; + view.spawn("external_pending_put_slot_drop_cleanup", async move { + if let Err(err) = worker_view + .client_kv_api() + .inner() + .owner_release_local_reserve_slot_lease(lease) + .await + { + tracing::error!("pending local-first Put slot Drop cleanup failed: {}", err); + return; + } + release_external_pending_put_counts(&owner_key_control, &key, owns_local_put); + }); + } else if !self.local_slot_release_failed.load(Ordering::Acquire) { + release_external_pending_put_counts( + &self.owner_key_control, + &self.key, + self.owns_local_put, + ); + } else { + tracing::error!( + "retaining pending Put fence after local slot release failure: key={}", + self.key + ); + } + } } fn allocate_external_holding_id(counter: &AtomicU64) -> u64 { @@ -1371,46 +1758,74 @@ fn clone_if_owner_hot_entry_matches( .then(|| current.clone()) } -fn pin_current_owner_hot_source( - key: &str, - entry: &OwnerHotCacheEntry, - owner_key_control: &Mutex>, - get_cached_info: &DashMap, - counters: &OwnerHotCacheCounters, -) -> Option> { - let controls = owner_key_control.lock(); - if controls - .get(key) - .is_some_and(|state| state.reclaim.is_some()) - { - counters.skipped_reclaim.fetch_add(1, Ordering::Relaxed); - return None; - } - let Some(cached) = get_cached_info.get(key) else { - counters.skipped_stale.fetch_add(1, Ordering::Relaxed); - return None; +enum OwnerHotPinResult { + Pinned(Arc), + ReclaimBusy, + Stale, +} + +fn pin_current_owner_hot_source_from_index( + entry_put_id: crate::master_kv_router::put::PutIDForAKey, + entry: &Weak, + resolve_current: impl FnOnce() -> Option<(crate::master_kv_router::put::PutIDForAKey, Arc)>, +) -> OwnerHotPinResult { + let Some((current_put_id, current)) = resolve_current() else { + // Do not upgrade the listener's Weak after the local index has + // disappeared. A reclaim Prepare may already own the sole Arc and + // Commit relies on that ownership. A still-live Weak therefore means + // "retry after the transient owner transition"; a dead Weak is + // definitively obsolete. + return if entry.strong_count() == 0 { + OwnerHotPinResult::Stale + } else { + OwnerHotPinResult::ReclaimBusy + }; }; - let Some(pinned) = clone_if_owner_hot_entry_matches( - (cached.put_time_ms, cached.put_version), - &cached.mem_holder, - entry.put_id, - &entry.memory_info, - ) else { - counters.skipped_stale.fetch_add(1, Ordering::Relaxed); - return None; + let Some(pinned) = + clone_if_owner_hot_entry_matches(current_put_id, ¤t, entry_put_id, entry) + else { + return OwnerHotPinResult::Stale; }; - // This clone is made under the same key fence used by reclaim. If reclaim - // wins first the source is absent/fenced; if this clone wins, reclaim sees - // the additional strong reference and returns Busy. - Some(pinned) + // `resolve_current` clones from the DashMap entry while its shard read + // guard is held. Reclaim Prepare cannot remove that entry until the clone + // exists, and its strong-count check will consequently return Busy. This + // gives us the required per-key pin without the global owner-control lock. + Some(pinned).map_or(OwnerHotPinResult::Stale, OwnerHotPinResult::Pinned) } -fn owner_hot_group_anchor_identity( - group: &crate::master_kv_router::msg_pack::PutAtomicGroup, -) -> Option { - group - .members +fn pin_current_owner_hot_source( + key: &str, + entry: &OwnerHotCacheEntry, + get_cached_info: &DashMap, + counters: &OwnerHotCacheCounters, +) -> OwnerHotPinResult { + let result = pin_current_owner_hot_source_from_index(entry.put_id, &entry.memory_info, || { + get_cached_info.get(key).map(|cached| { + ( + (cached.put_time_ms, cached.put_version), + cached.mem_holder.clone(), + ) + }) + }); + match result { + OwnerHotPinResult::Pinned(pinned) => OwnerHotPinResult::Pinned(pinned), + OwnerHotPinResult::ReclaimBusy => { + counters.skipped_reclaim.fetch_add(1, Ordering::Relaxed); + OwnerHotPinResult::ReclaimBusy + } + OwnerHotPinResult::Stale => { + counters.skipped_stale.fetch_add(1, Ordering::Relaxed); + OwnerHotPinResult::Stale + } + } +} + +fn owner_hot_group_anchor_identity( + group: &crate::master_kv_router::msg_pack::PutAtomicGroup, +) -> Option { + group + .members .first() .map(OwnerHotReplicaIdentity::from_group_member) } @@ -1454,7 +1869,6 @@ fn forget_owner_hot_atomic_group( OwnerHotReplicaIdentity, Arc, >, - group_replica_triggered: &DashSet, identity: &OwnerHotReplicaIdentity, ) { let group = atomic_groups @@ -1463,9 +1877,6 @@ fn forget_owner_hot_atomic_group( let Some(group) = group else { return; }; - if let Some(anchor) = owner_hot_group_anchor_identity(group.as_ref()) { - group_replica_triggered.remove(&anchor); - } for member in &group.members { atomic_groups.remove(&OwnerHotReplicaIdentity::from_group_member(member)); } @@ -1473,22 +1884,13 @@ fn forget_owner_hot_atomic_group( fn pin_current_owner_hot_group_sources( group: &crate::master_kv_router::msg_pack::PutAtomicGroup, - owner_key_control: &Mutex>, get_cached_info: &DashMap, counters: &OwnerHotCacheCounters, ) -> Option)>> { - let controls = owner_key_control.lock(); let mut sources = Vec::with_capacity(group.members.len()); for member in &group.members { - if controls - .get(&member.key) - .is_some_and(|state| state.reclaim.is_some()) - { - counters.skipped_reclaim.fetch_add(1, Ordering::Relaxed); - return None; - } let Some(cached) = get_cached_info.get(&member.key) else { - counters.skipped_stale.fetch_add(1, Ordering::Relaxed); + counters.skipped_reclaim.fetch_add(1, Ordering::Relaxed); return None; }; if (cached.put_time_ms, cached.put_version) != member.put_id { @@ -1555,7 +1957,6 @@ fn owner_hot_tp_cohort_key_rows( fn pin_current_owner_hot_tp_cohort_sources( cohort_key_rows: &[Vec], expect_atomic_group: bool, - owner_key_control: &Mutex>, get_cached_info: &DashMap, atomic_groups: &DashMap< OwnerHotReplicaIdentity, @@ -1563,7 +1964,6 @@ fn pin_current_owner_hot_tp_cohort_sources( >, counters: &OwnerHotCacheCounters, ) -> Option)>> { - let controls = owner_key_control.lock(); let mut cohort_sources = Vec::new(); for rank_keys in cohort_key_rows { if rank_keys.is_empty() { @@ -1571,15 +1971,8 @@ fn pin_current_owner_hot_tp_cohort_sources( } let mut rank_sources = Vec::with_capacity(rank_keys.len()); for key in rank_keys { - if controls - .get(key) - .is_some_and(|state| state.reclaim.is_some()) - { - counters.skipped_reclaim.fetch_add(1, Ordering::Relaxed); - return None; - } let Some(cached) = get_cached_info.get(key) else { - counters.skipped_stale.fetch_add(1, Ordering::Relaxed); + counters.skipped_reclaim.fetch_add(1, Ordering::Relaxed); return None; }; rank_sources.push(( @@ -1625,61 +2018,11 @@ fn pin_current_owner_hot_tp_cohort_sources( Some(cohort_sources) } -fn try_enqueue_owner_hot_replica_event( - identity: OwnerHotReplicaIdentity, - memory_info: Arc, - group_trigger: Option, - inflight: &Arc>, - group_replica_triggered: &Arc>, - counters: &Arc, - eviction_tx: &tokio::sync::ampsc::Sender, -) -> bool { - if !inflight.insert(identity.clone()) { - counters.skipped_duplicate.fetch_add(1, Ordering::Relaxed); - return false; - } - let event = OwnerHotEvictionEvent { - key: identity.key.clone(), - put_id: (identity.put_time_ms, identity.put_version), - memory_info: Arc::downgrade(&memory_info), - guard: OwnerHotReplicaGuard::new( - identity, - inflight.clone(), - counters.clone(), - group_trigger, - group_replica_triggered.clone(), - ), - }; - match eviction_tx.try_send(event) { - Ok(()) => { - counters.replica_enqueued.fetch_add(1, Ordering::Relaxed); - true - } - Err(err) => { - let event = err.into_inner(); - tracing::warn!( - "owner hot-cache eviction actor is closed; replica event dropped: key={} put_id=({},{})", - event.key, - event.put_id.0, - event.put_id.1 - ); - event.guard.mark_dispatch_failed(); - false - } - } -} - fn build_owner_hot_cache( capacity_bytes: u64, - owner_key_control: Arc>>, - get_cached_info: Arc>, - inflight: Arc>, - atomic_groups: Arc< - DashMap>, - >, - group_replica_triggered: Arc>, counters: Arc, - eviction_tx: tokio::sync::ampsc::Sender, + retry_queue: Arc, + eviction_tx: tokio::sync::ampsc::UnboundedSender, ) -> moka::sync::Cache { assert!( capacity_bytes > 0, @@ -1693,90 +2036,31 @@ fn build_owner_hot_cache( return; } counters.size_evictions.fetch_add(1, Ordering::Relaxed); - let Some(memory_info) = pin_current_owner_hot_source( - key.as_str(), - &entry, - owner_key_control.as_ref(), - get_cached_info.as_ref(), - counters.as_ref(), - ) else { - return; - }; let identity = OwnerHotReplicaIdentity { key: (*key).clone(), put_time_ms: entry.put_id.0, put_version: entry.put_id.1, }; - let group = atomic_groups - .get(&identity) - .map(|entry| entry.value().clone()); - let cohort_sources = match owner_hot_tp_cohort_key_rows(&identity, group.as_deref()) { - Ok(Some(cohort_key_rows)) => pin_current_owner_hot_tp_cohort_sources( - &cohort_key_rows, - group.is_some(), - owner_key_control.as_ref(), - get_cached_info.as_ref(), - atomic_groups.as_ref(), - counters.as_ref(), - ), - Ok(None) => match group.as_deref() { - Some(group) => pin_current_owner_hot_group_sources( - group, - owner_key_control.as_ref(), - get_cached_info.as_ref(), - counters.as_ref(), - ), - None => Some(vec![(identity.clone(), memory_info)]), - }, - Err(()) => None, - }; - let Some(cohort_sources) = cohort_sources else { - counters - .group_trigger_incomplete - .fetch_add(1, Ordering::Relaxed); - return; + let selection_debt = OwnerHotSelectionDebt::new( + u64::from(entry.weight_bytes), + counters.selection_debt_bytes.clone(), + ); + let event = OwnerHotEvictionEvent { + key: identity.key.clone(), + put_id: entry.put_id, + memory_info: entry.memory_info.clone(), + selection_debt, + retry: false, + source_eviction_cohort: None, + retry_failures: 0, }; - if cohort_sources.len() > 1 { + if let Err(err) = eviction_tx.send(event) { + let event = err.0; counters - .group_replica_triggers + .source_evict_dispatch_failed .fetch_add(1, Ordering::Relaxed); - let mut enqueued = 0u64; - for (member_identity, member_memory_info) in cohort_sources { - if try_enqueue_owner_hot_replica_event( - member_identity, - member_memory_info, - None, - &inflight, - &group_replica_triggered, - &counters, - &eviction_tx, - ) { - enqueued = enqueued.saturating_add(1); - } - } - counters - .group_members_enqueued - .fetch_add(enqueued, Ordering::Relaxed); - if enqueued == 0 { - counters - .group_trigger_duplicates - .fetch_add(1, Ordering::Relaxed); - } - return; + retry_queue.schedule(event, "eviction dispatcher closed"); } - let (identity, memory_info) = cohort_sources - .into_iter() - .next() - .expect("owner hot cohort must contain its trigger source"); - let _ = try_enqueue_owner_hot_replica_event( - identity, - memory_info, - None, - &inflight, - &group_replica_triggered, - &counters, - &eviction_tx, - ); }) .build() } @@ -1833,31 +2117,42 @@ pub struct ClientKvApiInner { get_cached_info: Arc>, /// key -> locally readable resident slot before backend put_start/put_done finishes. precommit_local_visible_info: DashMap, + /// Transferred Get targets awaiting an idempotent master GetDone result. + /// These entries fence reclaim but are never visible to readers. + pending_local_get_info: DashMap, /// key -> local replica version remembered from local put/get durable-replica success. /// This authority is positive-only: hit means "can answer exists=true immediately when /// allow_local_snapshot is enabled"; miss does not imply non-existence. local_snapshot_info: DashMap, /// KvOwner-managed resident staging grants for hostless put_start. owner_local_reserve_pool: Mutex, - /// Serialize reserve claims so a later waiter cannot steal slots reclaimed for the - /// waiter currently assembling a lease. Tokio's mutex provides FIFO acquisition order. - owner_local_reserve_claim_lock: limit_thirdparty::tokio::sync::AMutex<()>, + /// Serialize claims only within one slot-size class. Tokio's mutex provides FIFO + /// acquisition order for equal-size waiters without making an unrelated class wait + /// behind a pressured class. + owner_local_reserve_claim_locks: DashMap>>, /// Wake the background reserve actor after demand/free-slot changes. owner_local_reserve_rebalance_notify: Arc, /// Owner-local write-back put ids for external local-first path. external_local_first_put_id_counter: AtomicU32, - /// Atomic owner-side gate for local-first puts, local index access, and reclaim fencing. - owner_key_control: Arc>>, + /// Correlates idempotent owner source-eviction batches in logs and RPC responses. + next_owner_source_eviction_operation_id: AtomicU64, + /// Sharded per-key gate for local-first puts, local index access, and reclaim fencing. + owner_key_control: Arc, /// A weak-value admission/recency tier. It never owns resident memory and /// therefore cannot become a second physical-reclaim authority. owner_hot_cache: Option>, - owner_hot_replica_inflight: Arc>, + /// Exact selected identities remain here until their backing is physically + /// Free or the source is restored to owner-hot. + owner_source_eviction_selected: + Arc>>, owner_hot_atomic_groups: Arc< DashMap>, >, - owner_hot_group_replica_triggered: Arc>, owner_hot_counters: Arc, - owner_hot_eviction_rx: Mutex>>, + owner_hot_retry_queue: Arc, + owner_hot_eviction_tx: tokio::sync::ampsc::UnboundedSender, + owner_hot_eviction_rx: + Mutex>>, /// Shared delete actor input for owner -> external weak-index invalidation. pub external_invalidate_delete: EnsureMemholderMgmtDeleteHandle, @@ -1868,8 +2163,11 @@ pub struct ClientKvApiInner { // record external_client get_holding info (owned, flattened manager) pub external_get_holding: OwnerExternalMemMgr, - pub external_get_start_registry: DashMap>, - pub external_get_start_by_key: DashMap>, + pub external_get_start_registry: DashMap, + /// Metrics-only weak index of active per-key Get flights. Correctness + /// remains in the sharded key-control table; observing metrics must never + /// scan or hold those fences. + external_get_flight_registry: DashMap>, next_external_get_start_handle: AtomicU64, /// External holding identities are independent from upstream and resident holder ids. next_external_holding_id: AtomicU64, @@ -1901,8 +2199,11 @@ pub struct ClientKvApiInner { rpc_caller_batch_prepare_put_keys: RPCCaller, rpc_caller_batch_release_put_key_reservations: RPCCaller, rpc_caller_put_append_start: RPCCaller, + rpc_caller_batch_put_append_start: RPCCaller, rpc_caller_put_append_revoke: RPCCaller, rpc_caller_put_append_done: RPCCaller, + rpc_caller_batch_put_append_done: RPCCaller, + rpc_caller_batch_evict_owner_source: RPCCaller, rpc_caller_reserve_local_grant: RPCCaller, rpc_caller_release_local_grant: RPCCaller, rpc_caller_delete: RPCCaller, @@ -1933,6 +2234,34 @@ impl ClientKvApiInner { &self.view } + pub(crate) fn track_external_get_flight(&self, op: &Arc) { + self.external_get_flight_registry + .insert(op.key.clone(), Arc::downgrade(op)); + } + + pub(crate) fn untrack_external_get_flight(&self, op: &Arc) { + let weak = Arc::downgrade(op); + self.external_get_flight_registry + .remove_if(&op.key, |_, current| Weak::ptr_eq(current, &weak)); + } + + fn external_get_flight_snapshot(&self) -> Vec> { + let mut ops = Vec::new(); + let mut stale = Vec::new(); + for entry in &self.external_get_flight_registry { + if let Some(op) = entry.value().upgrade() { + ops.push(op); + } else { + stale.push(entry.key().clone()); + } + } + for key in stale { + self.external_get_flight_registry + .remove_if(&key, |_, weak| weak.strong_count() == 0); + } + ops + } + fn owner_hot_register_atomic_group( &self, group: &crate::master_kv_router::msg_pack::PutAtomicGroup, @@ -1941,11 +2270,84 @@ impl ClientKvApiInner { } fn owner_hot_forget_atomic_group_for_member(&self, identity: &OwnerHotReplicaIdentity) { - forget_owner_hot_atomic_group( - self.owner_hot_atomic_groups.as_ref(), - self.owner_hot_group_replica_triggered.as_ref(), - identity, - ); + forget_owner_hot_atomic_group(self.owner_hot_atomic_groups.as_ref(), identity); + } + + pub(crate) fn owner_hot_prepare_eviction( + &self, + event: &OwnerHotEvictionEvent, + ) -> OwnerHotEvictionPreparation { + let trigger = OwnerHotReplicaIdentity { + key: event.key.clone(), + put_time_ms: event.put_id.0, + put_version: event.put_id.1, + }; + let cache_entry = OwnerHotCacheEntry { + put_id: event.put_id, + memory_info: event.memory_info.clone(), + weight_bytes: 0, + }; + let memory_info = match pin_current_owner_hot_source( + event.key.as_str(), + &cache_entry, + self.get_cached_info.as_ref(), + self.owner_hot_counters.as_ref(), + ) { + OwnerHotPinResult::Pinned(memory_info) => memory_info, + OwnerHotPinResult::ReclaimBusy => { + return OwnerHotEvictionPreparation::RetryableReclaimFence; + } + OwnerHotPinResult::Stale => return OwnerHotEvictionPreparation::Obsolete, + }; + + // A retry is authoritative for exactly one previously selected key. + // Re-expanding it would pin every cohort member again while the safe + // reclaim pipeline is waiting for those very pins to disappear. + if event.retry { + return OwnerHotEvictionPreparation::Ready { + trigger: trigger.clone(), + sources: vec![(trigger, memory_info)], + }; + } + + // Cohort lookup and pinning deliberately happen here, after the + // synchronous Moka listener has returned. Each source Arc is cloned + // directly from its current DashMap entry. A concurrent reclaim must + // wait for that shard read guard and then observes the extra strong + // reference, so no global owner-control lock is needed. + let group = self + .owner_hot_atomic_groups + .get(&trigger) + .map(|entry| entry.value().clone()); + let cohort_sources = match owner_hot_tp_cohort_key_rows(&trigger, group.as_deref()) { + Ok(Some(cohort_key_rows)) => pin_current_owner_hot_tp_cohort_sources( + &cohort_key_rows, + group.is_some(), + self.get_cached_info.as_ref(), + self.owner_hot_atomic_groups.as_ref(), + self.owner_hot_counters.as_ref(), + ), + Ok(None) => match group.as_deref() { + Some(group) => pin_current_owner_hot_group_sources( + group, + self.get_cached_info.as_ref(), + self.owner_hot_counters.as_ref(), + ), + None => Some(vec![(trigger.clone(), memory_info)]), + }, + Err(()) => None, + }; + match cohort_sources { + Some(sources) if !sources.is_empty() => { + OwnerHotEvictionPreparation::Ready { trigger, sources } + } + _ => { + self.owner_hot_counters + .group_trigger_incomplete + .fetch_add(1, Ordering::Relaxed); + OwnerHotEvictionPreparation::RetryableIncompleteCohort + } + } } fn owner_hot_track_committed( @@ -1977,6 +2379,22 @@ impl ClientKvApiInner { } } + pub(crate) fn owner_hot_admit_published_committed( + &self, + key: &str, + put_id: crate::master_kv_router::put::PutIDForAKey, + atomic_group: Option<&crate::master_kv_router::msg_pack::PutAtomicGroup>, + ) -> bool { + let memory_info = self.get_cached_info.get(key).and_then(|cached| { + ((cached.put_time_ms, cached.put_version) == put_id).then(|| cached.mem_holder.clone()) + }); + let Some(memory_info) = memory_info else { + return false; + }; + self.owner_hot_track_committed(key, put_id, &memory_info, atomic_group); + true + } + fn owner_hot_touch_or_promote( &self, key: &str, @@ -2000,7 +2418,7 @@ impl ClientKvApiInner { put_id: crate::master_kv_router::put::PutIDForAKey, memory_info: &Arc, ) -> bool { - let controls = self.owner_key_control.lock(); + let controls = self.owner_key_control.lock_key(key); if controls .get(key) .is_some_and(|state| state.reclaim.is_some()) @@ -2019,24 +2437,31 @@ impl ClientKvApiInner { key: &str, put_id: crate::master_kv_router::put::PutIDForAKey, ) { - let Some(cache) = self.owner_hot_cache.as_ref() else { - return; - }; - let _ = cache.entry(key.to_string()).and_compute_with(|entry| { - if entry - .as_ref() - .is_some_and(|entry| entry.value().put_id == put_id) - { - MokaComputeOp::Remove - } else { - MokaComputeOp::Nop - } - }); - self.owner_hot_forget_atomic_group_for_member(&OwnerHotReplicaIdentity { + let identity = OwnerHotReplicaIdentity { key: key.to_string(), put_time_ms: put_id.0, put_version: put_id.1, - }); + }; + if let Some(cache) = self.owner_hot_cache.as_ref() { + let _ = cache.entry(key.to_string()).and_compute_with(|entry| { + if entry + .as_ref() + .is_some_and(|entry| entry.value().put_id == put_id) + { + MokaComputeOp::Remove + } else { + MokaComputeOp::Nop + } + }); + } + if let Some((_identity, debt)) = self.owner_source_eviction_selected.remove(&identity) { + debt.release(); + self.owner_hot_counters + .source_evict_committed_members + .fetch_add(1, Ordering::Relaxed); + } + self.owner_hot_retry_queue.remove(&identity); + self.owner_hot_forget_atomic_group_for_member(&identity); } pub(crate) fn release_local_reserve_route_for_memory_info(&self, memory_info: &MemoryInfo) { @@ -2103,8 +2528,8 @@ impl ClientKvApiInner { key: &str, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, - ) -> KvResult<()> { - let mut controls = self.owner_key_control.lock(); + ) -> KvResult> { + let mut controls = self.owner_key_control.lock_key(key); if controls .get(key) .is_some_and(|state| state.reclaim.is_some()) @@ -2115,6 +2540,7 @@ impl ClientKvApiInner { } if reject_if_exist_same_key && (self.precommit_local_visible_info.contains_key(key) + || self.pending_local_get_info.contains_key(key) || self.get_cached_info.contains_key(key) || self.local_snapshot_info.contains_key(key)) { @@ -2132,24 +2558,25 @@ impl ClientKvApiInner { .local_puts .checked_add(1) .expect("owner local-first put counter overflow"); - Ok(()) + state.external_pending_puts = state + .external_pending_puts + .checked_add(1) + .expect("external pending Put fence counter overflow"); + Ok(Arc::new(ExternalPendingPutFenceGuard { + key: key.to_string(), + owner_key_control: self.owner_key_control.clone(), + owns_local_put: true, + local_slot_cleanup_view: Some(self.view.clone_view()), + local_slot_lease: Mutex::new(None), + local_slot_release_failed: std::sync::atomic::AtomicBool::new(false), + })) } - pub(crate) fn release_external_local_first_put_key(&self, key: &str) { - let mut controls = self.owner_key_control.lock(); - let remove = { - let state = controls - .get_mut(key) - .expect("owner local-first put state missing on release"); - state.local_puts = state - .local_puts - .checked_sub(1) - .expect("owner local-first put counter underflow"); - state.local_puts == 0 && state.reclaim.is_none() - }; - if remove { - controls.remove(key); - } + pub(crate) fn acquire_external_pending_put_fence( + &self, + key: &str, + ) -> KvResult> { + acquire_external_pending_put_fence_for_key(&self.owner_key_control, key) } pub(crate) fn remember_local_snapshot( @@ -2157,7 +2584,7 @@ impl ClientKvApiInner { key: &str, put_id: crate::master_kv_router::put::PutIDForAKey, ) { - let controls = self.owner_key_control.lock(); + let controls = self.owner_key_control.lock_key(key); if controls .get(key) .is_some_and(|state| state.reclaim.is_some()) @@ -2180,7 +2607,7 @@ impl ClientKvApiInner { } pub(crate) fn has_local_snapshot(&self, key: &str) -> bool { - let controls = self.owner_key_control.lock(); + let controls = self.owner_key_control.lock_key(key); if controls .get(key) .is_some_and(|state| state.reclaim.is_some()) @@ -2194,7 +2621,7 @@ impl ClientKvApiInner { pub(crate) fn local_visible_mem_holder(&self, key: &str) -> Option> { let (memory_info, hot_put_id) = { - let controls = self.owner_key_control.lock(); + let controls = self.owner_key_control.lock_key(key); if controls .get(key) .is_some_and(|state| state.reclaim.is_some()) @@ -2227,7 +2654,7 @@ impl ClientKvApiInner { key: &str, put_id: crate::master_kv_router::put::PutIDForAKey, ) -> Option> { - let controls = self.owner_key_control.lock(); + let controls = self.owner_key_control.lock_key(key); if controls .get(key) .is_some_and(|state| state.reclaim.is_some()) @@ -2253,13 +2680,19 @@ impl ClientKvApiInner { &self, keys: &[String], ) -> Vec>> { - // A hostless get_start commonly checks hundreds of pages from one - // local prefix. Take one coherent reclaim-fence snapshot instead of - // locking owner_key_control once per page. The MemoryInfo Arcs keep - // any selected backing alive if reclaim begins after this snapshot. - let resolved = { - let controls = self.owner_key_control.lock(); - resolve_local_visible_batch(keys, &controls, |key| { + // Resolve each page under only its own short sharded fence. The batch + // itself never owns a synchronous lock. A cloned MemoryInfo pins the + // selected backing if reclaim starts after this point. + let resolved = keys + .iter() + .map(|key| { + let controls = self.owner_key_control.lock_key(key); + if controls + .get(key) + .is_some_and(|state| state.reclaim.is_some()) + { + return None; + } let memory_info = self.local_visible_mem_holder_unfenced(key)?; let hot_put_id = self .get_cached_info @@ -2268,7 +2701,7 @@ impl ClientKvApiInner { .map(|cached| (cached.put_time_ms, cached.put_version)); Some((memory_info, hot_put_id)) }) - }; + .collect::>(); resolved .into_iter() .zip(keys) @@ -2299,6 +2732,11 @@ impl ClientKvApiInner { ExternalHoldingGetInfo { key: memory_info.key.clone(), req_node_id: req_node_id.to_string(), + requester_node_start_time: self + .view + .cluster_manager() + .get_member_info_cached(req_node_id) + .map(|member| member.node_start_time), memory_info, }, ); @@ -2334,6 +2772,140 @@ impl ClientKvApiInner { ) } + pub(crate) fn install_hidden_pending_local_get( + &self, + key: &str, + get_id: u64, + put_id: crate::master_kv_router::put::PutIDForAKey, + addr: u64, + base_addr: u64, + len: u32, + slot_size: u64, + grant_id: u64, + slot_index: u32, + ) -> KvResult> { + let controls = self.owner_key_control.lock_key(key); + if controls + .get(key) + .is_some_and(|state| state.reclaim.is_some()) + || self.pending_local_get_info.contains_key(key) + { + return Err(KvError::Api(ApiError::KeyBeingWritten { + key: key.to_string(), + })); + } + self.owner_mark_local_reserve_slot_pending_visible(slot_size, grant_id, slot_index)?; + self.owner_retain_local_reserve_resident_slot_holder(slot_size, grant_id, slot_index)?; + let resident_owner_node_id: NodeID = self.view.cluster_manager().get_self_info().id.into(); + let memory_info = Arc::new(MemoryInfo::new_local_reserve_resident_with_base( + addr, + base_addr, + len, + key.to_string(), + resident_owner_node_id, + self.view.clone(), + slot_size, + grant_id, + slot_index, + )); + let previous = self.pending_local_get_info.insert( + key.to_string(), + PendingLocalGetInfo { + get_id, + put_id, + mem_holder: memory_info.clone(), + }, + ); + assert!( + previous.is_none(), + "pending local Get must be unique per key" + ); + drop(controls); + Ok(memory_info) + } + + pub(crate) fn abort_hidden_pending_local_get(&self, key: &str, get_id: u64) -> bool { + let _controls = self.owner_key_control.lock_key(key); + self.pending_local_get_info + .remove_if(key, |_, pending| pending.get_id == get_id) + .is_some() + } + + pub(crate) fn promote_hidden_pending_local_get( + &self, + key: &str, + get_id: u64, + put_id: crate::master_kv_router::put::PutIDForAKey, + ) -> KvResult> { + let memory_info = { + let controls = self.owner_key_control.lock_key(key); + if controls + .get(key) + .is_some_and(|state| state.reclaim.is_some()) + { + return Err(KvError::Api(ApiError::KeyBeingWritten { + key: key.to_string(), + })); + } + let Some(pending_memory_info) = + self.pending_local_get_info.get(key).and_then(|pending| { + (pending.get_id == get_id && pending.put_id == put_id) + .then(|| pending.mem_holder.clone()) + }) + else { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "hidden pending local Get is absent: key={} get_id={}", + key, get_id + ), + })); + }; + let (slot_size, grant_id, slot_index) = pending_memory_info + .local_reserve_resident_slot_ref() + .expect("pending local Get must carry a local-reserve slot"); + self.owner_promote_local_reserve_pending_slot_to_committed( + slot_size, grant_id, slot_index, + )?; + let removed = self + .pending_local_get_info + .remove_if(key, |_, pending| { + pending.get_id == get_id + && pending.put_id == put_id + && Arc::ptr_eq(&pending.mem_holder, &pending_memory_info) + }) + .is_some(); + if !removed { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "hidden pending local Get changed while promoting: key={} get_id={}", + key, get_id + ), + })); + } + let replaced = self.get_cached_info.insert( + key.to_string(), + GetCachedInfo { + put_time_ms: put_id.0, + put_version: put_id.1, + mem_holder: pending_memory_info.clone(), + }, + ); + if let Some(previous) = replaced { + self.release_local_reserve_route_for_memory_info(previous.mem_holder.as_ref()); + } + self.local_snapshot_info.insert( + key.to_string(), + LocalSnapshotInfo { + put_time_ms: put_id.0, + put_version: put_id.1, + }, + ); + drop(controls); + pending_memory_info + }; + Ok(memory_info) + } + pub async fn install_local_committed_memory_info( &self, key: &str, @@ -2355,7 +2927,7 @@ impl ClientKvApiInner { .await, ); { - let controls = self.owner_key_control.lock(); + let controls = self.owner_key_control.lock_key(key); if controls .get(key) .is_some_and(|state| state.reclaim.is_some()) @@ -2394,7 +2966,7 @@ impl ClientKvApiInner { memory_info: Arc, ) -> bool { { - let controls = self.owner_key_control.lock(); + let controls = self.owner_key_control.lock_key(key); if controls .get(key) .is_some_and(|state| state.reclaim.is_some()) @@ -2435,7 +3007,7 @@ impl ClientKvApiInner { key: &str, memory_info: Arc, ) { - let controls = self.owner_key_control.lock(); + let controls = self.owner_key_control.lock_key(key); assert!( !controls .get(key) @@ -2466,7 +3038,7 @@ impl ClientKvApiInner { key: &str, expected_mem_holder: &Arc, ) -> bool { - let _controls = self.owner_key_control.lock(); + let _controls = self.owner_key_control.lock_key(key); self.precommit_local_visible_info .remove_if(key, |_, info| { Arc::ptr_eq(&info.mem_holder, expected_mem_holder) @@ -2474,15 +3046,34 @@ impl ClientKvApiInner { .is_some() } + pub fn precommit_local_visible_memory_info(&self, key: &str) -> Option> { + self.precommit_local_visible_info + .get(key) + .map(|info| info.mem_holder.clone()) + } + + pub(crate) fn committed_local_reserve_slot_is_current( + &self, + key: &str, + put_id: crate::master_kv_router::put::PutIDForAKey, + expected: &crate::master_kv_router::msg_pack::PutDoneCommittedSlot, + ) -> bool { + self.get_cached_info.get(key).is_some_and(|cached| { + (cached.put_time_ms, cached.put_version) == put_id + && cached.mem_holder.local_reserve_resident_slot_ref() + == Some((expected.slot_size, expected.grant_id, expected.slot_index)) + }) + } + pub fn promote_precommit_local_reserve_resident_slot_if_same( &self, key: &str, put_id: crate::master_kv_router::put::PutIDForAKey, memory_info: Arc, - atomic_group: Option<&crate::master_kv_router::msg_pack::PutAtomicGroup>, + _atomic_group: Option<&crate::master_kv_router::msg_pack::PutAtomicGroup>, ) -> KvResult<()> { { - let controls = self.owner_key_control.lock(); + let controls = self.owner_key_control.lock_key(key); if controls .get(key) .is_some_and(|state| state.reclaim.is_some()) @@ -2541,7 +3132,6 @@ impl ClientKvApiInner { }, ); } - self.owner_hot_track_committed(key, put_id, &memory_info, atomic_group); Ok(()) } } @@ -2559,6 +3149,9 @@ pub struct ExternalPendingPutCtx { pub local_reserve_slot: Option, pub local_reserve_slot_size: Option, pub atomic_group: Option, + /// Keep the per-key reclaim fence alive for every cache/user clone of this + /// pending context. The counter is released only by the final Arc drop. + pub(crate) _pending_fence: Arc, } #[derive(Debug, Clone)] @@ -2572,10 +3165,12 @@ pub(crate) struct ReplicaTaskTarget { pub(crate) struct ReplicaTaskJob { pub key: String, pub put_id: crate::master_kv_router::put::PutIDForAKey, - pub holder: Arc, + /// Replica tasks are independent hit-rate work and keep their transfer + /// source alive until the transfer finishes. Capacity eviction never enters + /// this queue. + pub holder: Option>, pub target: Option, pub preferred_sub_cluster: Option, - pub hot_replica_guard: Option, pub protect_source_on_remote_complete: bool, } @@ -2807,76 +3402,577 @@ impl OwnerLocalReserveGrantState { } } } - _ => { - unreachable!("release_committed_slot_route expects a committed slot"); + _ => { + unreachable!("release_committed_slot_route expects a committed slot"); + } + } + } + + pub fn is_fully_free(&self) -> bool { + self.free_slots.len() == self.slot_count as usize + } + + pub fn used_slot_count(&self) -> usize { + self.slot_count as usize - self.free_slots.len() + } +} + +#[derive(Debug, Clone)] +pub(crate) struct OwnerLocalReserveClassState { + pub slot_size: u64, + pub slots_per_grant: u32, + pub grants: Vec, + /// Stable grant identity -> current index in `grants`. Every vector removal uses + /// swap-remove and repairs the one moved entry, so per-slot state transitions never + /// scan all grants. + grant_indices: HashMap, + /// Dense set of grants which currently contain at least one free slot. This avoids + /// scanning full grants while assembling a lease. + claimable_grant_ids: Vec, + claimable_grant_indices: HashMap, + free_slots: usize, + prepared_slots: usize, + pending_visible_slots: usize, + committed_slots: usize, + pub last_grow_at: Option, + pub pending_slot_demand: usize, + pub max_observed_claim_slots: usize, + pub expected_grant_count: usize, +} + +impl OwnerLocalReserveClassState { + pub fn new(slot_size: u64, slots_per_grant: u32) -> Self { + Self { + slot_size, + slots_per_grant, + grants: Vec::new(), + grant_indices: HashMap::new(), + claimable_grant_ids: Vec::new(), + claimable_grant_indices: HashMap::new(), + free_slots: 0, + prepared_slots: 0, + pending_visible_slots: 0, + committed_slots: 0, + last_grow_at: None, + pending_slot_demand: 0, + max_observed_claim_slots: 0, + expected_grant_count: 0, + } + } + + pub fn free_slot_count(&self) -> usize { + self.free_slots + } + + pub fn used_slot_count(&self) -> usize { + self.prepared_slots + .saturating_add(self.pending_visible_slots) + .saturating_add(self.committed_slots) + } + + pub fn grant_count(&self) -> usize { + self.grants.len() + } + + pub fn prepared_slot_count(&self) -> usize { + self.prepared_slots + } + + pub fn pending_visible_slot_count(&self) -> usize { + self.pending_visible_slots + } + + pub fn committed_slot_count(&self) -> usize { + self.committed_slots + } + + fn add_claimable_grant(&mut self, grant_id: u64) { + if self.claimable_grant_indices.contains_key(&grant_id) { + return; + } + let index = self.claimable_grant_ids.len(); + self.claimable_grant_ids.push(grant_id); + let previous = self.claimable_grant_indices.insert(grant_id, index); + assert!( + previous.is_none(), + "duplicate claimable local-reserve grant" + ); + } + + fn remove_claimable_grant(&mut self, grant_id: u64) { + let Some(index) = self.claimable_grant_indices.remove(&grant_id) else { + return; + }; + let removed = self.claimable_grant_ids.swap_remove(index); + assert_eq!(removed, grant_id, "claimable grant index drift"); + if let Some(moved_grant_id) = self.claimable_grant_ids.get(index).copied() { + let moved_index = self + .claimable_grant_indices + .get_mut(&moved_grant_id) + .expect("moved claimable grant must remain indexed"); + *moved_index = index; + } + } + + pub fn install_grant(&mut self, grant: OwnerLocalReserveGrantState) { + assert_eq!(grant.slot_size, self.slot_size, "grant slot-size drift"); + assert_eq!( + grant.slot_count, self.slots_per_grant, + "grant slot-count drift" + ); + assert!( + !self.grant_indices.contains_key(&grant.grant_id), + "duplicate local-reserve grant id" + ); + + let mut free = 0usize; + let mut prepared = 0usize; + let mut pending_visible = 0usize; + let mut committed = 0usize; + for state in &grant.slot_states { + match state { + OwnerLocalReserveSlotState::Free => free += 1, + OwnerLocalReserveSlotState::Prepared => prepared += 1, + OwnerLocalReserveSlotState::PendingLocalVisible { .. } => pending_visible += 1, + OwnerLocalReserveSlotState::Committed { .. } => committed += 1, + } + } + assert_eq!(free, grant.free_slots.len(), "grant free-slot index drift"); + + let grant_id = grant.grant_id; + let index = self.grants.len(); + self.grants.push(grant); + let previous = self.grant_indices.insert(grant_id, index); + assert!(previous.is_none(), "duplicate local-reserve grant id"); + if free != 0 { + self.add_claimable_grant(grant_id); + } + self.free_slots = self + .free_slots + .checked_add(free) + .expect("free slot overflow"); + self.prepared_slots = self + .prepared_slots + .checked_add(prepared) + .expect("prepared slot overflow"); + self.pending_visible_slots = self + .pending_visible_slots + .checked_add(pending_visible) + .expect("pending-visible slot overflow"); + self.committed_slots = self + .committed_slots + .checked_add(committed) + .expect("committed slot overflow"); + } + + pub fn claim_available(&mut self, max_slots: usize) -> Vec { + let claim_count = self.free_slots.min(max_slots); + let mut slots = Vec::with_capacity(claim_count); + while slots.len() < claim_count { + let grant_id = *self + .claimable_grant_ids + .last() + .expect("free-slot counter requires a claimable grant"); + let grant_index = *self + .grant_indices + .get(&grant_id) + .expect("claimable grant must be installed"); + let (slot, exhausted) = { + let grant = &mut self.grants[grant_index]; + let slot = grant + .claim_prepared_slot() + .expect("claimable grant must contain a free slot"); + (slot, grant.free_slots.is_empty()) + }; + self.free_slots = self + .free_slots + .checked_sub(1) + .expect("free slot counter underflow"); + self.prepared_slots = self + .prepared_slots + .checked_add(1) + .expect("prepared slot overflow"); + if exhausted { + self.remove_claimable_grant(grant_id); } + slots.push(slot); } + slots } - pub fn is_fully_free(&self) -> bool { - self.free_slots.len() == self.slot_count as usize + fn grant_index(&self, grant_id: u64) -> Option { + self.grant_indices.get(&grant_id).copied() } - pub fn used_slot_count(&self) -> usize { - self.slot_count as usize - self.free_slots.len() + pub fn grant(&self, grant_id: u64) -> Option<&OwnerLocalReserveGrantState> { + self.grant_index(grant_id) + .and_then(|index| self.grants.get(index)) } -} -#[derive(Debug, Clone)] -pub(crate) struct OwnerLocalReserveClassState { - pub slot_size: u64, - pub slots_per_grant: u32, - pub grants: Vec, - pub last_grow_at: Option, - pub pending_slot_demand: usize, - pub expected_grant_count: usize, -} + pub fn release_prepared_slot(&mut self, grant_id: u64, slot_index: u32) -> bool { + let Some(grant_index) = self.grant_index(grant_id) else { + return false; + }; + let was_exhausted = self.grants[grant_index].free_slots.is_empty(); + self.grants[grant_index].release_prepared_slot(slot_index); + self.prepared_slots = self + .prepared_slots + .checked_sub(1) + .expect("prepared slot counter underflow"); + self.free_slots = self.free_slots.checked_add(1).expect("free slot overflow"); + if was_exhausted { + self.add_claimable_grant(grant_id); + } + true + } -impl OwnerLocalReserveClassState { - pub fn new(slot_size: u64, slots_per_grant: u32) -> Self { - Self { - slot_size, - slots_per_grant, - grants: Vec::new(), - last_grow_at: None, - pending_slot_demand: 0, - expected_grant_count: 0, + pub fn mark_prepared_slot_pending_visible(&mut self, grant_id: u64, slot_index: u32) -> bool { + let Some(grant_index) = self.grant_index(grant_id) else { + return false; + }; + self.grants[grant_index].mark_prepared_slot_pending_visible(slot_index); + self.prepared_slots = self + .prepared_slots + .checked_sub(1) + .expect("prepared slot counter underflow"); + self.pending_visible_slots = self + .pending_visible_slots + .checked_add(1) + .expect("pending-visible slot overflow"); + true + } + + pub fn promote_pending_visible_slot_to_committed( + &mut self, + grant_id: u64, + slot_index: u32, + ) -> bool { + let Some(grant_index) = self.grant_index(grant_id) else { + return false; + }; + self.grants[grant_index].promote_pending_visible_slot_to_committed(slot_index); + self.pending_visible_slots = self + .pending_visible_slots + .checked_sub(1) + .expect("pending-visible slot counter underflow"); + self.committed_slots = self + .committed_slots + .checked_add(1) + .expect("committed slot overflow"); + true + } + + pub fn retain_resident_slot_holder(&mut self, grant_id: u64, slot_index: u32) -> bool { + let Some(grant_index) = self.grant_index(grant_id) else { + return false; + }; + self.grants[grant_index].retain_resident_slot_holder(slot_index); + true + } + + pub fn release_resident_slot_holder(&mut self, grant_id: u64, slot_index: u32) -> bool { + let Some(grant_index) = self.grant_index(grant_id) else { + return false; + }; + let (was_exhausted, prior_state, became_free) = { + let grant = &mut self.grants[grant_index]; + let was_exhausted = grant.free_slots.is_empty(); + let prior_state = grant + .slot_states + .get(slot_index as usize) + .expect("slot state index out of range") + .clone(); + let free_before = grant.free_slots.len(); + grant.release_resident_slot_holder(slot_index); + ( + was_exhausted, + prior_state, + grant.free_slots.len() != free_before, + ) + }; + if became_free { + match prior_state { + OwnerLocalReserveSlotState::PendingLocalVisible { .. } => { + self.pending_visible_slots = self + .pending_visible_slots + .checked_sub(1) + .expect("pending-visible slot counter underflow"); + } + OwnerLocalReserveSlotState::Committed { .. } => { + self.committed_slots = self + .committed_slots + .checked_sub(1) + .expect("committed slot counter underflow"); + } + _ => unreachable!("resident holder must belong to a resident slot"), + } + self.free_slots = self.free_slots.checked_add(1).expect("free slot overflow"); + if was_exhausted { + self.add_claimable_grant(grant_id); + } } + true } - pub fn free_slot_count(&self) -> usize { - self.grants.iter().map(|grant| grant.free_slots.len()).sum() + pub fn release_committed_slot_route(&mut self, grant_id: u64, slot_index: u32) -> bool { + let Some(grant_index) = self.grant_index(grant_id) else { + return false; + }; + let (was_exhausted, became_free) = { + let grant = &mut self.grants[grant_index]; + let was_exhausted = grant.free_slots.is_empty(); + let free_before = grant.free_slots.len(); + grant.release_committed_slot_route(slot_index); + (was_exhausted, grant.free_slots.len() != free_before) + }; + if became_free { + self.committed_slots = self + .committed_slots + .checked_sub(1) + .expect("committed slot counter underflow"); + self.free_slots = self.free_slots.checked_add(1).expect("free slot overflow"); + if was_exhausted { + self.add_claimable_grant(grant_id); + } + } + true } - pub fn used_slot_count(&self) -> usize { - self.grants - .iter() - .map(|grant| grant.used_slot_count()) - .sum() + /// Drop the route reference and the resident `MemoryInfo` reference as one + /// slot-pool transaction. This is the normal owner-reclaim transition and + /// avoids exposing an intermediate state across two pool lock acquisitions. + pub fn release_committed_resident_slot(&mut self, grant_id: u64, slot_index: u32) -> bool { + if self.grant_index(grant_id).is_none() { + return false; + } + assert!(self.release_committed_slot_route(grant_id, slot_index)); + assert!(self.release_resident_slot_holder(grant_id, slot_index)); + true } - pub fn grant_count(&self) -> usize { - self.grants.len() + pub fn detach_fully_free_grant( + &mut self, + grant_id: u64, + ) -> Option { + let grant_index = self.grant_indices.remove(&grant_id)?; + assert!( + self.grants[grant_index].is_fully_free(), + "only a fully-free grant may be detached" + ); + self.remove_claimable_grant(grant_id); + let grant = self.grants.swap_remove(grant_index); + assert_eq!(grant.grant_id, grant_id, "grant index drift"); + if let Some(moved_grant) = self.grants.get(grant_index) { + let moved_index = self + .grant_indices + .get_mut(&moved_grant.grant_id) + .expect("moved grant must remain indexed"); + *moved_index = grant_index; + } + self.free_slots = self + .free_slots + .checked_sub(grant.slot_count as usize) + .expect("free slot counter underflow"); + Some(grant) + } + + pub fn take_all_grants(&mut self) -> Vec { + self.grant_indices.clear(); + self.claimable_grant_ids.clear(); + self.claimable_grant_indices.clear(); + self.free_slots = 0; + self.prepared_slots = 0; + self.pending_visible_slots = 0; + self.committed_slots = 0; + std::mem::take(&mut self.grants) } } #[cfg(test)] mod owner_reclaim_slot_tests { use super::{ - GetCachedInfo, OwnerHotCacheCounters, OwnerHotCacheEntry, OwnerHotReplicaGuard, - OwnerHotReplicaIdentity, OwnerKeyControlState, OwnerLocalReserveGrantState, - OwnerReclaimRecord, allocate_external_holding_id, build_owner_hot_cache, - clone_if_owner_hot_entry_matches, forget_owner_hot_atomic_group, - owner_hot_tp_cohort_key_rows, register_owner_hot_atomic_group, resolve_local_visible_batch, + ExternalPendingPutCtx, ExternalPendingPutFenceGuard, OwnerHotCacheCounters, + OwnerHotCacheEntry, OwnerHotEvictionEvent, OwnerHotReplicaIdentity, OwnerHotRetryQueue, + OwnerHotSelectionDebt, OwnerKeyControlState, OwnerKeyControlTable, + OwnerLocalReserveGrantState, OwnerLocalReserveSlotLease, OwnerLocalReserveSlotRef, + OwnerLocalReserveSlotState, OwnerReclaimRecord, acquire_external_pending_put_fence_for_key, + allocate_external_holding_id, build_owner_hot_cache, clone_if_owner_hot_entry_matches, + forget_owner_hot_atomic_group, owner_hot_tp_cohort_key_rows, + pin_current_owner_hot_source_from_index, register_owner_hot_atomic_group, }; use crate::master_kv_router::msg_pack::{ OwnerReclaimItem, PutAtomicGroup, PutAtomicGroupMember, }; - use dashmap::{DashMap, DashSet}; + use dashmap::DashMap; use parking_lot::Mutex; - use std::collections::HashMap; use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::{Arc, Weak}; + use std::time::{Duration, Instant}; + + fn pending_put_count(controls: &Arc, key: &str) -> Option { + controls + .lock_key(key) + .get(key) + .map(|state| state.external_pending_puts) + } + + fn controls_with_state(key: &str, state: OwnerKeyControlState) -> Arc { + let controls = Arc::new(OwnerKeyControlTable::default()); + controls.lock_key(key).insert(key.to_string(), state); + controls + } + + #[test] + fn external_pending_put_guard_clone_releases_only_after_last_drop() { + let controls = Arc::new(OwnerKeyControlTable::default()); + let guard = acquire_external_pending_put_fence_for_key(&controls, "clone-key") + .expect("pending fence acquisition must succeed"); + let clone = guard.clone(); + assert_eq!(pending_put_count(&controls, "clone-key"), Some(1)); + + drop(guard); + assert_eq!(pending_put_count(&controls, "clone-key"), Some(1)); + drop(clone); + assert_eq!(pending_put_count(&controls, "clone-key"), None); + } + + #[test] + fn stale_pending_put_guard_drop_cannot_erase_new_generation() { + let controls = Arc::new(OwnerKeyControlTable::default()); + let old = acquire_external_pending_put_fence_for_key(&controls, "aba-key") + .expect("old pending fence acquisition must succeed"); + let new = acquire_external_pending_put_fence_for_key(&controls, "aba-key") + .expect("new pending fence acquisition must succeed"); + assert_eq!(pending_put_count(&controls, "aba-key"), Some(2)); + + drop(old); + assert_eq!(pending_put_count(&controls, "aba-key"), Some(1)); + drop(new); + assert_eq!(pending_put_count(&controls, "aba-key"), None); + } + + #[test] + fn local_first_pending_guard_releases_both_key_counters() { + let controls = controls_with_state( + "local-key", + OwnerKeyControlState { + local_puts: 1, + external_pending_puts: 1, + reclaim: None, + external_get: None, + }, + ); + let guard = Arc::new(ExternalPendingPutFenceGuard { + key: "local-key".to_string(), + owner_key_control: controls.clone(), + owns_local_put: true, + local_slot_cleanup_view: None, + local_slot_lease: Mutex::new(None), + local_slot_release_failed: std::sync::atomic::AtomicBool::new(false), + }); + + drop(guard); + assert!(controls.lock_key("local-key").get("local-key").is_none()); + } + + #[test] + fn failed_local_slot_release_keeps_key_fence_closed() { + let controls = controls_with_state( + "failed-slot", + OwnerKeyControlState { + local_puts: 1, + external_pending_puts: 1, + reclaim: None, + external_get: None, + }, + ); + let guard = Arc::new(ExternalPendingPutFenceGuard { + key: "failed-slot".to_string(), + owner_key_control: controls.clone(), + owns_local_put: true, + local_slot_cleanup_view: None, + local_slot_lease: Mutex::new(None), + local_slot_release_failed: std::sync::atomic::AtomicBool::new(true), + }); + + drop(guard); + let controls = controls.lock_key("failed-slot"); + assert_eq!(controls["failed-slot"].local_puts, 1); + assert_eq!(controls["failed-slot"].external_pending_puts, 1); + } + + #[test] + fn committed_local_first_slot_disarms_drop_cleanup_before_fence_release() { + let controls = controls_with_state( + "committed-slot", + OwnerKeyControlState { + local_puts: 1, + external_pending_puts: 1, + reclaim: None, + external_get: None, + }, + ); + let guard = Arc::new(ExternalPendingPutFenceGuard { + key: "committed-slot".to_string(), + owner_key_control: controls.clone(), + owns_local_put: true, + local_slot_cleanup_view: None, + local_slot_lease: Mutex::new(None), + local_slot_release_failed: std::sync::atomic::AtomicBool::new(false), + }); + guard.attach_local_slot_lease(OwnerLocalReserveSlotLease { + value_len: 8, + slot_size: 8, + slots: vec![OwnerLocalReserveSlotRef { + grant_id: 7, + slot_index: 2, + ptr: 0x1008, + base_addr: 0x1000, + }], + }); + + guard.disarm_local_slot_lease(); + drop(guard); + assert!( + controls + .lock_key("committed-slot") + .get("committed-slot") + .is_none() + ); + } + + #[test] + fn pending_ctx_clone_keeps_fence_after_explicit_cache_invalidation() { + let controls = Arc::new(OwnerKeyControlTable::default()); + let fence = acquire_external_pending_put_fence_for_key(&controls, "cached-key") + .expect("pending fence acquisition must succeed"); + let cache = moka::sync::Cache::new(1); + let identity = ("cached-key".to_string(), 10, 2); + cache.insert( + identity.clone(), + ExternalPendingPutCtx { + peer_id: None, + src_offset: 0, + target_base_addr: 0, + target_offset: 0, + len: 1, + make_replica_task: false, + preferred_sub_cluster: None, + replica_target: None, + local_reserve_slot: None, + local_reserve_slot_size: None, + atomic_group: None, + _pending_fence: fence, + }, + ); + let clone = cache.get(&identity).expect("pending ctx must exist"); + cache.invalidate(&identity); + cache.run_pending_tasks(); + assert_eq!(pending_put_count(&controls, "cached-key"), Some(1)); + + drop(clone); + assert_eq!(pending_put_count(&controls, "cached-key"), None); + } #[test] fn external_holding_ids_are_nonzero_and_unique_for_resident_pages() { @@ -2910,30 +4006,162 @@ mod owner_reclaim_slot_tests { } #[test] - fn hot_replica_guard_keeps_dedup_until_terminal_outcome() { - let identity = OwnerHotReplicaIdentity { - key: "hot-key".to_string(), - put_time_ms: 10, - put_version: 2, + fn dispatcher_pin_and_reclaim_prepare_are_serialized_by_the_current_index() { + let current = Mutex::new(Some(((10, 2), Arc::new(7u64)))); + let weak = Arc::downgrade(¤t.lock().as_ref().unwrap().1); + + let pinned = match pin_current_owner_hot_source_from_index((10, 2), &weak, || { + current + .lock() + .as_ref() + .map(|(put_id, value)| (*put_id, value.clone())) + }) { + super::OwnerHotPinResult::Pinned(pinned) => pinned, + _ => panic!("current source must pin under the owner fence"), }; - let inflight = Arc::new(DashSet::new()); - assert!(inflight.insert(identity.clone())); + let prepared_after_pin = current.lock().take().unwrap().1; + assert_eq!(Arc::strong_count(&prepared_after_pin), 2); + drop(pinned); + assert_eq!(Arc::strong_count(&prepared_after_pin), 1); + + // If Prepare wins and moves the sole Arc out of the local index, the + // dispatcher observes an absent current entry. It must not upgrade the + // Weak that now points into Prepared, or Commit's try_unwrap could race + // an unexpected second holder. + let current = Mutex::new(Some(((11, 3), Arc::new(9u64)))); + let weak = Arc::downgrade(¤t.lock().as_ref().unwrap().1); + let prepared_before_pin = current.lock().take().unwrap().1; + assert!(matches!( + pin_current_owner_hot_source_from_index((11, 3), &weak, || { + current + .lock() + .as_ref() + .map(|(put_id, value)| (*put_id, value.clone())) + }), + super::OwnerHotPinResult::ReclaimBusy + )); + assert_eq!(Arc::strong_count(&prepared_before_pin), 1); + + drop(prepared_before_pin); + assert!(matches!( + pin_current_owner_hot_source_from_index((11, 3), &weak, || None), + super::OwnerHotPinResult::Stale + )); + } + + #[test] + fn owner_hot_retry_queue_is_exactly_once_and_keeps_selection_debt() { let counters = Arc::new(OwnerHotCacheCounters::default()); - let group_replica_triggered = Arc::new(DashSet::new()); - let guard = OwnerHotReplicaGuard::new( - identity.clone(), - inflight.clone(), - counters.clone(), - None, - group_replica_triggered, + let retry_queue = OwnerHotRetryQueue::new(counters.clone()); + let identity = OwnerHotReplicaIdentity { + key: "retry-key".to_string(), + put_time_ms: 12, + put_version: 3, + }; + let debt = OwnerHotSelectionDebt::new(64, counters.selection_debt_bytes.clone()); + let event = OwnerHotEvictionEvent { + key: identity.key.clone(), + put_id: (identity.put_time_ms, identity.put_version), + memory_info: Weak::new(), + selection_debt: debt, + retry: true, + source_eviction_cohort: None, + retry_failures: 0, + }; + retry_queue.schedule(event.clone(), "first failure"); + retry_queue.schedule(event, "duplicate failure"); + assert_eq!(retry_queue.len(), 1); + assert_eq!(counters.selection_debt_bytes.load(Ordering::Acquire), 64); + + let due = retry_queue.take_due_batch(Instant::now() + Duration::from_secs(10), 128); + assert_eq!(due.len(), 1); + assert_eq!(retry_queue.len(), 1); + assert_eq!(counters.selection_debt_bytes.load(Ordering::Acquire), 64); + assert!( + retry_queue + .take_due_batch(Instant::now() + Duration::from_secs(30), 128) + .is_empty(), + "a dispatched retry stays exactly once until dispatcher acknowledgement" ); - assert!(inflight.contains(&identity)); + let accepted = retry_queue + .take_for_inflight(&identity) + .expect("dispatcher acknowledgement must take the authoritative event"); + accepted.selection_debt.release(); + assert_eq!(retry_queue.len(), 0); + assert_eq!(counters.selection_debt_bytes.load(Ordering::Acquire), 0); + } - guard.mark_completed(); - drop(guard); - assert!(!inflight.contains(&identity)); - assert_eq!(counters.replica_completed.load(Ordering::Relaxed), 1); - assert_eq!(counters.replica_failed.load(Ordering::Relaxed), 0); + #[test] + fn owner_hot_retry_queue_deadlines_stay_bounded_under_high_churn() { + const CHURN: usize = 20_000; + + let counters = Arc::new(OwnerHotCacheCounters::default()); + let retry_queue = OwnerHotRetryQueue::new(counters.clone()); + let identity = OwnerHotReplicaIdentity { + key: "retry-churn".to_string(), + put_time_ms: 21, + put_version: 5, + }; + let debt = OwnerHotSelectionDebt::new(64, counters.selection_debt_bytes.clone()); + let event = OwnerHotEvictionEvent { + key: identity.key.clone(), + put_id: (identity.put_time_ms, identity.put_version), + memory_info: Weak::new(), + selection_debt: debt, + retry: true, + source_eviction_cohort: None, + retry_failures: 0, + }; + + for _ in 0..CHURN { + retry_queue.schedule(event.clone(), "repeated failure"); + } + assert_eq!(retry_queue.len(), 1); + assert_eq!(retry_queue.state.lock().deadlines.len(), 1); + + let due = retry_queue.take_due_batch(Instant::now() + Duration::from_secs(10), 1); + assert_eq!(due.len(), 1); + assert_eq!(retry_queue.len(), 1); + assert_eq!(retry_queue.state.lock().deadlines.len(), 0); + + for _ in 0..CHURN { + retry_queue.schedule(due[0].clone(), "repeated dispatcher failure"); + } + assert_eq!(retry_queue.len(), 1); + assert_eq!(retry_queue.state.lock().deadlines.len(), 1); + + let event = retry_queue + .take_for_inflight(&identity) + .expect("live retry must remain available to the dispatcher"); + assert_eq!(retry_queue.len(), 0); + assert_eq!(retry_queue.state.lock().deadlines.len(), 0); + event.selection_debt.release(); + assert_eq!(counters.selection_debt_bytes.load(Ordering::Acquire), 0); + + let remove_identity = OwnerHotReplicaIdentity { + key: "retry-remove-churn".to_string(), + put_time_ms: 22, + put_version: 6, + }; + let remove_debt = OwnerHotSelectionDebt::new(32, counters.selection_debt_bytes.clone()); + let remove_event = OwnerHotEvictionEvent { + key: remove_identity.key.clone(), + put_id: (remove_identity.put_time_ms, remove_identity.put_version), + memory_info: Weak::new(), + selection_debt: remove_debt, + retry: true, + source_eviction_cohort: None, + retry_failures: 0, + }; + for _ in 0..CHURN { + retry_queue.schedule(remove_event.clone(), "remove churn"); + } + assert_eq!(retry_queue.len(), 1); + assert_eq!(retry_queue.state.lock().deadlines.len(), 1); + retry_queue.remove(&remove_identity); + assert_eq!(retry_queue.len(), 0); + assert_eq!(retry_queue.state.lock().deadlines.len(), 0); + assert_eq!(counters.selection_debt_bytes.load(Ordering::Acquire), 0); } #[test] @@ -2961,11 +4189,8 @@ mod owner_reclaim_slot_tests { let second_group = atomic_groups.get(&second).unwrap().value().clone(); assert!(Arc::ptr_eq(&first_group, &second_group)); - let triggered = DashSet::new(); - assert!(triggered.insert(first.clone())); - forget_owner_hot_atomic_group(&atomic_groups, &triggered, &second); + forget_owner_hot_atomic_group(&atomic_groups, &second); assert!(atomic_groups.is_empty()); - assert!(!triggered.contains(&first)); } #[test] @@ -3010,71 +4235,12 @@ mod owner_reclaim_slot_tests { ); } - #[test] - fn hot_group_trigger_is_persistent_on_success_and_retryable_on_failure() { - let member = OwnerHotReplicaIdentity { - key: "member".to_string(), - put_time_ms: 10, - put_version: 2, - }; - let group_trigger = OwnerHotReplicaIdentity { - key: "anchor".to_string(), - put_time_ms: 10, - put_version: 1, - }; - let inflight = Arc::new(DashSet::new()); - let triggered = Arc::new(DashSet::new()); - let counters = Arc::new(OwnerHotCacheCounters::default()); - - assert!(inflight.insert(member.clone())); - assert!(triggered.insert(group_trigger.clone())); - let failed_guard = OwnerHotReplicaGuard::new( - member.clone(), - inflight.clone(), - counters.clone(), - Some(group_trigger.clone()), - triggered.clone(), - ); - drop(failed_guard); - assert!(!inflight.contains(&member)); - assert!(!triggered.contains(&group_trigger)); - assert_eq!(counters.replica_failed.load(Ordering::Relaxed), 1); - - assert!(inflight.insert(member.clone())); - assert!(triggered.insert(group_trigger.clone())); - let completed_guard = OwnerHotReplicaGuard::new( - member.clone(), - inflight.clone(), - counters.clone(), - Some(group_trigger.clone()), - triggered.clone(), - ); - completed_guard.mark_completed(); - drop(completed_guard); - assert!(!inflight.contains(&member)); - assert!(triggered.contains(&group_trigger)); - assert_eq!(counters.replica_completed.load(Ordering::Relaxed), 1); - } - #[test] fn hot_cache_only_dispatches_size_removals_and_keeps_capacity() { - let controls = Arc::new(Mutex::new(HashMap::new())); - let cached = Arc::new(DashMap::::new()); - let inflight = Arc::new(DashSet::new()); - let atomic_groups = Arc::new(DashMap::new()); - let group_replica_triggered = Arc::new(DashSet::new()); let counters = Arc::new(OwnerHotCacheCounters::default()); - let (tx, mut rx) = limit_thirdparty::tokio::sync::ampsc::channel(8); - let cache = build_owner_hot_cache( - 10, - controls, - cached, - inflight, - atomic_groups, - group_replica_triggered, - counters.clone(), - tx, - ); + let retry_queue = Arc::new(OwnerHotRetryQueue::new(counters.clone())); + let (tx, mut rx) = limit_thirdparty::tokio::sync::ampsc::unbounded_channel(); + let cache = build_owner_hot_cache(10, counters.clone(), retry_queue, tx); let entry = |put_version| OwnerHotCacheEntry { put_id: (10, put_version), memory_info: Weak::new(), @@ -3092,36 +4258,45 @@ mod owner_reclaim_slot_tests { cache.run_pending_tasks(); assert!(counters.size_evictions.load(Ordering::Relaxed) >= 1); assert_eq!(cache.policy().max_capacity(), Some(10)); - assert!( - rx.try_recv().is_err(), - "stale weak entries must not dispatch" - ); + let event = rx + .try_recv() + .expect("the Moka listener must emit lightweight metadata without pinning"); + assert!(event.memory_info.upgrade().is_none()); } #[test] - fn batch_local_visibility_skips_reclaim_fenced_keys() { + fn pointwise_batch_visibility_skips_reclaim_fenced_keys() { let keys = vec![ "local-a".to_string(), "fenced".to_string(), "local-b".to_string(), ]; - let mut controls = HashMap::new(); - controls.insert( + let controls = OwnerKeyControlTable::default(); + controls.lock_key("fenced").insert( "fenced".to_string(), OwnerKeyControlState { local_puts: 0, + external_pending_puts: 0, reclaim: Some(OwnerReclaimRecord::Committed(OwnerReclaimItem { key: "fenced".to_string(), ..OwnerReclaimItem::default() })), + external_get: None, }, ); let mut resolved_keys = Vec::new(); - - let visible = resolve_local_visible_batch(&keys, &controls, |key| { - resolved_keys.push(key.to_string()); - Some(key.to_string()) - }); + let visible = keys + .iter() + .map(|key| { + let shard = controls.lock_key(key); + if shard.get(key).is_some_and(|state| state.reclaim.is_some()) { + None + } else { + resolved_keys.push(key.to_string()); + Some(key.to_string()) + } + }) + .collect::>(); assert_eq!( visible, @@ -3134,6 +4309,29 @@ mod owner_reclaim_slot_tests { assert_eq!(resolved_keys, vec!["local-a", "local-b"]); } + #[test] + fn sharded_owner_control_does_not_globally_block_unrelated_keys() { + let controls = OwnerKeyControlTable::default(); + let first = "shard-key-a"; + let first_shard = OwnerKeyControlTable::shard_index(first); + let second = (0..10_000) + .map(|idx| format!("shard-key-b-{idx}")) + .find(|key| OwnerKeyControlTable::shard_index(key) != first_shard) + .expect("a key on another owner-control shard must exist"); + + let _first_guard = controls.lock_key(first); + assert!( + controls.shards[OwnerKeyControlTable::shard_index(&second)] + .try_lock() + .is_some(), + "one key fence must not block an unrelated shard" + ); + assert!( + controls.shards[first_shard].try_lock().is_none(), + "the same shard must remain serialized while its guard is held" + ); + } + #[test] fn committed_slot_becomes_free_only_after_route_and_holder_are_released() { let mut grant = OwnerLocalReserveGrantState::new(7, 0, 0, 16, 8, 2); @@ -3149,6 +4347,43 @@ mod owner_reclaim_slot_tests { assert_eq!(grant.free_slots.len(), 2); assert!(grant.is_fully_free()); } + + #[test] + fn owner_reclaim_releases_committed_route_and_resident_holder_as_one_pool_update() { + let mut class = super::OwnerLocalReserveClassState::new(8, 2); + class.install_grant(OwnerLocalReserveGrantState::new(7, 0, 0, 16, 8, 2)); + let slot = class.claim_available(1).pop().expect("slot should be free"); + assert!(class.mark_prepared_slot_pending_visible(slot.grant_id, slot.slot_index)); + assert!(class.retain_resident_slot_holder(slot.grant_id, slot.slot_index)); + assert!(class.promote_pending_visible_slot_to_committed(slot.grant_id, slot.slot_index)); + assert_eq!(class.committed_slot_count(), 1); + assert_eq!(class.free_slot_count(), 1); + + assert!(class.release_committed_resident_slot(slot.grant_id, slot.slot_index)); + assert_eq!(class.committed_slot_count(), 0); + assert_eq!(class.free_slot_count(), 2); + } + + #[test] + fn failed_pending_get_releases_only_its_slot() { + let mut grant = OwnerLocalReserveGrantState::new(7, 0, 0, 24, 8, 3); + let failed = grant.claim_prepared_slot().expect("first slot"); + let unrelated = grant.claim_prepared_slot().expect("second slot"); + grant.mark_prepared_slot_pending_visible(failed.slot_index); + grant.retain_resident_slot_holder(failed.slot_index); + + grant.release_resident_slot_holder(failed.slot_index); + + assert!(matches!( + grant.slot_states[failed.slot_index as usize], + OwnerLocalReserveSlotState::Free + )); + assert!(matches!( + grant.slot_states[unrelated.slot_index as usize], + OwnerLocalReserveSlotState::Prepared + )); + assert_eq!(grant.free_slots.len(), 2); + } } #[derive(Debug, Default)] @@ -3339,6 +4574,16 @@ fn format_metrics_snapshot_prometheus( } impl ClientKvApiInner { + pub(crate) fn owner_local_reserve_claim_lock( + &self, + slot_size: u64, + ) -> Arc> { + self.owner_local_reserve_claim_locks + .entry(slot_size) + .or_insert_with(|| Arc::new(limit_thirdparty::tokio::sync::AMutex::new(()))) + .clone() + } + pub fn get_holding_len(&self) -> usize { self.external_get_holding.total() } @@ -3360,10 +4605,83 @@ impl ClientKvApiInner { ) }) .unwrap_or_default(); + let ( + external_get_flights, + external_get_flights_starting, + external_get_flights_finishing, + external_get_flights_revoking, + external_get_undecided_interests, + external_get_retained_interests, + ) = { + let mut flights = 0u64; + let mut starting = 0u64; + let mut finishing = 0u64; + let mut revoking = 0u64; + let mut undecided = 0u64; + let mut retained = 0u64; + // Metrics use a weak side index and never scan correctness fences. + for op in self.external_get_flight_snapshot() { + flights = flights.saturating_add(1); + let state = op.state.lock(); + undecided = undecided.saturating_add(state.undecided as u64); + retained = retained.saturating_add(state.retained as u64); + match &state.phase { + ExternalGetKeySharedPhase::Starting + | ExternalGetKeySharedPhase::Started { .. } => { + starting = starting.saturating_add(1) + } + ExternalGetKeySharedPhase::Finishing { .. } => { + finishing = finishing.saturating_add(1) + } + ExternalGetKeySharedPhase::Revoking { .. } => { + revoking = revoking.saturating_add(1) + } + ExternalGetKeySharedPhase::Ready { .. } + | ExternalGetKeySharedPhase::Failed { .. } => {} + } + } + (flights, starting, finishing, revoking, undecided, retained) + }; + let ( + local_reserve_slots_free, + local_reserve_slots_prepared, + local_reserve_slots_pending_visible, + local_reserve_slots_committed, + ) = { + let pool = self.owner_local_reserve_pool.lock(); + let mut free = 0u64; + let mut prepared = 0u64; + let mut pending_visible = 0u64; + let mut committed = 0u64; + for class in pool.classes.values() { + free = + free.saturating_add(u64::try_from(class.free_slot_count()).unwrap_or(u64::MAX)); + prepared = prepared + .saturating_add(u64::try_from(class.prepared_slot_count()).unwrap_or(u64::MAX)); + pending_visible = pending_visible.saturating_add( + u64::try_from(class.pending_visible_slot_count()).unwrap_or(u64::MAX), + ); + committed = committed.saturating_add( + u64::try_from(class.committed_slot_count()).unwrap_or(u64::MAX), + ); + } + (free, prepared, pending_visible, committed) + }; OwnerRuntimeObserveSnapshot { external_get_holding_entries: self.external_get_holding.total() as u64, external_get_holding_bytes, + external_get_start_handles: self.external_get_start_registry.len() as u64, + external_get_flights, + external_get_flights_starting, + external_get_flights_finishing, + external_get_flights_revoking, + external_get_undecided_interests, + external_get_retained_interests, external_pending_put_entries: self.external_pending_puts.entry_count(), + local_reserve_slots_free, + local_reserve_slots_prepared, + local_reserve_slots_pending_visible, + local_reserve_slots_committed, hot_cache_capacity_bytes, hot_cache_entries, hot_cache_weighted_bytes, @@ -3371,31 +4689,40 @@ impl ClientKvApiInner { .owner_hot_counters .size_evictions .load(Ordering::Relaxed), - hot_replica_enqueued: self + hot_source_evict_handoff_members: self + .owner_hot_counters + .source_evict_handoff_members + .load(Ordering::Relaxed), + hot_source_evict_committed_members: self .owner_hot_counters - .replica_enqueued + .source_evict_committed_members .load(Ordering::Relaxed), - hot_replica_completed: self + hot_source_evict_restored_members: self .owner_hot_counters - .replica_completed + .source_evict_restored_members .load(Ordering::Relaxed), - hot_replica_already_satisfied: self + hot_source_evict_obsolete: self .owner_hot_counters - .replica_already_satisfied + .source_evict_obsolete .load(Ordering::Relaxed), - hot_replica_failed: self + hot_source_evict_dispatch_failed: self .owner_hot_counters - .replica_failed + .source_evict_dispatch_failed .load(Ordering::Relaxed), - hot_replica_obsolete: self + hot_source_eviction_selected: self.owner_source_eviction_selected.len() as u64, + hot_source_evict_retry_entries: self.owner_hot_retry_queue.len() as u64, + hot_source_evict_retry_scheduled: self .owner_hot_counters - .replica_obsolete + .source_evict_retry_scheduled .load(Ordering::Relaxed), - hot_replica_dispatch_failed: self + hot_source_evict_retry_emitted: self .owner_hot_counters - .replica_dispatch_failed + .source_evict_retry_emitted + .load(Ordering::Relaxed), + hot_selection_debt_bytes: self + .owner_hot_counters + .selection_debt_bytes .load(Ordering::Relaxed), - hot_replica_inflight: self.owner_hot_replica_inflight.len() as u64, hot_eviction_skipped_stale: self .owner_hot_counters .skipped_stale @@ -3404,20 +4731,7 @@ impl ClientKvApiInner { .owner_hot_counters .skipped_reclaim .load(Ordering::Relaxed), - hot_eviction_skipped_duplicate: self - .owner_hot_counters - .skipped_duplicate - .load(Ordering::Relaxed), hot_group_registry_entries: self.owner_hot_atomic_groups.len() as u64, - hot_group_replica_triggered: self.owner_hot_group_replica_triggered.len() as u64, - hot_group_replica_triggers: self - .owner_hot_counters - .group_replica_triggers - .load(Ordering::Relaxed), - hot_group_members_enqueued: self - .owner_hot_counters - .group_members_enqueued - .load(Ordering::Relaxed), hot_group_trigger_duplicates: self .owner_hot_counters .group_trigger_duplicates @@ -3905,6 +5219,8 @@ impl ClientKvApiInner { .or_insert_with(|| OwnerLocalReserveClassState::new(slot_size, slots_per_grant)); class_state.pending_slot_demand = class_state.pending_slot_demand.saturating_add(demand_slots); + class_state.max_observed_claim_slots = + class_state.max_observed_claim_slots.max(demand_slots); } pub(crate) fn owner_local_reserve_consume_pending_demand( @@ -3950,33 +5266,46 @@ impl ClientKvApi { metrics.set_kv_external_pending_put_entries( snapshot.external_pending_put_entries, ); + tracing::info!( + active_handles = snapshot.external_get_start_handles, + active_flights = snapshot.external_get_flights, + starting_flights = snapshot.external_get_flights_starting, + finishing_flights = snapshot.external_get_flights_finishing, + revoking_flights = snapshot.external_get_flights_revoking, + undecided_interests = snapshot.external_get_undecided_interests, + retained_interests = snapshot.external_get_retained_interests, + reserve_free = snapshot.local_reserve_slots_free, + reserve_prepared = snapshot.local_reserve_slots_prepared, + reserve_pending_visible = snapshot.local_reserve_slots_pending_visible, + reserve_committed = snapshot.local_reserve_slots_committed, + "owner Get lifecycle snapshot" + ); if snapshot.hot_cache_capacity_bytes > 0 { tracing::info!( capacity_bytes = snapshot.hot_cache_capacity_bytes, entries = snapshot.hot_cache_entries, weighted_bytes = snapshot.hot_cache_weighted_bytes, size_evictions = snapshot.hot_size_evictions, - replica_enqueued = snapshot.hot_replica_enqueued, - replica_completed = snapshot.hot_replica_completed, - replica_already_satisfied = snapshot.hot_replica_already_satisfied, - replica_failed = snapshot.hot_replica_failed, - replica_obsolete = snapshot.hot_replica_obsolete, - replica_dispatch_failed = snapshot.hot_replica_dispatch_failed, - replica_inflight = snapshot.hot_replica_inflight, + source_evict_handoff_members = snapshot.hot_source_evict_handoff_members, + source_evict_committed_members = snapshot.hot_source_evict_committed_members, + source_evict_restored_members = snapshot.hot_source_evict_restored_members, + source_evict_obsolete = snapshot.hot_source_evict_obsolete, + source_evict_dispatch_failed = snapshot.hot_source_evict_dispatch_failed, + source_eviction_selected = snapshot.hot_source_eviction_selected, + source_evict_retry_entries = snapshot.hot_source_evict_retry_entries, + source_evict_retry_scheduled = snapshot.hot_source_evict_retry_scheduled, + source_evict_retry_emitted = snapshot.hot_source_evict_retry_emitted, + selection_debt_bytes = snapshot.hot_selection_debt_bytes, skipped_stale = snapshot.hot_eviction_skipped_stale, skipped_reclaim = snapshot.hot_eviction_skipped_reclaim, - skipped_duplicate = snapshot.hot_eviction_skipped_duplicate, group_registry_entries = snapshot.hot_group_registry_entries, - group_replica_triggered = snapshot.hot_group_replica_triggered, - group_replica_triggers = snapshot.hot_group_replica_triggers, - group_members_enqueued = snapshot.hot_group_members_enqueued, group_trigger_duplicates = snapshot.hot_group_trigger_duplicates, group_trigger_incomplete = snapshot.hot_group_trigger_incomplete, grouped_put_done_batches = snapshot.grouped_put_done_batches, grouped_put_done_items = snapshot.grouped_put_done_items, legacy_put_done_batches = snapshot.legacy_put_done_batches, legacy_put_done_items = snapshot.legacy_put_done_items, - "owner hot replica policy snapshot" + "owner hot source-eviction policy snapshot" ); } } @@ -3999,24 +5328,25 @@ impl ClientKvApi { tokio::sync::ampsc::channel(REPLICA_TASK_QUEUE_CAPACITY); let (owner_local_publish_tx, owner_local_publish_rx) = tokio::sync::ampsc::channel(OWNER_LOCAL_PUBLISH_QUEUE_CAPACITY); + // The Moka eviction listener is synchronous and must never block while + // holding Moka's housekeeper lock. Events contain only weak payload + // references and are deduplicated by exact selected identities, so use + // a lossless metadata channel instead of dropping cohorts when the old + // bounded queue briefly filled under cache pressure. let (owner_hot_eviction_tx, owner_hot_eviction_rx) = - tokio::sync::ampsc::channel(OWNER_HOT_EVICTION_QUEUE_CAPACITY); + tokio::sync::ampsc::unbounded_channel(); let get_cached_info = Arc::new(DashMap::new()); - let owner_key_control = Arc::new(Mutex::new(HashMap::new())); - let owner_hot_replica_inflight = Arc::new(DashSet::new()); + let owner_key_control = Arc::new(OwnerKeyControlTable::default()); + let owner_source_eviction_selected = Arc::new(DashMap::new()); let owner_hot_atomic_groups = Arc::new(DashMap::new()); - let owner_hot_group_replica_triggered = Arc::new(DashSet::new()); let owner_hot_counters = Arc::new(OwnerHotCacheCounters::default()); + let owner_hot_retry_queue = Arc::new(OwnerHotRetryQueue::new(owner_hot_counters.clone())); let owner_hot_cache = owner_hot_cache_capacity_bytes.map(|capacity_bytes| { build_owner_hot_cache( capacity_bytes, - owner_key_control.clone(), - get_cached_info.clone(), - owner_hot_replica_inflight.clone(), - owner_hot_atomic_groups.clone(), - owner_hot_group_replica_triggered.clone(), owner_hot_counters.clone(), - owner_hot_eviction_tx, + owner_hot_retry_queue.clone(), + owner_hot_eviction_tx.clone(), ) }); @@ -4028,19 +5358,22 @@ impl ClientKvApi { get_remote_kv_lock: AMapLock::new(Duration::from_secs(60)), get_cached_info, precommit_local_visible_info: DashMap::new(), + pending_local_get_info: DashMap::new(), local_snapshot_info: DashMap::new(), owner_local_reserve_pool: Mutex::new(OwnerLocalReservePoolState::default()), - owner_local_reserve_claim_lock: limit_thirdparty::tokio::sync::AMutex::new(()), + owner_local_reserve_claim_locks: DashMap::new(), owner_local_reserve_rebalance_notify: Arc::new( limit_thirdparty::tokio::sync::Notify::new(), ), external_local_first_put_id_counter: AtomicU32::new(0), + next_owner_source_eviction_operation_id: AtomicU64::new(1), owner_key_control, owner_hot_cache, - owner_hot_replica_inflight, + owner_source_eviction_selected, owner_hot_atomic_groups, - owner_hot_group_replica_triggered, owner_hot_counters, + owner_hot_retry_queue, + owner_hot_eviction_tx, owner_hot_eviction_rx: Mutex::new(Some(owner_hot_eviction_rx)), external_invalidate_delete: EnsureMemholderMgmtDeleteHandle::new( OwnerExternalMemMgr::DELETE_SUBMIT_QUEUE_CAPACITY, @@ -4051,7 +5384,7 @@ impl ClientKvApi { owner_delete_ack_mgr: OwnerDeleteAckMemMgr::default(), external_get_holding: OwnerExternalMemMgr::default(), external_get_start_registry: DashMap::new(), - external_get_start_by_key: DashMap::new(), + external_get_flight_registry: DashMap::new(), next_external_get_start_handle: AtomicU64::new(1), next_external_holding_id: AtomicU64::new(1), external_pending_puts: moka::sync::Cache::builder() @@ -4076,8 +5409,11 @@ impl ClientKvApi { rpc_caller_batch_prepare_put_keys: RPCCaller::new(), rpc_caller_batch_release_put_key_reservations: RPCCaller::new(), rpc_caller_put_append_start: RPCCaller::new(), + rpc_caller_batch_put_append_start: RPCCaller::new(), rpc_caller_put_append_revoke: RPCCaller::new(), rpc_caller_put_append_done: RPCCaller::new(), + rpc_caller_batch_put_append_done: RPCCaller::new(), + rpc_caller_batch_evict_owner_source: RPCCaller::new(), rpc_caller_reserve_local_grant: RPCCaller::new(), rpc_caller_release_local_grant: RPCCaller::new(), rpc_caller_delete: RPCCaller::new(), @@ -4142,12 +5478,21 @@ impl ClientKvApi { inner .rpc_caller_put_append_start .regist(inner.view.p2p_module()); + inner + .rpc_caller_batch_put_append_start + .regist(inner.view.p2p_module()); inner .rpc_caller_put_append_revoke .regist(inner.view.p2p_module()); inner .rpc_caller_put_append_done .regist(inner.view.p2p_module()); + inner + .rpc_caller_batch_put_append_done + .regist(inner.view.p2p_module()); + inner + .rpc_caller_batch_evict_owner_source + .regist(inner.view.p2p_module()); inner .rpc_caller_reserve_local_grant .regist(inner.view.p2p_module()); @@ -4179,6 +5524,8 @@ impl ClientKvApi { RPCCaller::::new().regist(inner.view.p2p_module()); RPCCaller::::new().regist(inner.view.p2p_module()); spawn_owner_local_reserve_rebalance_actor(inner.view.clone_view()); + spawn_owner_slot_pressure_actor(inner.view.clone_view()); + external_api::spawn_external_get_start_handle_sweeper(inner.view.clone_view()); self.spawn_runtime_observe_reporter(); // External RPC handlers @@ -4533,10 +5880,11 @@ impl ClientKvApi { } if inner.owner_hot_cache.is_some() { if let Some(owner_hot_eviction_rx) = inner.owner_hot_eviction_rx.lock().take() { - put::spawn_owner_hot_replica_dispatcher( + put::spawn_owner_source_eviction_dispatcher( inner.view.clone_view(), owner_hot_eviction_rx, ); + put::spawn_owner_hot_retry_actor(inner.view.clone_view()); } else { tracing::warn!("owner_hot_eviction_rx already taken for ClientKvApi"); } @@ -4551,7 +5899,7 @@ impl ClientKvApi { tracing::warn!("owner_local_publish_rx already taken for ClientKvApi"); } - // Spawn cluster listener to clean up get_holding when external_client leaves + // Spawn cluster listener to retire generation-scoped external requester state. let view = inner.view.clone_view(); let view2 = view.clone(); let view_task = view2.clone(); @@ -4566,15 +5914,43 @@ impl ClientKvApi { Ok(event) => { match event { ClusterEvent::MemberLeft(node_id) => { - let removed = view_task - .client_kv_api() - .inner() + let departed_epoch = view_task + .cluster_manager() + .get_prev_member_info(&node_id) + .map(|member| member.node_start_time); + let current_epoch = view_task + .cluster_manager() + .get_member_info_cached(&node_id) + .map(|member| member.node_start_time); + let Some(departed_epoch) = external_api::external_member_left_departed_epoch( + departed_epoch, + current_epoch, + ) else { + tracing::debug!( + "Ignoring ambiguous/delayed external MemberLeft: node={} departed_epoch={:?} current_epoch={:?}", + node_id, + departed_epoch, + current_epoch, + ); + continue; + }; + + let inner = view_task.client_kv_api().inner(); + let removed_handles = external_api::cleanup_external_get_start_handles_for_generation( + &inner.external_get_start_registry, + &node_id, + departed_epoch, + ); + let removed_holdings = inner .external_get_holding - .cleanup_node(&node_id); - if removed > 0 { + .cleanup_node_generation(&node_id, departed_epoch); + if removed_handles > 0 || removed_holdings > 0 { tracing::info!( - "Cleaned up get_holding for external_client: {} (removed {} holdings)", - node_id, removed + "Cleaned up departed external requester state: node={} epoch={} handles={} holdings={}", + node_id, + departed_epoch, + removed_handles, + removed_holdings, ); } } @@ -4582,8 +5958,11 @@ impl ClientKvApi { } } Err(e) => { - tracing::error!("Failed to receive cluster event: {}", e); - break; + tracing::warn!( + "Client cluster event receiver error (will resubscribe): {}", + e + ); + listen_cluster_event = view_task.cluster_manager().listen(); } } } diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs index 1171c65..8bfa822 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs @@ -1,8 +1,9 @@ use super::{ - ClientKvApiInner, OwnerHotEvictionEvent, OwnerLocalReserveClassState, - OwnerLocalReserveGrantState, OwnerLocalReservePoolState, OwnerLocalReserveSlotLease, - OwnerLocalReserveSlotRef, ReplicaTaskJob, ReplicaTaskTarget, + ClientKvApiInner, OwnerHotEvictionEvent, OwnerHotEvictionPreparation, OwnerHotSelectionDebt, + OwnerLocalReserveClassState, OwnerLocalReserveGrantState, OwnerLocalReservePoolState, + OwnerLocalReserveSlotLease, OwnerLocalReserveSlotRef, ReplicaTaskJob, ReplicaTaskTarget, local_reserve_rebalance::{owner_local_reserve_timeout_config, wait_owner_local_reserve_ready}, + owner_hot_weight_bytes, }; use crate::OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES; use crate::cluster_manager::NodeIDString; @@ -16,16 +17,20 @@ use crate::observe_kvope::{ use crate::{ client_kv_api::ClientKvApiView, master_kv_router::msg_pack::{ - BatchEnqueueReplicaTaskReq, BatchEnqueueReplicaTaskResp, BatchPreparePutKeyItemReq, - BatchPreparePutKeysReq, BatchPreparePutKeysResp, BatchPutDoneItemReq, BatchPutDoneReq, + BatchEnqueueReplicaTaskReq, BatchEnqueueReplicaTaskResp, BatchEvictOwnerSourceReq, + BatchEvictOwnerSourceResp, BatchPreparePutKeyItemReq, BatchPreparePutKeysReq, + BatchPreparePutKeysResp, BatchPutAppendDoneItemReq, BatchPutAppendDoneReq, + BatchPutAppendDoneResp, BatchPutAppendStartItemReq, BatchPutAppendStartReq, + BatchPutAppendStartResp, BatchPutDoneItemReq, BatchPutDoneItemResp, BatchPutDoneReq, BatchPutDoneResp, BatchPutRevokeItemReq, BatchPutRevokeReq, BatchPutRevokeResp, BatchPutStartItemReq, BatchPutStartReq, BatchPutStartResp, BatchReleasePutKeyReservationsReq, BatchReleasePutKeyReservationsResp, EnqueueReplicaTaskItemResp, GroupedBatchPutDoneItemReq, GroupedBatchPutDoneReq, - GroupedBatchPutDoneResp, PutAppendDoneReq, PutAppendDoneResp, PutAppendRevokeReq, - PutAppendStartReq, PutAppendStartResp, PutAtomicGroup, PutDoneCommittedSlot, PutDoneReq, - PutRevokeReq, PutStartReq, PutStartResp, ReleaseLocalGrantReq, ReserveLocalGrantOutcome, - ReserveLocalGrantReq, + GroupedBatchPutDoneResp, OwnerReclaimBacking, OwnerSourceEvictionCohort, + OwnerSourceEvictionMember, OwnerSourceEvictionOutcome, PutAppendDoneReq, PutAppendDoneResp, + PutAppendRevokeReq, PutAppendStartOutcome, PutAppendStartReq, PutAppendStartResp, + PutAtomicGroup, PutDoneCommittedSlot, PutDoneReq, PutRevokeReq, PutStartReq, PutStartResp, + ReleaseLocalGrantReq, ReserveLocalGrantOutcome, ReserveLocalGrantReq, }, memholder::{UserMemHolder, UserMemHolderExposeKind}, p2p::msg_pack::MsgPack, @@ -34,7 +39,7 @@ use crate::{ }; use chrono::Utc; use fluxon_commu::TransferBreakdown; -use fluxon_util::semaphore_map::SemaphoreMap; +use futures::future::join_all; use limit_thirdparty::tokio; use std::sync::{Arc, atomic::Ordering}; use std::time::{Duration, Instant}; @@ -78,7 +83,7 @@ fn owner_local_reserve_install_grant( class_state.slots_per_grant == slots_per_grant, "slots_per_grant drift detected while installing local reserve grant" ); - class_state.grants.push(grant); + class_state.install_grant(grant); } fn owner_local_reserve_try_claim( @@ -120,18 +125,7 @@ fn owner_local_reserve_claim_available( .entry(slot_size) .or_insert_with(|| OwnerLocalReserveClassState::new(slot_size, slots_per_grant)); let claim_count = class_state.free_slot_count().min(max_slots); - let mut slots = Vec::with_capacity(claim_count); - for grant in class_state.grants.iter_mut() { - while slots.len() < claim_count { - match grant.claim_prepared_slot() { - Some(slot) => slots.push(slot), - None => break, - } - } - if slots.len() == claim_count { - break; - } - } + let slots = class_state.claim_available(max_slots); assert_eq!( slots.len(), claim_count, @@ -241,6 +235,125 @@ mod local_reserve_claim_tests { assert_eq!(pool.classes.get(&8).unwrap().free_slot_count(), 0); } + #[test] + fn grant_index_and_cached_counters_survive_swap_remove_and_reinstall() { + const SLOT_SIZE: u64 = 8; + const SLOTS_PER_GRANT: u32 = 4; + let mut pool = OwnerLocalReservePoolState::default(); + for grant_id in 1..=3 { + owner_local_reserve_install_grant( + &mut pool, + SLOT_SIZE, + SLOTS_PER_GRANT, + OwnerLocalReserveGrantState::new( + grant_id, + grant_id * 1000, + grant_id * 1000, + SLOT_SIZE * u64::from(SLOTS_PER_GRANT), + SLOT_SIZE, + SLOTS_PER_GRANT, + ), + ); + } + + let class = pool.classes.get_mut(&SLOT_SIZE).unwrap(); + assert_eq!(class.free_slot_count(), 12); + assert_eq!(class.used_slot_count(), 0); + let detached = class + .detach_fully_free_grant(2) + .expect("middle grant must be indexed"); + assert_eq!(class.free_slot_count(), 8); + assert_eq!(class.grant_count(), 2); + + // Removing the middle Vec entry swap-moves grant 3. A subsequent state + // transition by grant id proves that its repaired index is authoritative. + let claimed = class.claim_available(1); + assert_eq!(claimed.len(), 1); + assert_eq!(claimed[0].grant_id, 3); + assert_eq!(class.free_slot_count(), 7); + assert_eq!(class.prepared_slot_count(), 1); + assert!(class.release_prepared_slot(3, claimed[0].slot_index)); + assert_eq!(class.free_slot_count(), 8); + assert_eq!(class.prepared_slot_count(), 0); + + class.install_grant(detached); + assert_eq!(class.free_slot_count(), 12); + assert_eq!(class.used_slot_count(), 0); + assert_eq!(class.grant_count(), 3); + } + + #[test] + fn committed_slots_are_reclaimed_and_reused_independently_across_grants() { + const SLOT_SIZE: u64 = 8; + const SLOTS_PER_GRANT: u32 = 4; + + let mut pool = OwnerLocalReservePoolState::default(); + for (grant_id, addr) in [(1, 1000), (2, 2000)] { + owner_local_reserve_install_grant( + &mut pool, + SLOT_SIZE, + SLOTS_PER_GRANT, + OwnerLocalReserveGrantState::new( + grant_id, + addr, + addr, + SLOT_SIZE * u64::from(SLOTS_PER_GRANT), + SLOT_SIZE, + SLOTS_PER_GRANT, + ), + ); + } + + let initial = owner_local_reserve_claim_available(&mut pool, SLOT_SIZE, SLOTS_PER_GRANT, 8); + assert_eq!(initial.len(), 8); + { + let class = pool.classes.get_mut(&SLOT_SIZE).unwrap(); + for slot in &initial { + assert!(class.mark_prepared_slot_pending_visible(slot.grant_id, slot.slot_index)); + assert!(class.retain_resident_slot_holder(slot.grant_id, slot.slot_index)); + assert!( + class.promote_pending_visible_slot_to_committed(slot.grant_id, slot.slot_index) + ); + } + } + + let victims = [initial[1].clone(), initial[5].clone()]; + { + let class = pool.classes.get_mut(&SLOT_SIZE).unwrap(); + for victim in &victims { + assert!(class.release_committed_slot_route(victim.grant_id, victim.slot_index)); + assert!(class.release_resident_slot_holder(victim.grant_id, victim.slot_index)); + } + assert_eq!(class.free_slot_count(), 2); + assert_eq!(class.grant_count(), 2); + assert!(class.grants.iter().all(|grant| !grant.is_fully_free())); + assert!(class.grants.iter().all(|grant| grant.free_slots.len() == 1)); + } + + for cycle in 0..10 { + let reused = + owner_local_reserve_claim_available(&mut pool, SLOT_SIZE, SLOTS_PER_GRANT, 2); + assert_eq!(reused.len(), 2, "cycle {cycle} did not reuse both slots"); + let mut reused_grant_ids = reused.iter().map(|slot| slot.grant_id).collect::>(); + reused_grant_ids.sort_unstable(); + assert_eq!(reused_grant_ids, vec![1, 2]); + + let class = pool.classes.get_mut(&SLOT_SIZE).unwrap(); + for slot in reused { + assert!(class.mark_prepared_slot_pending_visible(slot.grant_id, slot.slot_index)); + assert!(class.retain_resident_slot_holder(slot.grant_id, slot.slot_index)); + assert!( + class.promote_pending_visible_slot_to_committed(slot.grant_id, slot.slot_index) + ); + assert!(class.release_committed_slot_route(slot.grant_id, slot.slot_index)); + assert!(class.release_resident_slot_holder(slot.grant_id, slot.slot_index)); + } + assert_eq!(class.free_slot_count(), 2); + assert_eq!(class.grant_count(), 2); + assert!(class.grants.iter().all(|grant| !grant.is_fully_free())); + } + } + #[limit_thirdparty::tokio::test] async fn later_waiter_cannot_steal_slot_before_current_claim_turn_completes() { const SLOT_SIZE: u64 = 4 * 1024; @@ -272,7 +385,8 @@ mod local_reserve_claim_tests { } // Model a five-slot waiter that has made partial progress while owning the claim turn. - let current_claim_turn = api.inner().owner_local_reserve_claim_lock.lock().await; + let claim_lock = api.inner().owner_local_reserve_claim_lock(SLOT_SIZE); + let current_claim_turn = claim_lock.lock().await; let first_partial = { let mut pool = api.inner().owner_local_reserve_pool.lock(); owner_local_reserve_claim_available(&mut pool, SLOT_SIZE, SLOTS_PER_GRANT, 3) @@ -335,10 +449,110 @@ mod local_reserve_claim_tests { assert_eq!(later_lease.slots.len(), 1); } + #[limit_thirdparty::tokio::test] + async fn same_class_claim_waiters_complete_in_fifo_order() { + const SLOT_SIZE: u64 = 4 * 1024; + + let api = Arc::new( + ClientKvApi::construct(ClientKvApiNewArg { + test_spec_config: TestSpecConfig::default(), + owner_hot_cache_capacity_bytes: None, + }) + .await + .expect("construct test ClientKvApi"), + ); + let claim_lock = api.inner().owner_local_reserve_claim_lock(SLOT_SIZE); + let claim_turn = claim_lock.lock().await; + let order = Arc::new(std::sync::Mutex::new(Vec::new())); + + let first_queued = Arc::new(std::sync::atomic::AtomicBool::new(false)); + let first_lock = api.inner().owner_local_reserve_claim_lock(SLOT_SIZE); + let first_order = Arc::clone(&order); + let first_queued_task = Arc::clone(&first_queued); + let first = tokio::spawn(async move { + first_queued_task.store(true, std::sync::atomic::Ordering::Release); + let _turn = first_lock.lock_owned().await; + first_order.lock().unwrap().push(1u8); + }); + while !first_queued.load(std::sync::atomic::Ordering::Acquire) { + tokio::task::yield_now().await; + } + + let second_queued = Arc::new(std::sync::atomic::AtomicBool::new(false)); + let second_lock = api.inner().owner_local_reserve_claim_lock(SLOT_SIZE); + let second_order = Arc::clone(&order); + let second_queued_task = Arc::clone(&second_queued); + let second = tokio::spawn(async move { + second_queued_task.store(true, std::sync::atomic::Ordering::Release); + let _turn = second_lock.lock_owned().await; + second_order.lock().unwrap().push(2u8); + }); + while !second_queued.load(std::sync::atomic::Ordering::Acquire) { + tokio::task::yield_now().await; + } + drop(claim_turn); + + limit_thirdparty::tokio::time::timeout(Duration::from_secs(1), async { + first.await.expect("first same-class waiter panicked"); + second.await.expect("second same-class waiter panicked"); + }) + .await + .expect("same-class FIFO waiters did not complete"); + assert_eq!(*order.lock().unwrap(), vec![1, 2]); + } + + #[limit_thirdparty::tokio::test] + async fn pressured_class_does_not_block_an_unrelated_slot_class() { + const BLOCKED_SLOT_SIZE: u64 = 4 * 1024; + const READY_SLOT_SIZE: u64 = 8 * 1024; + let ready_slots_per_grant = owner_local_reserve_slots_per_grant(READY_SLOT_SIZE); + + let api = Arc::new( + ClientKvApi::construct(ClientKvApiNewArg { + test_spec_config: TestSpecConfig::default(), + owner_hot_cache_capacity_bytes: None, + }) + .await + .expect("construct test ClientKvApi"), + ); + let blocked_lock = api + .inner() + .owner_local_reserve_claim_lock(BLOCKED_SLOT_SIZE); + let _blocked_turn = blocked_lock.lock().await; + { + let mut pool = api.inner().owner_local_reserve_pool.lock(); + owner_local_reserve_install_grant( + &mut pool, + READY_SLOT_SIZE, + ready_slots_per_grant, + OwnerLocalReserveGrantState::new( + 1, + 1000, + 1000, + READY_SLOT_SIZE * u64::from(ready_slots_per_grant), + READY_SLOT_SIZE, + ready_slots_per_grant, + ), + ); + } + + let ready_api = Arc::clone(&api); + let ready_lease = limit_thirdparty::tokio::time::timeout( + Duration::from_secs(1), + ready_api + .inner() + .owner_claim_local_reserve_slot_lease(READY_SLOT_SIZE, 1), + ) + .await + .expect("an unrelated slot class was head-of-line blocked") + .expect("ready slot class claim failed"); + assert_eq!(ready_lease.slot_size, READY_SLOT_SIZE); + assert_eq!(ready_lease.slots.len(), 1); + } + #[limit_thirdparty::tokio::test] async fn queued_claims_publish_aggregate_demand_and_cancel_cleanly() { const SLOT_SIZE: u64 = 4 * 1024; - const SLOTS_PER_GRANT: u32 = 4; let api = Arc::new( ClientKvApi::construct(ClientKvApiNewArg { @@ -348,7 +562,8 @@ mod local_reserve_claim_tests { .await .expect("construct test ClientKvApi"), ); - let claim_turn = api.inner().owner_local_reserve_claim_lock.lock().await; + let claim_lock = api.inner().owner_local_reserve_claim_lock(SLOT_SIZE); + let claim_turn = claim_lock.lock().await; let first_api = Arc::clone(&api); let first = tokio::spawn(async move { @@ -435,6 +650,10 @@ pub struct OwnerLocalPublishItem { pub struct OwnerLocalPublishJob { pub items: Vec, pub key_reservation_ids: Vec, + /// External local-first requests keep their owner reclaim fences here until + /// the grouped master terminal response and all local promotions complete. + /// Native/Pyo3 jobs use master key reservations instead and leave this empty. + pub external_pending_contexts: Vec, } #[derive(Debug, Clone, Copy, Default)] @@ -525,12 +744,8 @@ impl ClientKvApiInner { request_started_at, )); }; - let _claim_turn = match tokio::time::timeout( - remaining_for_turn, - self.owner_local_reserve_claim_lock.lock(), - ) - .await - { + let claim_lock = self.owner_local_reserve_claim_lock(slot_size); + let _claim_turn = match tokio::time::timeout(remaining_for_turn, claim_lock.lock()).await { Ok(claim_turn) => claim_turn, Err(_) => { return Err(owner_local_reserve_timeout_error( @@ -611,19 +826,14 @@ impl ClientKvApiInner { })); }; for slot_ref in &lease.slots { - let Some(grant) = class_state - .grants - .iter_mut() - .find(|grant| grant.grant_id == slot_ref.grant_id) - else { + if !class_state.release_prepared_slot(slot_ref.grant_id, slot_ref.slot_index) { return Err(KvError::Api(ApiError::Unknown { detail: format!( "resident local reserve grant missing while releasing slot lease: grant_id={}", slot_ref.grant_id ), })); - }; - grant.release_prepared_slot(slot_ref.slot_index); + } } } self.owner_local_reserve_rebalance_notify().notify_waiters(); @@ -645,19 +855,14 @@ impl ClientKvApiInner { ), })); }; - let Some(grant) = class_state - .grants - .iter_mut() - .find(|grant| grant.grant_id == grant_id) - else { + if !class_state.mark_prepared_slot_pending_visible(grant_id, slot_index) { return Err(KvError::Api(ApiError::Unknown { detail: format!( "local reserve grant missing while marking pending slot: grant_id={}", grant_id ), })); - }; - grant.mark_prepared_slot_pending_visible(slot_index); + } Ok(()) } @@ -676,19 +881,14 @@ impl ClientKvApiInner { ), })); }; - let Some(grant) = class_state - .grants - .iter_mut() - .find(|grant| grant.grant_id == grant_id) - else { + if !class_state.promote_pending_visible_slot_to_committed(grant_id, slot_index) { return Err(KvError::Api(ApiError::Unknown { detail: format!( "local reserve grant missing while promoting pending slot: grant_id={}", grant_id ), })); - }; - grant.promote_pending_visible_slot_to_committed(slot_index); + } Ok(()) } @@ -707,19 +907,14 @@ impl ClientKvApiInner { ), })); }; - let Some(grant) = class_state - .grants - .iter_mut() - .find(|grant| grant.grant_id == grant_id) - else { + if !class_state.retain_resident_slot_holder(grant_id, slot_index) { return Err(KvError::Api(ApiError::Unknown { detail: format!( "local reserve grant missing while retaining resident slot holder: grant_id={}", grant_id ), })); - }; - grant.retain_resident_slot_holder(slot_index); + } Ok(()) } @@ -739,19 +934,14 @@ impl ClientKvApiInner { ), })); }; - let Some(grant) = class_state - .grants - .iter_mut() - .find(|grant| grant.grant_id == grant_id) - else { + if !class_state.release_resident_slot_holder(grant_id, slot_index) { return Err(KvError::Api(ApiError::Unknown { detail: format!( "local reserve grant missing while releasing resident slot holder: grant_id={}", grant_id ), })); - }; - grant.release_resident_slot_holder(slot_index); + } } self.owner_local_reserve_rebalance_notify().notify_waiters(); Ok(()) @@ -773,19 +963,43 @@ impl ClientKvApiInner { ), })); }; - let Some(grant) = class_state - .grants - .iter_mut() - .find(|grant| grant.grant_id == grant_id) - else { + if !class_state.release_committed_slot_route(grant_id, slot_index) { return Err(KvError::Api(ApiError::Unknown { detail: format!( "local reserve grant missing while releasing committed slot route: grant_id={}", grant_id ), })); + } + } + self.owner_local_reserve_rebalance_notify().notify_waiters(); + Ok(()) + } + + pub fn owner_release_local_reserve_committed_resident_slot( + &self, + slot_size: u64, + grant_id: u64, + slot_index: u32, + ) -> KvResult<()> { + { + let mut pool = self.owner_local_reserve_pool.lock(); + let Some(class_state) = pool.classes.get_mut(&slot_size) else { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "local reserve class missing while reclaiming committed resident slot: slot_size={}", + slot_size + ), + })); }; - grant.release_committed_slot_route(slot_index); + if !class_state.release_committed_resident_slot(grant_id, slot_index) { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "local reserve grant missing while reclaiming committed resident slot: grant_id={}", + grant_id + ), + })); + } } self.owner_local_reserve_rebalance_notify().notify_waiters(); Ok(()) @@ -795,8 +1009,8 @@ impl ClientKvApiInner { let grants = { let mut pool = self.owner_local_reserve_pool.lock(); let mut detached = Vec::new(); - for (_slot_size, class_state) in pool.classes.drain() { - detached.extend(class_state.grants); + for (_slot_size, mut class_state) in pool.classes.drain() { + detached.extend(class_state.take_all_grants()); } detached }; @@ -1263,10 +1477,9 @@ impl ClientKvApiInner { .send(ReplicaTaskJob { key: key.to_string(), put_id, - holder, + holder: Some(holder), target: Some(target), preferred_sub_cluster: None, - hot_replica_guard: None, protect_source_on_remote_complete: true, }) .await @@ -1314,10 +1527,9 @@ impl ClientKvApiInner { .send(ReplicaTaskJob { key: key.to_string(), put_id, - holder, + holder: Some(holder), target: None, preferred_sub_cluster, - hot_replica_guard: None, protect_source_on_remote_complete, }) .await @@ -1808,23 +2020,14 @@ impl ClientKvApiInner { .await } - pub async fn reserve_local_grant( - &self, - slot_size: u64, - required_free_slots: u32, - reclaim_before_grow: bool, - ) -> KvResult { + pub async fn reserve_local_grant(&self) -> KvResult { if !self.view.register_shutdown_poller().is_running() { return Err(KvError::Api(ApiError::SystemShutdown { detail: "ClientKvApi is shutting down; rejecting reserve_local_grant".to_string(), })); } let req = MsgPack { - serialize_part: ReserveLocalGrantReq { - slot_size, - required_free_slots, - reclaim_before_grow, - }, + serialize_part: ReserveLocalGrantReq {}, raw_bytes: Vec::new(), }; let master_node_id = self @@ -1933,7 +2136,6 @@ impl ClientKvApiInner { put_id: PutIDForAKey, len: u32, preferred_sub_cluster: Option<&str>, - demote_source_on_remote_complete: bool, protect_source_on_remote_complete: bool, ) -> KvResult { if !self.view.register_shutdown_poller().is_running() { @@ -1947,7 +2149,6 @@ impl ClientKvApiInner { put_id, len: len as u64, preferred_sub_cluster: preferred_sub_cluster.map(|s| s.to_string()), - demote_source_on_remote_complete, protect_source_on_remote_complete, }, raw_bytes: Vec::new(), @@ -1975,6 +2176,113 @@ impl ClientKvApiInner { Ok(resp.serialize_part) } + pub async fn batch_put_append_start( + &self, + items: Vec, + ) -> KvResult { + if items.is_empty() { + return Ok(BatchPutAppendStartResp { + items: Vec::new(), + error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + }); + } + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting batch_put_append_start" + .to_string(), + })); + } + let req = MsgPack { + serialize_part: BatchPutAppendStartReq { items }, + raw_bytes: Vec::new(), + }; + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let resp = self + .rpc_caller_batch_put_append_start + .call_with_transport_policy( + self.view.p2p_module(), + master_node_id.into(), + req, + Some(std::time::Duration::from_secs(60)), + RpcTransportPolicy::ForceTransport, + 2, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + Ok(resp.serialize_part) + } + + pub async fn batch_evict_owner_source( + &self, + cohorts: Vec, + ) -> KvResult { + if cohorts.is_empty() { + return Ok(BatchEvictOwnerSourceResp { + operation_id: 0, + cohorts: Vec::new(), + error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, + error_json: String::new(), + }); + } + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting owner source eviction".to_string(), + })); + } + let operation_id = self + .next_owner_source_eviction_operation_id + .fetch_add(1, Ordering::Relaxed); + let self_info = self.view.cluster_manager().get_self_info(); + let req = MsgPack { + serialize_part: BatchEvictOwnerSourceReq { + operation_id, + owner_node_start_time: self_info.node_start_time, + cohorts, + }, + raw_bytes: Vec::new(), + }; + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let resp = self + .rpc_caller_batch_evict_owner_source + .call_with_transport_policy( + self.view.p2p_module(), + master_node_id.into(), + req, + Some(Duration::from_secs(60)), + RpcTransportPolicy::ForceTransport, + 2, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + if resp.serialize_part.operation_id != operation_id { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "owner source-eviction operation id mismatch: requested={} response={}", + operation_id, resp.serialize_part.operation_id + ), + })); + } + Ok(resp.serialize_part) + } + pub async fn put_append_revoke(&self, key: &str, put_id: PutIDForAKey) -> KvResult<()> { if !self.view.register_shutdown_poller().is_running() { return Err(KvError::Api(ApiError::SystemShutdown { @@ -2047,17 +2355,25 @@ impl ClientKvApiInner { Ok(resp.serialize_part) } - pub async fn batch_put_start( + pub async fn batch_put_append_done( &self, - items: Vec, - ) -> KvResult { + items: Vec, + ) -> KvResult { + if items.is_empty() { + return Ok(BatchPutAppendDoneResp { + items: Vec::new(), + error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + }); + } if !self.view.register_shutdown_poller().is_running() { return Err(KvError::Api(ApiError::SystemShutdown { - detail: "ClientKvApi is shutting down; rejecting batch_put_start".to_string(), + detail: "ClientKvApi is shutting down; rejecting batch_put_append_done".to_string(), })); } let req = MsgPack { - serialize_part: BatchPutStartReq { items }, + serialize_part: BatchPutAppendDoneReq { items }, raw_bytes: Vec::new(), }; let master_node_id = self @@ -2066,14 +2382,14 @@ impl ClientKvApiInner { .find_or_wait_master_node() .await?; let resp = self - .rpc_caller_batch_put_start + .rpc_caller_batch_put_append_done .call_with_transport_policy( self.view.p2p_module(), master_node_id.into(), req, Some(std::time::Duration::from_secs(60)), RpcTransportPolicy::ForceTransport, - 2, + 0, ) .await .map_err(KvError::from)?; @@ -2084,21 +2400,58 @@ impl ClientKvApiInner { Ok(resp.serialize_part) } - pub async fn batch_prepare_put_keys( + pub async fn batch_put_start( &self, - items: Vec, - ) -> KvResult { - if items.is_empty() { - return Ok(BatchPreparePutKeysResp { - reservation_ids: Vec::new(), - error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, - error_json: String::new(), - server_process_us: 0, - }); - } + items: Vec, + ) -> KvResult { if !self.view.register_shutdown_poller().is_running() { return Err(KvError::Api(ApiError::SystemShutdown { - detail: "ClientKvApi is shutting down; rejecting batch_prepare_put_keys" + detail: "ClientKvApi is shutting down; rejecting batch_put_start".to_string(), + })); + } + let req = MsgPack { + serialize_part: BatchPutStartReq { items }, + raw_bytes: Vec::new(), + }; + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let resp = self + .rpc_caller_batch_put_start + .call_with_transport_policy( + self.view.p2p_module(), + master_node_id.into(), + req, + Some(std::time::Duration::from_secs(60)), + RpcTransportPolicy::ForceTransport, + 2, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + Ok(resp.serialize_part) + } + + pub async fn batch_prepare_put_keys( + &self, + items: Vec, + ) -> KvResult { + if items.is_empty() { + return Ok(BatchPreparePutKeysResp { + reservation_ids: Vec::new(), + error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + }); + } + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting batch_prepare_put_keys" .to_string(), })); } @@ -2486,30 +2839,20 @@ impl ClientKvApiInner { } } -const OWNER_HOT_APPEND_START_MAX_ATTEMPTS: usize = 3; - -fn replica_append_demotes_source_on_remote_complete(is_owner_hot: bool) -> bool { - // Owner-hot eviction is an exclusive tier transition after the remote cohort is recoverable. - // Ordinary replica and tier-1 append tasks remain inclusive. - is_owner_hot -} +const REPLICA_TASK_BATCH_MERGE_WINDOW: Duration = Duration::from_millis(2); +const OWNER_LOCAL_PUBLISH_RETRY_INITIAL: Duration = Duration::from_millis(25); +const OWNER_LOCAL_PUBLISH_RETRY_MAX: Duration = Duration::from_secs(1); #[cfg(test)] mod owner_hot_replica_policy_tests { use super::{ OwnerLocalPublishItem, complete_owner_local_publish_group_lens, - replica_append_demotes_source_on_remote_complete, + owner_local_publish_cohort_complete, }; use crate::master_kv_router::msg_pack::{ PutAtomicGroup, PutAtomicGroupMember, PutDoneCommittedSlot, }; - #[test] - fn owner_hot_replication_is_exclusive_after_remote_completion() { - assert!(replica_append_demotes_source_on_remote_complete(true)); - assert!(!replica_append_demotes_source_on_remote_complete(false)); - } - fn publish_item( key: &str, put_id: (u64, u32), @@ -2562,6 +2905,33 @@ mod owner_hot_replica_policy_tests { ]; assert_eq!(complete_owner_local_publish_group_lens(&partial), None); } + + #[test] + fn hot_admission_waits_for_every_atomic_group_member_to_publish() { + let group = PutAtomicGroup { + members: vec![ + PutAtomicGroupMember { + key: "a".to_string(), + put_id: (1, 0), + }, + PutAtomicGroupMember { + key: "b".to_string(), + put_id: (1, 1), + }, + ], + }; + let items = vec![ + publish_item("a", (1, 0), Some(group.clone())), + publish_item("b", (1, 1), Some(group)), + publish_item("single", (2, 0), None), + ]; + let partial = vec![&items[0]]; + assert!(!owner_local_publish_cohort_complete(&items[0], &partial)); + let complete = vec![&items[0], &items[1]]; + assert!(owner_local_publish_cohort_complete(&items[0], &complete)); + assert!(owner_local_publish_cohort_complete(&items[1], &complete)); + assert!(owner_local_publish_cohort_complete(&items[2], &partial)); + } } async fn start_replica_append_with_retry( @@ -2569,116 +2939,411 @@ async fn start_replica_append_with_retry( job: &ReplicaTaskJob, len: u32, ) -> KvResult { - let max_attempts = if job.hot_replica_guard.is_some() { - OWNER_HOT_APPEND_START_MAX_ATTEMPTS - } else { - 1 + inner + .put_append_start( + &job.key, + job.put_id, + len, + job.preferred_sub_cluster.as_deref(), + job.protect_source_on_remote_complete, + ) + .await +} + +fn owner_source_eviction_identity( + member: &OwnerSourceEvictionMember, +) -> super::OwnerHotReplicaIdentity { + super::OwnerHotReplicaIdentity { + key: member.key.clone(), + put_time_ms: member.put_id.0, + put_version: member.put_id.1, + } +} + +fn owner_source_eviction_member( + identity: &super::OwnerHotReplicaIdentity, + memory_info: &crate::memholder::MemoryInfo, +) -> Option { + let (slot_size, grant_id, slot_index) = memory_info.local_reserve_resident_slot_ref()?; + Some(OwnerSourceEvictionMember { + key: identity.key.clone(), + put_id: (identity.put_time_ms, identity.put_version), + backing: OwnerReclaimBacking::CommittedSlot { + grant_id, + slot_index, + slot_size, + }, + }) +} + +fn finish_owner_source_selection( + inner: &ClientKvApiInner, + cohort: &OwnerSourceEvictionCohort, + restore_current: bool, + reason: &str, +) { + for member in &cohort.members { + let identity = owner_source_eviction_identity(member); + if let Some((_identity, debt)) = inner.owner_source_eviction_selected.remove(&identity) { + debt.release(); + inner + .owner_hot_counters + .source_evict_restored_members + .fetch_add(1, Ordering::Relaxed); + } + inner.owner_hot_retry_queue.remove(&identity); + if !restore_current { + continue; + } + let group = inner + .owner_hot_atomic_groups + .get(&identity) + .map(|entry| entry.value().clone()); + if inner.owner_hot_admit_published_committed(&member.key, member.put_id, group.as_deref()) { + tracing::warn!( + key = member.key, + put_time_ms = member.put_id.0, + put_version = member.put_id.1, + reason, + "restored current source to owner-hot after source eviction did not enter reclaim" + ); + } + } +} + +fn schedule_owner_source_eviction_retry( + inner: &ClientKvApiInner, + mut event: OwnerHotEvictionEvent, + cohort: Arc, + reason: &'static str, +) { + event.retry = true; + event.source_eviction_cohort = Some(cohort); + inner.owner_hot_retry_queue.schedule(event, reason); +} + +fn prepare_owner_source_eviction_event( + inner: &ClientKvApiInner, + mut event: OwnerHotEvictionEvent, +) -> Option<(OwnerHotEvictionEvent, Arc)> { + let trigger = super::OwnerHotReplicaIdentity { + key: event.key.clone(), + put_time_ms: event.put_id.0, + put_version: event.put_id.1, }; - let mut attempt = 1usize; - loop { - match inner - .put_append_start( - &job.key, - job.put_id, - len, - job.preferred_sub_cluster.as_deref(), - replica_append_demotes_source_on_remote_complete(job.hot_replica_guard.is_some()), - job.protect_source_on_remote_complete, + + if event.retry { + let _ = inner.owner_hot_retry_queue.take_for_inflight(&trigger); + } + if let Some(cohort) = event.source_eviction_cohort.clone() { + if cohort.members.iter().all(|member| { + inner + .owner_source_eviction_selected + .contains_key(&owner_source_eviction_identity(member)) + }) { + return Some((event, cohort)); + } + // Commit/invalidation may win the race with a due retry. Any remaining + // selected members are restored rather than leaving false projected credit. + finish_owner_source_selection(inner, &cohort, true, "retry cohort lost selected identity"); + event.selection_debt.release(); + return None; + } + + if inner.owner_source_eviction_selected.contains_key(&trigger) { + event.selection_debt.release(); + inner + .owner_hot_counters + .group_trigger_duplicates + .fetch_add(1, Ordering::Relaxed); + return None; + } + + let (resolved_trigger, sources) = match inner.owner_hot_prepare_eviction(&event) { + OwnerHotEvictionPreparation::Ready { trigger, sources } => (trigger, sources), + OwnerHotEvictionPreparation::RetryableReclaimFence => { + inner.owner_hot_retry_queue.schedule( + event, + "owner reclaim fence busy before exact source selection", + ); + return None; + } + OwnerHotEvictionPreparation::RetryableIncompleteCohort => { + inner + .owner_hot_retry_queue + .schedule(event, "owner source cohort is temporarily incomplete"); + return None; + } + OwnerHotEvictionPreparation::Obsolete => { + event.selection_debt.release(); + inner + .owner_hot_counters + .source_evict_obsolete + .fetch_add(1, Ordering::Relaxed); + return None; + } + }; + debug_assert_eq!(resolved_trigger, trigger); + + let members = sources + .iter() + .map(|(identity, memory_info)| owner_source_eviction_member(identity, memory_info.as_ref())) + .collect::>>(); + let Some(members) = members else { + event.selection_debt.release(); + inner + .owner_hot_counters + .group_trigger_incomplete + .fetch_add(1, Ordering::Relaxed); + tracing::error!( + key = event.key, + put_time_ms = event.put_id.0, + put_version = event.put_id.1, + "owner-hot selected a source without exact CommittedSlot backing" + ); + return None; + }; + let cohort = Arc::new(OwnerSourceEvictionCohort { members }); + + if cohort.members.iter().any(|member| { + inner + .owner_source_eviction_selected + .contains_key(&owner_source_eviction_identity(member)) + }) { + event.selection_debt.release(); + inner + .owner_hot_counters + .group_trigger_duplicates + .fetch_add(1, Ordering::Relaxed); + return None; + } + + let mut installed = Vec::with_capacity(cohort.members.len()); + for ((identity, memory_info), member) in sources.iter().zip(cohort.members.iter()) { + debug_assert_eq!(identity, &owner_source_eviction_identity(member)); + let debt = if identity == &trigger { + event.selection_debt.clone() + } else { + OwnerHotSelectionDebt::new( + u64::from(owner_hot_weight_bytes(memory_info.as_ref())), + inner.owner_hot_counters.selection_debt_bytes.clone(), ) - .await + }; + if inner + .owner_source_eviction_selected + .insert(identity.clone(), debt.clone()) + .is_some() { - Ok(resp) => return Ok(resp), - Err(err) - if attempt < max_attempts - && matches!(err, KvError::Api(ApiError::KeyBeingWritten { .. })) => - { - tracing::warn!( - "owner hot replica append start failed; retrying: key={} put_id=({},{}) attempt={}/{} err={}", - job.key, - job.put_id.0, - job.put_id.1, - attempt, - max_attempts, - err + debt.release(); + for installed_identity in installed { + if let Some((_identity, installed_debt)) = inner + .owner_source_eviction_selected + .remove(&installed_identity) + { + installed_debt.release(); + } + } + event.selection_debt.release(); + return None; + } + installed.push(identity.clone()); + } + event.source_eviction_cohort = Some(cohort.clone()); + Some((event, cohort)) +} + +async fn process_owner_source_eviction_events( + view: &ClientKvApiView, + events: Vec, +) { + let inner = view.client_kv_api().inner(); + let prepared = events + .into_iter() + .filter_map(|event| prepare_owner_source_eviction_event(inner, event)) + .collect::>(); + if prepared.is_empty() { + return; + } + let cohorts = prepared + .iter() + .map(|(_, cohort)| cohort.as_ref().clone()) + .collect::>(); + let response = inner.batch_evict_owner_source(cohorts).await; + let Ok(response) = response else { + for (event, cohort) in prepared { + schedule_owner_source_eviction_retry( + inner, + event, + cohort, + "owner source-eviction RPC failed", + ); + } + return; + }; + if response.cohorts.len() != prepared.len() { + for (event, cohort) in prepared { + schedule_owner_source_eviction_retry( + inner, + event, + cohort, + "owner source-eviction response length mismatch", + ); + } + return; + } + + for (index, ((event, cohort), result)) in prepared + .into_iter() + .zip(response.cohorts.into_iter()) + .enumerate() + { + if result.cohort_index != u32::try_from(index).unwrap_or(u32::MAX) { + schedule_owner_source_eviction_retry( + inner, + event, + cohort, + "owner source-eviction response identity mismatch", + ); + continue; + } + match result.outcome { + OwnerSourceEvictionOutcome::Accepted + | OwnerSourceEvictionOutcome::AlreadyInProgress => { + inner + .owner_hot_counters + .source_evict_handoff_members + .fetch_add(cohort.members.len() as u64, Ordering::Relaxed); + // Selected debt stays live until owner reclaim Commit calls + // owner_hot_invalidate_version for every exact member. + } + OwnerSourceEvictionOutcome::Completed => { + finish_owner_source_selection( + inner, + &cohort, + true, + "master reported source deletion already completed", + ); + } + OwnerSourceEvictionOutcome::RetryableBusy | OwnerSourceEvictionOutcome::Unspecified => { + schedule_owner_source_eviction_retry( + inner, + event, + cohort, + "master source reclaim is temporarily busy", + ); + } + OwnerSourceEvictionOutcome::Stale => { + finish_owner_source_selection( + inner, + &cohort, + true, + "master rejected stale source identity", + ); + } + OwnerSourceEvictionOutcome::RejectedNotEvictable => { + tracing::error!( + cohort_members = cohort.members.len(), + detail = result.detail, + "owner selected a source cohort that master declared non-evictable" + ); + finish_owner_source_selection( + inner, + &cohort, + true, + "master rejected non-evictable source cohort", ); - let delay_ms = 25u64.saturating_mul(1u64 << (attempt - 1)); - tokio::time::sleep(Duration::from_millis(delay_ms)).await; - attempt += 1; } - Err(err) => return Err(err), } } } -pub fn spawn_owner_hot_replica_dispatcher( +pub fn spawn_owner_source_eviction_dispatcher( view: ClientKvApiView, - mut rx: tokio::sync::ampsc::Receiver, + mut rx: tokio::sync::ampsc::UnboundedReceiver, ) { + const MAX_COHORTS_PER_RPC: usize = 128; + const MERGE_WINDOW: Duration = Duration::from_millis(2); + let view_task = view.clone(); - let _ = view.spawn("owner_hot_replica_dispatcher", async move { + let _ = view.spawn("owner_source_eviction_dispatcher", async move { let mut shutdown_waiter = view_task.register_shutdown_waiter(); loop { - let event = tokio::select! { + let first = tokio::select! { _ = shutdown_waiter.wait() => { - tracing::info!("owner_hot_replica_dispatcher stopping due to shutdown signal"); + tracing::info!("owner source-eviction dispatcher stopping due to shutdown"); break; } event = rx.recv() => { - match event { - Some(event) => event, - None => break, - } + let Some(event) = event else { break; }; + event } }; - let inner = view_task.client_kv_api().inner(); - let Some(memory_info) = event.memory_info.upgrade() else { - event.guard.mark_obsolete(); - continue; - }; - if !inner.owner_hot_source_is_current( - &event.key, - event.put_id, - &memory_info, - ) { - event.guard.mark_obsolete(); + let mut events = Vec::with_capacity(MAX_COHORTS_PER_RPC); + events.push(first); + let merge_window = tokio::time::sleep(MERGE_WINDOW); + tokio::pin!(merge_window); + while events.len() < MAX_COHORTS_PER_RPC { + tokio::select! { + _ = &mut merge_window => break, + event = rx.recv() => { + let Some(event) = event else { break; }; + events.push(event); + } + } + } + process_owner_source_eviction_events(&view_task, events).await; + } + }); +} + +pub fn spawn_owner_hot_retry_actor(view: ClientKvApiView) { + const RETRY_EMIT_BATCH: usize = 128; + const RETRY_POLL_INTERVAL: Duration = Duration::from_millis(25); + + let view_task = view.clone(); + let _ = view.spawn("owner_hot_retry_actor", async move { + let mut shutdown_waiter = view_task.register_shutdown_waiter(); + let retry_queue = view_task + .client_kv_api() + .inner() + .owner_hot_retry_queue + .clone(); + let notify = retry_queue.notify.clone(); + let mut tick = tokio::time::interval(RETRY_POLL_INTERVAL); + loop { + tokio::select! { + _ = shutdown_waiter.wait() => return, + _ = tick.tick() => {}, + _ = notify.notified() => {}, + } + let events = retry_queue.take_due_batch(Instant::now(), RETRY_EMIT_BATCH); + if events.is_empty() { continue; } - let holder = Arc::new(UserMemHolder::new( - memory_info, - inner.get_or_init_all_memholder_refcount(), - UserMemHolderExposeKind::SegPtr, - )); - let key = event.key.clone(); - let put_id = event.put_id; - if let Err(err) = inner - .replica_task_tx - .send(ReplicaTaskJob { - key: event.key, - put_id: event.put_id, - holder, - target: None, - preferred_sub_cluster: None, - hot_replica_guard: Some(event.guard), - protect_source_on_remote_complete: false, - }) - .await - { - tracing::warn!( - "replica task actor queue closed for owner hot eviction: key={} put_id=({},{}) err={}", - key, - put_id.0, - put_id.1, - err - ); + let inner = view_task.client_kv_api().inner(); + for event in events { + if let Err(err) = inner.owner_hot_eviction_tx.send(event) { + let event = err.0; + retry_queue.schedule(event, "retry dispatcher closed"); + return; + } + inner + .owner_hot_counters + .source_evict_retry_emitted + .fetch_add(1, Ordering::Relaxed); } } }); } -async fn process_replica_task(view_task: ClientKvApiView, job: ReplicaTaskJob) { +async fn process_replica_task(view_task: ClientKvApiView, mut job: ReplicaTaskJob) { let inner = view_task.client_kv_api().inner(); - let src_offset = job.holder.memory_info().offset; - let len = job.holder.get_length() as u64; + let holder = job + .holder + .as_ref() + .expect("replica task source must be pinned before transfer"); + let src_offset = holder.memory_info().offset; + let len = holder.get_length() as u64; let target = if let Some(target) = job.target.clone() { target } else { @@ -2708,17 +3373,19 @@ async fn process_replica_task(view_task: ClientKvApiView, job: ReplicaTaskJob) { return; } }; - if !append_start.scheduled { - tracing::debug!( - "replica append task not scheduled: key={} put_id=({},{})", - job.key, - job.put_id.0, - job.put_id.1 - ); - if let Some(guard) = job.hot_replica_guard.as_ref() { - guard.mark_already_satisfied(); + match append_start.outcome { + PutAppendStartOutcome::Scheduled => {} + PutAppendStartOutcome::AlreadySatisfied | PutAppendStartOutcome::Obsolete => return, + PutAppendStartOutcome::RetryableNoSpace | PutAppendStartOutcome::Unspecified => { + tracing::debug!( + outcome = ?append_start.outcome, + "replica append task deferred: key={} put_id=({},{})", + job.key, + job.put_id.0, + job.put_id.1 + ); + return; } - return; } ReplicaTaskTarget { node_id: append_start.node_id, @@ -2763,7 +3430,7 @@ async fn process_replica_task(view_task: ClientKvApiView, job: ReplicaTaskJob) { } // Append-done may reclaim the source synchronously. Release the transfer-only holder first so // this task does not make its own reclaim look busy. - drop(job.holder); + drop(job.holder.take()); match inner.put_append_done(&job.key, job.put_id).await { Ok(resp) => { tracing::debug!( @@ -2773,13 +3440,6 @@ async fn process_replica_task(view_task: ClientKvApiView, job: ReplicaTaskJob) { job.put_id.1, resp.appended ); - if let Some(guard) = job.hot_replica_guard.as_ref() { - if resp.appended { - guard.mark_completed(); - } else { - guard.mark_already_satisfied(); - } - } } Err(err) => { tracing::warn!( @@ -2793,6 +3453,349 @@ async fn process_replica_task(view_task: ClientKvApiView, job: ReplicaTaskJob) { } } +struct ReplicaAppendDoneJob { + key: String, + put_id: PutIDForAKey, +} + +async fn finish_replica_append_jobs_individually( + inner: &ClientKvApiInner, + jobs: Vec, +) { + let results = join_all(jobs.into_iter().map(|job| async move { + let result = inner.put_append_done(&job.key, job.put_id).await; + (job, result) + })) + .await; + for (job, result) in results { + match result { + Ok(_resp) => {} + Err(err) => { + tracing::warn!( + "replica task append done fallback failed: key={} put_id=({},{}) err={}", + job.key, + job.put_id.0, + job.put_id.1, + err + ); + } + } + } +} + +async fn process_replica_append_batch(view_task: ClientKvApiView, jobs: Vec) { + if jobs.is_empty() { + return; + } + let inner = view_task.client_kv_api().inner(); + let mut valid_jobs = Vec::with_capacity(jobs.len()); + let mut start_items = Vec::with_capacity(jobs.len()); + for job in jobs { + let len = job + .holder + .as_ref() + .expect("batch replica source must be pinned") + .get_length() as u64; + if u32::try_from(len).is_err() { + tracing::warn!( + "replica append task length does not fit u32: key={} put_id=({},{}) len={}", + job.key, + job.put_id.0, + job.put_id.1, + len + ); + continue; + } + start_items.push(BatchPutAppendStartItemReq { + key: job.key.clone(), + put_id: job.put_id, + len, + preferred_sub_cluster: job.preferred_sub_cluster.clone(), + protect_source_on_remote_complete: job.protect_source_on_remote_complete, + }); + valid_jobs.push(job); + } + if valid_jobs.is_empty() { + return; + } + + let requested = valid_jobs.len(); + let start_time = Instant::now(); + let start_resp = match inner.batch_put_append_start(start_items).await { + Ok(resp) if resp.items.len() == requested => resp, + Ok(resp) => { + tracing::warn!( + "batch replica append start response length mismatch: expected={} got={}", + requested, + resp.items.len() + ); + for job in valid_jobs { + spawn_replica_task_revoke( + view_task.clone(), + job.key, + job.put_id, + "batch start response mismatch", + ); + } + return; + } + Err(err) => { + tracing::warn!( + "batch replica append start RPC failed; falling back per item: items={} err={}", + requested, + err + ); + join_all( + valid_jobs + .into_iter() + .map(|job| process_replica_task(view_task.clone(), job)), + ) + .await; + return; + } + }; + + let mut scheduled = Vec::new(); + let mut already_satisfied = 0usize; + let mut start_failed = 0usize; + for (job, item) in valid_jobs.into_iter().zip(start_resp.items.into_iter()) { + if item.key != job.key || item.put_id != job.put_id { + tracing::warn!( + "batch replica append start identity mismatch: request_key={} request_put_id=({},{}) response_key={} response_put_id=({},{})", + job.key, + job.put_id.0, + job.put_id.1, + item.key, + item.put_id.0, + item.put_id.1 + ); + spawn_replica_task_revoke( + view_task.clone(), + job.key, + job.put_id, + "batch start identity mismatch", + ); + start_failed += 1; + continue; + } + if let Err(err) = + crate::rpcresp_kvresult_convert::try_from_code(item.error_code, item.error_json.clone()) + { + tracing::warn!( + "batch replica append start item failed: key={} put_id=({},{}) err={}", + job.key, + job.put_id.0, + job.put_id.1, + err + ); + start_failed += 1; + continue; + } + match item.outcome { + PutAppendStartOutcome::Scheduled => {} + PutAppendStartOutcome::AlreadySatisfied => { + already_satisfied += 1; + continue; + } + PutAppendStartOutcome::Obsolete => continue, + PutAppendStartOutcome::RetryableNoSpace | PutAppendStartOutcome::Unspecified => { + start_failed += 1; + continue; + } + } + let target = ReplicaTaskTarget { + node_id: item.node_id, + target_offset: item.target_addr - item.target_base_addr, + target_base_addr: item.target_base_addr, + len: item.len, + }; + let source_len = job + .holder + .as_ref() + .expect("scheduled batch replica source must remain pinned") + .get_length() as u64; + if source_len != target.len { + tracing::warn!( + "batch replica task length mismatch: key={} put_id=({},{}) src_len={} target_len={}", + job.key, + job.put_id.0, + job.put_id.1, + source_len, + target.len + ); + spawn_replica_task_revoke( + view_task.clone(), + job.key, + job.put_id, + "batch length mismatch", + ); + start_failed += 1; + continue; + } + scheduled.push((job, target)); + } + tracing::info!( + requested, + scheduled = scheduled.len(), + already_satisfied, + failed = start_failed, + rpc_us = duration_to_i64_us(start_time.elapsed()), + "replica writeback batch start complete" + ); + + let transfer_results = join_all(scheduled.into_iter().map(|(job, target)| { + let transfer_view = view_task.clone(); + async move { + let inner = transfer_view.client_kv_api().inner(); + let src_offset = job + .holder + .as_ref() + .expect("scheduled batch replica source must remain pinned") + .memory_info() + .offset; + let result = inner + .put_transfer( + &job.key, + job.put_id, + src_offset, + target.target_offset, + target.len, + Some(target.node_id), + Some(target.target_base_addr), + ) + .await; + (job, result) + } + })) + .await; + + let mut done_jobs = Vec::new(); + for (job, result) in transfer_results { + match result { + Ok(_) => { + let ReplicaTaskJob { + key, + put_id, + holder, + .. + } = job; + drop(holder); + done_jobs.push(ReplicaAppendDoneJob { key, put_id }); + } + Err(err) => { + tracing::warn!( + "batch replica task transfer failed: key={} put_id=({},{}) err={}", + job.key, + job.put_id.0, + job.put_id.1, + err + ); + spawn_replica_task_revoke( + view_task.clone(), + job.key, + job.put_id, + "batch transfer error", + ); + } + } + } + if done_jobs.is_empty() { + return; + } + + let done_requested = done_jobs.len(); + let done_items = done_jobs + .iter() + .map(|job| BatchPutAppendDoneItemReq { + key: job.key.clone(), + put_id: job.put_id, + }) + .collect(); + let done_time = Instant::now(); + let done_resp = match inner.batch_put_append_done(done_items).await { + Ok(resp) if resp.items.len() == done_requested => resp, + Ok(resp) => { + tracing::warn!( + "batch replica append done response length mismatch: expected={} got={}; falling back per item", + done_requested, + resp.items.len() + ); + finish_replica_append_jobs_individually(inner, done_jobs).await; + return; + } + Err(err) => { + tracing::warn!( + "batch replica append done RPC failed; falling back per item: items={} err={}", + done_requested, + err + ); + finish_replica_append_jobs_individually(inner, done_jobs).await; + return; + } + }; + + let mut appended = 0usize; + let mut already_done = 0usize; + let mut done_failed = 0usize; + for (job, item) in done_jobs.into_iter().zip(done_resp.items.into_iter()) { + let identity_matches = item.key == job.key && item.put_id == job.put_id; + let item_result = crate::rpcresp_kvresult_convert::try_from_code( + item.error_code, + item.error_json.clone(), + ); + if !identity_matches || item_result.is_err() { + tracing::warn!( + "batch replica append done item failed: key={} put_id=({},{}) identity_matches={} err={:?}", + job.key, + job.put_id.0, + job.put_id.1, + identity_matches, + item_result.err() + ); + spawn_replica_task_revoke( + view_task.clone(), + job.key, + job.put_id, + "batch done item error", + ); + done_failed += 1; + continue; + } + if item.appended { + appended += 1; + } else { + already_done += 1; + } + } + tracing::info!( + requested = done_requested, + appended, + already_satisfied = already_done, + failed = done_failed, + rpc_us = duration_to_i64_us(done_time.elapsed()), + "replica writeback batch done complete" + ); +} + +async fn process_replica_task_batch(view_task: ClientKvApiView, jobs: Vec) { + let mut append_jobs = Vec::new(); + let mut reserved_target_jobs = Vec::new(); + for job in jobs { + if job.target.is_some() { + reserved_target_jobs.push(job); + } else { + append_jobs.push(job); + } + } + let append = process_replica_append_batch(view_task.clone(), append_jobs); + let reserved = join_all( + reserved_target_jobs + .into_iter() + .map(|job| process_replica_task(view_task.clone(), job)), + ); + let (_, _) = futures::join!(append, reserved); +} + pub fn spawn_replica_task_actor( view: ClientKvApiView, mut rx: tokio::sync::ampsc::Receiver, @@ -2801,15 +3804,14 @@ pub fn spawn_replica_task_actor( let view_task = view.clone(); let _ = view.spawn("replica_task_actor", async move { let max_inflight = max_inflight.max(1); - let semaphore = Arc::new(::tokio::sync::Semaphore::new(max_inflight)); - let per_key = Arc::new(SemaphoreMap::new(1, Duration::from_secs(10 * 60))); tracing::info!( max_inflight, - "replica task actor started with bounded cross-key concurrency" + merge_window_ms = REPLICA_TASK_BATCH_MERGE_WINDOW.as_millis(), + "replica task actor started with time-window batching" ); let mut shutdown_waiter = view_task.register_shutdown_waiter(); loop { - let job = tokio::select! { + let first = tokio::select! { _ = shutdown_waiter.wait() => { tracing::info!("replica_task_actor stopping due to shutdown signal"); break; @@ -2821,24 +3823,23 @@ pub fn spawn_replica_task_actor( } } }; - let permit = match semaphore.clone().acquire_owned().await { - Ok(permit) => permit, - Err(err) => { - tracing::warn!( - "replica task actor semaphore closed; dropping queued work: err={}", - err - ); - break; + let mut batch = Vec::with_capacity(max_inflight); + batch.push(first); + let merge_window = tokio::time::sleep(REPLICA_TASK_BATCH_MERGE_WINDOW); + tokio::pin!(merge_window); + while batch.len() < max_inflight { + tokio::select! { + _ = &mut merge_window => break, + job = rx.recv() => { + match job { + Some(job) => batch.push(job), + None => break, + } + } } - }; - let spawn_view = view_task.clone(); - let worker_view = view_task.clone(); - let worker_per_key = per_key.clone(); - spawn_view.spawn("replica_task_worker", async move { - let _permit = permit; - let _key_permit = worker_per_key.acquire(job.key.clone()).await; - process_replica_task(worker_view, job).await; - }); + } + tracing::info!(items = batch.len(), "replica writeback batch flushed"); + process_replica_task_batch(view_task.clone(), batch).await; } }); } @@ -2962,7 +3963,20 @@ fn complete_owner_local_publish_group_lens(items: &[OwnerLocalPublishItem]) -> O Some(group_lens) } -async fn publish_owner_local_job(view: ClientKvApiView, job: OwnerLocalPublishJob) { +fn owner_local_publish_cohort_complete( + item: &OwnerLocalPublishItem, + promoted_items: &[&OwnerLocalPublishItem], +) -> bool { + item.atomic_group.as_ref().map_or(true, |group| { + group.members.iter().all(|member| { + promoted_items + .iter() + .any(|published| published.key == member.key && published.put_id == member.put_id) + }) + }) +} + +pub(crate) async fn publish_owner_local_job(view: ClientKvApiView, job: OwnerLocalPublishJob) { let inner = view.client_kv_api().inner(); if job.items.is_empty() { release_owner_local_publish_reservations(inner, job.key_reservation_ids).await; @@ -2970,105 +3984,209 @@ async fn publish_owner_local_job(view: ClientKvApiView, job: OwnerLocalPublishJo } let group_lens = complete_owner_local_publish_group_lens(&job.items); - let done_items = if let Some(atomic_group_lens) = group_lens { - inner - .owner_hot_counters - .grouped_put_done_batches - .fetch_add(1, Ordering::Relaxed); - inner - .owner_hot_counters - .grouped_put_done_items - .fetch_add(job.items.len() as u64, Ordering::Relaxed); - let items = job - .items - .iter() - .map(|item| GroupedBatchPutDoneItemReq { - key: item.key.clone(), - put_id: item.put_id, - lease_id: item.lease_id, - committed_slot: Some(item.committed_slot.clone()), - publish_local_cache: false, - }) - .collect::>(); - inner - .grouped_batch_put_done(items, atomic_group_lens) - .await - .map(|resp| resp.items) - } else { - inner - .owner_hot_counters - .legacy_put_done_batches - .fetch_add(1, Ordering::Relaxed); - inner - .owner_hot_counters - .legacy_put_done_items - .fetch_add(job.items.len() as u64, Ordering::Relaxed); - let items = job - .items - .iter() - .map(|item| BatchPutDoneItemReq { - key: item.key.clone(), - put_id: item.put_id, - lease_id: item.lease_id, - committed_slot: Some(item.committed_slot.clone()), - publish_local_cache: false, - atomic_group: item.atomic_group.clone(), - }) - .collect::>(); - inner.batch_put_done(items).await.map(|resp| resp.items) - }; + let incomplete_declared_group = + group_lens.is_none() && job.items.iter().any(|item| item.atomic_group.is_some()); + let mut shutdown_waiter = view.register_shutdown_waiter(); + let mut retry_delay = OWNER_LOCAL_PUBLISH_RETRY_INITIAL; + let mut published = false; - match done_items { - Ok(done_items) if done_items.len() == job.items.len() => { - for (item, done_item) in job.items.iter().zip(done_items.into_iter()) { - if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( + loop { + let attempt: Result<(), String> = async { + if incomplete_declared_group { + return Err( + "declared atomic group is incomplete or non-contiguous in publish job" + .to_string(), + ); + } + let done_items: Vec = + if let Some(atomic_group_lens) = group_lens.clone() { + inner + .owner_hot_counters + .grouped_put_done_batches + .fetch_add(1, Ordering::Relaxed); + inner + .owner_hot_counters + .grouped_put_done_items + .fetch_add(job.items.len() as u64, Ordering::Relaxed); + let items = job + .items + .iter() + .map(|item| GroupedBatchPutDoneItemReq { + key: item.key.clone(), + put_id: item.put_id, + lease_id: item.lease_id, + committed_slot: Some(item.committed_slot.clone()), + publish_local_cache: false, + }) + .collect::>(); + inner + .grouped_batch_put_done(items, atomic_group_lens) + .await + .map(|resp| resp.items) + .map_err(|err| format!("PutDone RPC uncertain: {err}"))? + } else { + inner + .owner_hot_counters + .legacy_put_done_batches + .fetch_add(1, Ordering::Relaxed); + inner + .owner_hot_counters + .legacy_put_done_items + .fetch_add(job.items.len() as u64, Ordering::Relaxed); + let items = job + .items + .iter() + .map(|item| BatchPutDoneItemReq { + key: item.key.clone(), + put_id: item.put_id, + lease_id: item.lease_id, + committed_slot: Some(item.committed_slot.clone()), + publish_local_cache: false, + atomic_group: item.atomic_group.clone(), + }) + .collect::>(); + inner + .batch_put_done(items) + .await + .map(|resp| resp.items) + .map_err(|err| format!("PutDone RPC uncertain: {err}"))? + }; + + if done_items.len() != job.items.len() { + return Err(format!( + "PutDone response length mismatch: expected={} got={}", + job.items.len(), + done_items.len() + )); + } + for (item, done_item) in job.items.iter().zip(done_items.iter()) { + if done_item.key != item.key || done_item.put_id != item.put_id { + return Err(format!( + "PutDone identity mismatch: request=({},({},{}) response=({},({},{}))", + item.key, + item.put_id.0, + item.put_id.1, + done_item.key, + done_item.put_id.0, + done_item.put_id.1, + )); + } + crate::rpcresp_kvresult_convert::try_from_code( done_item.error_code, done_item.error_json.clone(), + ) + .map_err(|err| { + format!( + "PutDone item unresolved: key={} put_id=({},{}) err={}", + item.key, item.put_id.0, item.put_id.1, err + ) + })?; + } + + // Do not expose only part of an atomic/TP cohort to owner-hot. + // First prove every master route terminal, then roll all local + // precommit slots forward. Replayed attempts accept members that + // were already promoted before a cancellation or partial local + // failure. + for item in &job.items { + if inner.committed_local_reserve_slot_is_current( + &item.key, + item.put_id, + &item.committed_slot, ) { + continue; + } + let memory_info = inner + .precommit_local_visible_memory_info(&item.key) + .ok_or_else(|| { + format!( + "precommit slot missing before promotion: key={} put_id=({},{})", + item.key, item.put_id.0, item.put_id.1 + ) + })?; + inner + .promote_precommit_local_reserve_resident_slot_if_same( + &item.key, + item.put_id, + memory_info, + item.atomic_group.as_ref(), + ) + .map_err(|err| { + format!( + "local promotion unresolved: key={} put_id=({},{}) err={}", + item.key, item.put_id.0, item.put_id.1, err + ) + })?; + } + Ok(()) + } + .await; + + match attempt { + Ok(()) => { + published = true; + break; + } + Err(reason) => { + tracing::warn!( + "owner local publish retained full cohort for retry: key_count={} external_fences={} retry_ms={} reason={}", + job.items.len(), + job.external_pending_contexts.len(), + retry_delay.as_millis(), + reason, + ); + } + } + + tokio::select! { + _ = tokio::time::sleep(retry_delay) => {} + _ = shutdown_waiter.wait() => break, + } + retry_delay = retry_delay + .saturating_mul(2) + .min(OWNER_LOCAL_PUBLISH_RETRY_MAX); + } + + if published { + let promoted_items = job.items.iter().collect::>(); + for item in &promoted_items { + if !owner_local_publish_cohort_complete(item, &promoted_items) { + tracing::warn!( + "owner local publish skipped hot admission for incomplete atomic group: key={} put_id=({},{})", + item.key, + item.put_id.0, + item.put_id.1 + ); + continue; + } + let _ = inner.owner_hot_admit_published_committed( + &item.key, + item.put_id, + item.atomic_group.as_ref(), + ); + } + + for item in promoted_items { + if item.make_replica_task { + if let Err(err) = inner + .make_replica_append_task( + &item.key, + item.put_id, + item.preferred_sub_cluster.clone(), + true, + ) + .await + { tracing::warn!( - "owner local publish failed: key={} put_id=({},{}) err={}", + "owner local publish enqueue replica append failed: key={} put_id=({},{}) err={}", item.key, item.put_id.0, item.put_id.1, err ); - continue; - } - if item.make_replica_task { - if let Err(err) = inner - .make_replica_append_task( - &item.key, - item.put_id, - item.preferred_sub_cluster.clone(), - true, - ) - .await - { - tracing::warn!( - "owner local publish enqueue replica append failed: key={} put_id=({},{}) err={}", - item.key, - item.put_id.0, - item.put_id.1, - err - ); - } } } } - Ok(done_items) => { - tracing::warn!( - "owner local publish response length mismatch: expected={} got={}", - job.items.len(), - done_items.len() - ); - } - Err(err) => { - tracing::warn!( - "owner local publish batch_put_done rpc failed: key_count={} err={}", - job.items.len(), - err - ); - } } release_owner_local_publish_reservations(inner, job.key_reservation_ids).await; diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs index 2c33a58..f3ea172 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs @@ -24,6 +24,7 @@ fn item_resp( fn record_item(record: &OwnerReclaimRecord) -> &OwnerReclaimItem { match record { OwnerReclaimRecord::Prepared(prepared) => &prepared.item, + OwnerReclaimRecord::Releasing(item) => item, OwnerReclaimRecord::Committed(item) => item, } } @@ -49,15 +50,23 @@ fn memory_matches_reclaim_backing( } } +fn reclaim_key_control_busy_detail(state: &super::OwnerKeyControlState) -> Option<&'static str> { + if state.local_puts != 0 { + Some("owner local put is inflight") + } else if state.external_pending_puts != 0 { + Some("owner external put context is still pending") + } else if state.external_get.is_some() { + Some("owner external Get is inflight") + } else { + None + } +} + fn prepare_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclaimItemResp { - let mut controls = inner.owner_key_control.lock(); + let mut controls = inner.owner_key_control.lock_key(&item.key); if let Some(state) = controls.get(&item.key) { - if state.local_puts != 0 { - return item_resp( - item, - OwnerReclaimItemState::Busy, - "owner local put is inflight", - ); + if let Some(detail) = reclaim_key_control_busy_detail(state) { + return item_resp(item, OwnerReclaimItemState::Busy, detail); } if let Some(record) = state.reclaim.as_ref() { if record_item(record) == item { @@ -65,6 +74,7 @@ fn prepare_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclai item, match record { OwnerReclaimRecord::Prepared(_) => OwnerReclaimItemState::Prepared, + OwnerReclaimRecord::Releasing(_) => OwnerReclaimItemState::Busy, OwnerReclaimRecord::Committed(_) => OwnerReclaimItemState::Committed, }, "reclaim phase already applied", @@ -84,18 +94,13 @@ fn prepare_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclai "owner precommit local index is still visible", ); } - if inner - .external_pending_puts - .iter() - .any(|(pending_key, _)| pending_key.0 == item.key) - { + if inner.pending_local_get_info.contains_key(&item.key) { return item_resp( item, OwnerReclaimItemState::Busy, - "owner external put context is still pending", + "owner local Get commit is pending", ); } - let Some((_key, cached_info)) = inner.get_cached_info.remove_if(&item.key, |_, cached| { cached.put_time_ms == item.put_id.0 && cached.put_version == item.put_id.1 @@ -130,7 +135,12 @@ fn prepare_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclai }) .map(|(_, snapshot)| snapshot); let state = controls.entry(item.key.clone()).or_default(); - assert!(state.reclaim.is_none() && state.local_puts == 0); + assert!( + state.reclaim.is_none() + && state.local_puts == 0 + && state.external_pending_puts == 0 + && state.external_get.is_none() + ); state.reclaim = Some(OwnerReclaimRecord::Prepared(OwnerPreparedReclaim { item: item.clone(), cached_info, @@ -173,26 +183,33 @@ fn release_prepared_backing_now(inner: &ClientKvApiInner, prepared: OwnerPrepare assert_eq!(actual_slot_index, *slot_index); inner - .owner_release_local_reserve_committed_slot_route( + .owner_release_local_reserve_committed_resident_slot( actual_slot_size, actual_grant_id, actual_slot_index, ) - .expect("owner reclaim committed route release must succeed"); - inner - .owner_release_local_reserve_resident_slot_holder( - actual_slot_size, - actual_grant_id, - actual_slot_index, - ) - .expect("owner reclaim resident holder release must succeed"); + .expect("owner reclaim committed resident slot release must succeed"); } } drop(memory_info); } +fn reclaim_release_fence_is_intact( + state: &super::OwnerKeyControlState, + item: &OwnerReclaimItem, +) -> bool { + // Prepare hides the local index before installing the reclaim fence. A + // later external Get may share this key state, but it can only take the + // remote path and therefore does not hold the detached local backing. + matches!( + state.reclaim.as_ref(), + Some(OwnerReclaimRecord::Releasing(releasing)) if releasing == item + ) && state.local_puts == 0 + && state.external_pending_puts == 0 +} + fn commit_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclaimItemResp { - let mut controls = inner.owner_key_control.lock(); + let mut controls = inner.owner_key_control.lock_key(&item.key); let Some(state) = controls.get_mut(&item.key) else { return item_resp( item, @@ -208,7 +225,18 @@ fn commit_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclaim ); }; let prepared = match record { - OwnerReclaimRecord::Prepared(prepared) if prepared.item == *item => prepared, + OwnerReclaimRecord::Prepared(prepared) if prepared.item == *item => { + state.reclaim = Some(OwnerReclaimRecord::Releasing(item.clone())); + prepared + } + OwnerReclaimRecord::Releasing(releasing) if releasing == *item => { + state.reclaim = Some(OwnerReclaimRecord::Releasing(releasing)); + return item_resp( + item, + OwnerReclaimItemState::Busy, + "owner reclaim slot release is already in progress", + ); + } OwnerReclaimRecord::Committed(committed) if committed == *item => { state.reclaim = Some(OwnerReclaimRecord::Committed(committed)); return item_resp( @@ -227,9 +255,19 @@ fn commit_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclaim } }; - // Keep the owner fence installed by holding the control lock until the slot is fully free. + // The Releasing marker keeps local Put/Get out. Drop the key-shard lock + // before touching the slot pool so no synchronous locks are nested. + drop(controls); release_prepared_backing_now(inner, prepared); - assert!(state.reclaim.is_none() && state.local_puts == 0); + + let mut controls = inner.owner_key_control.lock_key(&item.key); + let state = controls + .get_mut(&item.key) + .expect("owner reclaim releasing fence disappeared"); + assert!( + reclaim_release_fence_is_intact(state, item), + "a local put crossed an owner reclaim fence" + ); state.reclaim = Some(OwnerReclaimRecord::Committed(item.clone())); drop(controls); inner.owner_hot_invalidate_version(&item.key, item.put_id); @@ -240,8 +278,65 @@ fn commit_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclaim ) } +#[cfg(test)] +mod tests { + use super::{reclaim_key_control_busy_detail, reclaim_release_fence_is_intact}; + use crate::client_kv_api::{ + ExternalGetKeySharedOp, OwnerKeyControlState, OwnerKeyControlTable, OwnerReclaimRecord, + acquire_external_pending_put_fence_for_key, + }; + use crate::master_kv_router::msg_pack::{ + OwnerReclaimBacking, OwnerReclaimItem, OwnerReclaimReason, + }; + use std::sync::Arc; + + #[test] + fn pending_external_put_rejects_reclaim_prepare_precheck() { + let controls = Arc::new(OwnerKeyControlTable::default()); + let _guard = acquire_external_pending_put_fence_for_key(&controls, "pending-key") + .expect("pending fence acquisition must succeed"); + let controls = controls.lock_key("pending-key"); + assert_eq!( + reclaim_key_control_busy_detail(&controls["pending-key"]), + Some("owner external put context is still pending") + ); + } + + #[test] + fn remote_get_marker_can_overlap_reclaim_commit() { + let item = OwnerReclaimItem { + key: "remote-during-reclaim".to_string(), + put_id: (7, 1), + epoch: 9, + backing: OwnerReclaimBacking::CommittedSlot { + grant_id: 3, + slot_index: 4, + slot_size: 4096, + }, + reason: OwnerReclaimReason::OwnerCapacityEviction, + }; + let state = OwnerKeyControlState { + local_puts: 0, + external_pending_puts: 0, + reclaim: Some(OwnerReclaimRecord::Releasing(item.clone())), + external_get: Some(Arc::new(ExternalGetKeySharedOp::new( + "remote-during-reclaim".to_string(), + ))), + }; + assert!(reclaim_release_fence_is_intact(&state, &item)); + + let local_put_state = OwnerKeyControlState { + local_puts: 1, + external_pending_puts: 0, + reclaim: Some(OwnerReclaimRecord::Releasing(item.clone())), + external_get: state.external_get, + }; + assert!(!reclaim_release_fence_is_intact(&local_put_state, &item)); + } +} + fn abort_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclaimItemResp { - let mut controls = inner.owner_key_control.lock(); + let mut controls = inner.owner_key_control.lock_key(&item.key); let Some(state) = controls.get_mut(&item.key) else { return item_resp( item, @@ -272,7 +367,7 @@ fn abort_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclaimI "owner reclaim abort must restore an empty local snapshot slot" ); } - if state.local_puts == 0 { + if state.is_idle() { controls.remove(&item.key); } item_resp( @@ -281,6 +376,14 @@ fn abort_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclaimI "owner local index fence rolled back", ) } + OwnerReclaimRecord::Releasing(releasing) if releasing == *item => { + state.reclaim = Some(OwnerReclaimRecord::Releasing(releasing)); + item_resp( + item, + OwnerReclaimItemState::Busy, + "owner slot release is already in progress and cannot be aborted", + ) + } OwnerReclaimRecord::Committed(committed) if committed == *item => { state.reclaim = Some(OwnerReclaimRecord::Committed(committed)); item_resp( @@ -301,7 +404,7 @@ fn abort_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclaimI } fn finalize_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclaimItemResp { - let mut controls = inner.owner_key_control.lock(); + let mut controls = inner.owner_key_control.lock_key(&item.key); let Some(state) = controls.get_mut(&item.key) else { return item_resp( item, @@ -311,7 +414,7 @@ fn finalize_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerRecla }; match state.reclaim.take() { Some(OwnerReclaimRecord::Committed(committed)) if committed == *item => { - if state.local_puts == 0 { + if state.is_idle() { controls.remove(&item.key); } item_resp( @@ -320,6 +423,14 @@ fn finalize_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerRecla "owner reclaim fence cleared", ) } + Some(OwnerReclaimRecord::Releasing(releasing)) if releasing == *item => { + state.reclaim = Some(OwnerReclaimRecord::Releasing(releasing)); + item_resp( + item, + OwnerReclaimItemState::Busy, + "owner slot release is still in progress", + ) + } Some(other) => { state.reclaim = Some(other); item_resp( diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/delete.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/delete.rs index 703257f..87a18da 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/delete.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/delete.rs @@ -31,7 +31,7 @@ use std::time::Duration; /// /// It removes the key from `kv_routes`, then asynchronously: /// - emits a `DeleteKeyInfo` to the shared delete broadcast actor for clients -/// - removes the key from every node's local `node_kv_cache_controller` +/// - point-removes the exact version from ring-B and tier1 metadata caches pub fn do_delete_one_kv_all_replicas( view: &MasterKvRouterView, key: String, @@ -67,21 +67,9 @@ pub fn do_delete_one_kv_all_replicas( tracing::warn!("Failed to send delete broadcast: {}", err); } - // Remove from all node caches that hold replicas of this key - let nodes_replicas = kv_route_info.nodes_replicas.read(); - for (node_id, _kv_info) in nodes_replicas.iter() { - if let Some(cache) = view.master_kv_router().get_node_cache_controller(node_id) - { - let _ = cache.remove(&key_clone); - view.master_kv_router() - .remove_node_writeback_tier1_entry(node_id, &key_clone); - tracing::debug!( - "Removed key {} from node cache controller: {}", - key_clone, - node_id - ); - } - } + view.master_kv_router() + .remove_route_cache_entries_exact(&key_clone, &kv_route_info) + .await; } }); @@ -99,7 +87,6 @@ pub fn evict_one_kv_replica_for_node( node_id: NodeID, put_id: PutIDForAKey, ) -> Result<(), msg_and_error::ErrorCode> { - let _guard = view.master_kv_router().inner().route_lifetime_lock.lock(); let route = if let Some(route) = view.master_kv_router().inner().kv_routes.get(&key) { route.clone() } else { @@ -146,7 +133,11 @@ pub fn evict_one_kv_replica_for_node( .master_kv_router() .inner() .kv_routes - .remove_if(&key, |_, current| current.put_id == put_id) + .remove_if(&key, |_, current| { + Arc::ptr_eq(current, &route) + && current.put_id == put_id + && current.nodes_replicas.read().is_empty() + }) .is_some(); if removed && view.master_kv_router().prefix_index_enabled() { let view_task = view.clone(); diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs index 5e0833e..795a1c4 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs @@ -1,22 +1,24 @@ use super::{ - InflightGetInfo, KvRouteInfo, MasterKeyActivityCompletionGuard, MasterKvRouterView, - OwnerHoldingGetInfo, + CommittedSlotReplica, CompletedGetInfo, InflightGetInfo, InflightGetTarget, KvRouteInfo, + MasterKeyActivityCompletionGuard, MasterKvRouterView, OwnerHoldingGetInfo, + ReservedCapacityReason, msg_pack::{ BatchGetDoneItemResp, BatchGetDoneReq, BatchGetDoneResp, BatchGetRevokeItemResp, BatchGetRevokeReq, BatchGetRevokeResp, BatchGetStartItemResp, BatchGetStartReq, BatchGetStartResp, BatchIsExistReq, BatchIsExistResp, GetAllocationMode, GetDoneReq, - GetDoneResp, GetMetaReq, GetMetaResp, GetRevokeReq, GetRevokeResp, GetStartReq, - GetStartResp, MemHolderKeepAliveReq, MemHolderKeepAliveResp, MemHolderReleaseReq, - MemHolderReleaseResp, + GetDoneResp, GetMetaReq, GetMetaResp, GetPreparedLocalReserveTarget, GetRevokeReq, + GetRevokeResp, GetStartReq, GetStartResp, MemHolderKeepAliveReq, MemHolderKeepAliveResp, + MemHolderReleaseReq, MemHolderReleaseResp, }, - route_maintenance::{RoutePublishEvent, enqueue_post_route_maintenance}, + node_generation_is_current_live, publish_route_replica_tomb_fenced, + route_maintenance::{RoutePublishEvent, apply_post_route_maintenance_batch}, }; use crate::master_kv_router::OneKvNodesRoutes; use crate::master_kv_router::put::PutIDForAKey; use crate::memholder::MemholderManagerTrait; use crate::{ cluster_manager::NodeID, - master_seg_manager::{MasterSegManagerAccessTrait, one_seg_allocator::Allocation}, + master_seg_manager::{MasterSegManagerAccessTrait, NodeTombTag, one_seg_allocator::Allocation}, p2p::msg_pack::MsgPack, rpcresp_kvresult_convert::msg_and_error::{self, kv}, }; @@ -28,6 +30,7 @@ use std::collections::HashSet; use std::{ collections::HashMap, sync::{Arc, atomic::Ordering}, + time::Instant, }; fn touch_moka_for_node(view: MasterKvRouterView, node_id: String, key: String) { @@ -36,16 +39,27 @@ fn touch_moka_for_node(view: MasterKvRouterView, node_id: String, key: String) { } let view_task = view.clone(); view.spawn("touch_moka_for_node", async move { + let owner_cache_lock = view_task + .master_kv_router() + .inner() + .owner_cache_operation_locks + .get_lock(node_id.clone()); + let _owner_cache_guard = owner_cache_lock.lock().await; if let Some(cache) = view_task .master_kv_router() .get_node_cache_controller(&node_id) { - if let Some(desc) = cache.get(&key) - && let Some(tier1_cache) = view_task - .master_kv_router() - .get_node_writeback_tier1_controller(&node_id) + // A get is a hit signal for ring B when the source is an + // unindexed Allocation. Owner-indexed routes are intentionally + // absent from this cache. + let _ = cache.get(&key); + if let Some(tier1_cache) = view_task + .master_kv_router() + .get_node_writeback_tier1_controller(&node_id) { - tier1_cache.insert(key.clone(), desc); + // Tier1 has independent admission and replacement state; a + // hit only touches an already-admitted entry. + let _ = tier1_cache.get(&key); } tracing::debug!( "Touched key: {:?} on node cache: {} (TTL refresh)", @@ -69,6 +83,93 @@ fn one_kv_routes_has_live_replica(one_kv_nodes_routes: &OneKvNodesRoutes) -> boo .any(|kv_info| !kv_info.tomb_tag.is_tomb()) } +fn validate_prepared_local_reserve_target( + view: &MasterKvRouterView, + req_node_id: &NodeID, + target: &GetPreparedLocalReserveTarget, + value_len: u64, +) -> Result<(CommittedSlotReplica, NodeTombTag), msg_and_error::KvError> { + let invalid = |detail: String| { + msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { detail }) + }; + if target.slot_size == 0 { + return Err(invalid( + "prepared local-reserve Get target has zero slot_size".to_string(), + )); + } + if value_len > target.slot_size { + return Err(invalid(format!( + "prepared local-reserve Get target is too small: value_len={} slot_size={}", + value_len, target.slot_size + ))); + } + let Some(grant) = view + .master_kv_router() + .inner() + .local_reserve_grants + .get(&target.grant_id) + else { + return Err(invalid(format!( + "prepared local-reserve Get target references unknown grant_id={}", + target.grant_id + ))); + }; + if grant.owner_node_id != *req_node_id { + return Err(invalid(format!( + "prepared local-reserve Get target owner mismatch: grant_id={} owner={} requester={}", + target.grant_id, grant.owner_node_id, req_node_id + ))); + } + let tomb_tag = grant.tomb_tag.clone(); + if !node_generation_is_current_live(view, req_node_id, &tomb_tag) { + return Err(invalid(format!( + "prepared local-reserve Get target belongs to a departed owner generation: grant_id={} requester={}", + target.grant_id, req_node_id + ))); + } + let grant_base_addr = grant.allocation.base_addr(); + let grant_addr = grant_base_addr + .checked_add(grant.allocation.addr()) + .ok_or_else(|| invalid("local-reserve grant address overflow".to_string()))?; + let slot_offset = target + .slot_size + .checked_mul(u64::from(target.slot_index)) + .ok_or_else(|| invalid("prepared local-reserve Get slot offset overflow".to_string()))?; + let slot_end = slot_offset + .checked_add(target.slot_size) + .ok_or_else(|| invalid("prepared local-reserve Get slot end overflow".to_string()))?; + if slot_end > grant.allocation.capcity() { + return Err(invalid(format!( + "prepared local-reserve Get target is outside grant: grant_id={} slot_index={} slot_size={} grant_len={}", + target.grant_id, + target.slot_index, + target.slot_size, + grant.allocation.capcity() + ))); + } + let expected_addr = grant_addr + .checked_add(slot_offset) + .ok_or_else(|| invalid("prepared local-reserve Get target address overflow".to_string()))?; + if target.base_addr != grant_base_addr || target.addr != expected_addr { + return Err(invalid(format!( + "prepared local-reserve Get target geometry mismatch: grant_id={} expected_base={:#x} got_base={:#x} expected_addr={:#x} got_addr={:#x}", + target.grant_id, grant_base_addr, target.base_addr, expected_addr, target.addr + ))); + } + Ok(( + CommittedSlotReplica { + owner_node_id: req_node_id.clone(), + grant_id: target.grant_id, + slot_index: target.slot_index, + slot_size: target.slot_size, + addr: target.addr, + len: value_len, + base_addr: target.base_addr, + }, + tomb_tag, + )) +} + pub async fn handle_get_start( view: MasterKvRouterView, req: MsgPack, @@ -130,6 +231,18 @@ pub async fn handle_get_start( .inner() .next_get_id .fetch_add(1, Ordering::Relaxed); + let prepared_requester_lease = if req.serialize_part.prepared_target.is_some() { + match view.master_kv_router().reserve_prepared_get_requester( + &req.serialize_part.key, + &req_node_id, + get_id, + ) { + Ok(lease) => Some(lease), + Err(err) => return failed_resp_err(err, None, &view, &req.serialize_part.key), + } + } else { + None + }; let one_kv_nodes_routes: Arc = if let Some(one_kv_nodes_routes) = view .master_kv_router() @@ -140,7 +253,7 @@ pub async fn handle_get_start( one_kv_nodes_routes.clone() } else { // Key not found - tracing::info!("Key not found: {}", req.serialize_part.key); + tracing::debug!("Key not found: {}", req.serialize_part.key); let err = msg_and_error::KvError::Api(msg_and_error::ApiError::KeyNotFound { key: req.serialize_part.key.clone(), }); @@ -148,12 +261,14 @@ pub async fn handle_get_start( }; let replicas: HashMap = one_kv_nodes_routes.nodes_replicas.read().clone(); + let prepared_target = req.serialize_part.prepared_target.clone(); // Currently we are holding the lock with `replicas` // 选择一个replica (这里可以实现更复杂的选择逻辑) let mut replica_keys = replicas.keys().collect::>(); let mut tombs = HashSet::new(); - let mut target_allocations = None; + let mut target = None; let mut allocation_mode = GetAllocationMode::Temporary; + let mut durable_reservation = None; for _ in 0..replicas.len() { let to_remove_idx = rand::thread_rng().gen_range(0..replica_keys.len()); let selected_replica_key = replica_keys.remove(to_remove_idx); @@ -172,7 +287,7 @@ pub async fn handle_get_start( // MemHolder backing. That keeps the existing get-path carrier stable // and avoids the old None->unwrap panic. let mut allocate_request_target = - || -> Result, (u64, MsgPack)> { + || -> Result)> { let target_allocation = { let req_node_allocators = view.master_seg_manager().get_node_allocators(&req_node_id); @@ -228,56 +343,127 @@ pub async fn handle_get_start( } allocated_addr.unwrap() }; - if one_kv_nodes_routes.try_reserve_get_durable_slot() { + if let Some(reservation) = one_kv_nodes_routes.try_reserve_get_durable_slot() { allocation_mode = GetAllocationMode::DurableReplica; + durable_reservation = Some(reservation); } else { allocation_mode = GetAllocationMode::Temporary; } - Ok(Arc::new(target_allocation)) + Ok(InflightGetTarget::Allocation(Arc::new(target_allocation))) }; // 为get调用方分配接收内存作为传输target - if target_allocations.is_none() { - target_allocations = Some( - if let Some(replica_on_recv_node) = replicas.get(&req_node_id) { - match &replica_on_recv_node.backing { - super::KvReplicaBacking::Allocation(allocation) => { - allocation_mode = GetAllocationMode::ReuseReplica; - allocation.clone() - } - super::KvReplicaBacking::CommittedSlot(_) => { - match allocate_request_target() { - Ok(allocation) => allocation, - Err(resp) => return resp, - } - } + if target.is_none() { + target = Some(if let Some(prepared_target) = prepared_target.as_ref() { + if replicas + .get(&req_node_id) + .is_some_and(|replica| !replica.tomb_tag.is_tomb()) + { + let err = msg_and_error::KvError::Api( + msg_and_error::ApiError::InvalidArgument { + detail: format!( + "prepared local-reserve Get target cannot replace a live replica: key={} requester={}", + req.serialize_part.key, req_node_id + ), + }, + ); + return failed_resp_err( + err, + Some((tombs.clone(), one_kv_nodes_routes.put_id)), + &view, + &req.serialize_part.key, + ); + } + let (slot, _prepared_tomb_tag) = match validate_prepared_local_reserve_target( + &view, + &req_node_id, + prepared_target, + src_len, + ) { + Ok(slot) => slot, + Err(err) => { + return failed_resp_err( + err, + Some((tombs.clone(), one_kv_nodes_routes.put_id)), + &view, + &req.serialize_part.key, + ); } - } else { - match allocate_request_target() { + }; + allocation_mode = GetAllocationMode::LocalCommittedSlot; + InflightGetTarget::PreparedLocalReserveSlot(slot) + } else if let Some(replica_on_recv_node) = replicas.get(&req_node_id) { + match &replica_on_recv_node.backing { + super::KvReplicaBacking::Allocation(allocation) => { + allocation_mode = GetAllocationMode::ReuseReplica; + InflightGetTarget::Allocation(allocation.clone()) + } + super::KvReplicaBacking::CommittedSlot(_) => match allocate_request_target() { Ok(allocation) => allocation, Err(resp) => return resp, - } - }, - ); + }, + } + } else { + match allocate_request_target() { + Ok(allocation) => allocation, + Err(resp) => return resp, + } + }); } - let target_allocation = target_allocations.unwrap(); + let target = target + .as_ref() + .expect("Get target must be selected before building response") + .clone(); + + // Bind the target to the exact registration generation that owns its + // allocator/grant. Looking up only by node id at GetDone would allow + // an old completion to publish addresses into a reconnected node. + let target_tomb_tag = match &target { + InflightGetTarget::Allocation(allocation) => view + .master_seg_manager() + .get_allocation_tomb_tag(&req_node_id, allocation), + InflightGetTarget::PreparedLocalReserveSlot(slot) => view + .master_kv_router() + .inner() + .local_reserve_grants + .get(&slot.grant_id) + .and_then(|grant| { + (grant.owner_node_id == req_node_id + && node_generation_is_current_live(&view, &req_node_id, &grant.tomb_tag)) + .then(|| grant.tomb_tag.clone()) + }), + }; + let Some(target_tomb_tag) = target_tomb_tag else { + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "Get target generation changed before start publication: get_id={} key={} requester={}", + get_id, req.serialize_part.key, req_node_id + ), + }); + return failed_resp_err( + err, + Some((tombs.clone(), one_kv_nodes_routes.put_id)), + &view, + &req.serialize_part.key, + ); + }; // Convert to absolute addresses for Mooncake (requires absolute) // Use allocation's allocator base directly - let target_base = target_allocation.base_addr(); + let target_base = target.base_addr(); // If we reuse existing target on requesting node, declare src=target on req node let (resp_node_id, resp_src_addr, resp_target_addr, resp_src_base, resp_target_base) = if allocation_mode == GetAllocationMode::ReuseReplica { - let addr = target_base + target_allocation.addr(); + let addr = target.abs_addr(); // both src/target are on requesting node's allocation in this reuse case (req_node_id.clone(), addr, addr, target_base, target_base) } else { ( src_node_id.clone(), src_abs_addr, - target_base + target_allocation.addr(), + target.abs_addr(), src_base, target_base, ) @@ -292,6 +478,10 @@ pub async fn handle_get_start( src_base_addr: resp_src_base, target_base_addr: resp_target_base, len: src_len, + prepared_target: (allocation_mode == GetAllocationMode::LocalCommittedSlot) + .then(|| prepared_target.clone()) + .flatten(), + atomic_group: one_kv_nodes_routes.atomic_group.as_deref().cloned(), error_code: msg_and_error::OK, error_json: String::new(), server_process_us: 0, @@ -309,10 +499,13 @@ pub async fn handle_get_start( key: req.serialize_part.key.clone(), req_node_id, len: src_len, - allocation: target_allocation, // 存储target allocation + target, + target_tomb_tag, route: one_kv_nodes_routes.clone(), allocation_mode, + durable_reservation, _activity_lease: activity_lease, + _prepared_requester_lease: prepared_requester_lease, }; view.master_kv_router() @@ -346,7 +539,7 @@ pub async fn handle_get_start( }, ); } - tracing::info!("Key not found: {}", req.serialize_part.key); + tracing::debug!("Key not found: {}", req.serialize_part.key); { let err = msg_and_error::KvError::Api(msg_and_error::ApiError::KeyNotFound { key: req.serialize_part.key.clone(), @@ -363,10 +556,61 @@ pub async fn handle_get_start( pub async fn handle_get_revoke( view: MasterKvRouterView, req: MsgPack, + req_node_id: NodeID, ) -> MsgPack { tracing::debug!("Handling GetRevokeReq: {:?}", req.serialize_part); let get_id = req.serialize_part.get_id; + let done_lock = view + .master_kv_router() + .inner() + .get_done_locks + .get_lock(get_id); + let _done_guard = done_lock.lock().await; + + if let Some(inflight_info) = view + .master_kv_router() + .inner() + .inflight_gets + .get(&get_id) + .await + { + if inflight_info.req_node_id != req_node_id { + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { + detail: format!( + "GetRevoke requester mismatch: get_id={} expected={} got={}", + get_id, inflight_info.req_node_id, req_node_id + ), + }); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), + raw_bytes: Vec::new(), + }; + } + } else if let Some(completed) = view + .master_kv_router() + .inner() + .completed_gets + .get(&get_id) + .await + { + let detail = if completed.req_node_id != req_node_id { + format!( + "GetRevoke requester mismatch after completion: get_id={} expected={} got={}", + get_id, completed.req_node_id, req_node_id + ) + } else { + format!( + "GetRevoke lost the Done race; committed target must not be released: get_id={}", + get_id + ) + }; + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { detail }); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), + raw_bytes: Vec::new(), + }; + } // Remove from inflight_gets if let Some(inflight_info) = view @@ -378,8 +622,7 @@ pub async fn handle_get_revoke( { let _activity_completion = MasterKeyActivityCompletionGuard::new(inflight_info._activity_lease.clone()); - inflight_info.release_durable_slot_if_needed(); - tracing::info!("Revoked get operation with get_id: {}", get_id); + tracing::debug!("Revoked get operation with get_id: {}", get_id); } else { tracing::warn!("Get operation with get_id {} not found for revoke", get_id); } @@ -393,13 +636,59 @@ pub async fn handle_get_revoke( } } -pub async fn handle_get_done( +async fn handle_get_done_locked( view: MasterKvRouterView, req: MsgPack, + req_node_id: NodeID, + mut deferred_route_events: Option<&mut Vec>, + mut deferred_terminals: Option<&mut Vec<(u64, CompletedGetInfo)>>, ) -> MsgPack { tracing::debug!("Handling GetDoneReq: {:?}", req.serialize_part); let get_id = req.serialize_part.get_id; + if let Some(inflight_info) = view + .master_kv_router() + .inner() + .inflight_gets + .get(&get_id) + .await + { + if inflight_info.req_node_id != req_node_id { + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { + detail: format!( + "GetDone requester mismatch: get_id={} expected={} got={}", + get_id, inflight_info.req_node_id, req_node_id + ), + }); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), + raw_bytes: Vec::new(), + }; + } + } else if let Some(completed) = view + .master_kv_router() + .inner() + .completed_gets + .get(&get_id) + .await + { + if completed.req_node_id != req_node_id { + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { + detail: format!( + "GetDone requester mismatch after completion: get_id={} expected={} got={}", + get_id, completed.req_node_id, req_node_id + ), + }); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), + raw_bytes: Vec::new(), + }; + } + return MsgPack { + serialize_part: completed.response, + raw_bytes: Vec::new(), + }; + } // Remove from inflight_gets and transfer to get_holding if let Some(inflight_info) = view .master_kv_router() @@ -411,77 +700,163 @@ pub async fn handle_get_done( let _activity_completion = MasterKeyActivityCompletionGuard::new(inflight_info._activity_lease.clone()); let mut allocation_mode = inflight_info.allocation_mode; - let route = inflight_info.route.clone(); // clone req_node_id to avoid borrow/move conflict when inserting into kv_routes let req_node_id = inflight_info.req_node_id.clone(); - // capture allocation capacity before moving it - let alloc_cap = inflight_info.allocation.capcity(); - // Generate holder_id - let holder_id = view - .master_kv_router() - .inner() - .next_holder_id - .fetch_add(1, Ordering::Relaxed); - - let src_node_id = inflight_info.src_node_id; let key = inflight_info.key; - - // Create holding info - let holding_info = OwnerHoldingGetInfo { - key: key.clone(), - holding_node_id: inflight_info.req_node_id.clone(), - len: inflight_info.len, - allocation: inflight_info.allocation.clone(), + let target_cap = inflight_info.target.capacity(); + if !node_generation_is_current_live(&view, &req_node_id, &inflight_info.target_tomb_tag) { + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "GetDone target generation departed: get_id={} key={} requester={}", + get_id, key, req_node_id + ), + }); + let terminal: GetDoneResp = + crate::rpcresp_kvresult_convert::FromError::from_error(&err); + let completed = CompletedGetInfo { + req_node_id: req_node_id.clone(), + response: terminal.clone(), + }; + if let Some(terminals) = deferred_terminals.as_deref_mut() { + terminals.push((get_id, completed)); + } else { + view.master_kv_router() + .inner() + .completed_gets + .insert(get_id, completed) + .await; + } + return MsgPack { + serialize_part: terminal, + raw_bytes: Vec::new(), + }; + } + // Allocation-backed Gets need a master holder to keep their allocator guard alive. + // Local-reserve slots instead carry independent route and holder references in the + // owner's slot state, so they deliberately do not create a master Allocation holder. + let mut inserted_holder_key = None; + let holder_id = match &inflight_info.target { + InflightGetTarget::Allocation(allocation) => { + let holder_id = view + .master_kv_router() + .inner() + .next_holder_id + .fetch_add(1, Ordering::Relaxed); + let holder_key = + crate::memholder::NodeHolderKey::new(req_node_id.to_string(), holder_id); + view.master_kv_router().inner().get_holding.insert( + holder_key.clone(), + OwnerHoldingGetInfo { + key: key.clone(), + holding_node_id: inflight_info.req_node_id.clone(), + len: inflight_info.len, + allocation: allocation.clone(), + }, + ); + inserted_holder_key = Some(holder_key); + holder_id + } + InflightGetTarget::PreparedLocalReserveSlot(_) => 0, }; - // Store in get_holding cache (owned manager, flattened key) - view.master_kv_router().inner().get_holding.insert( - crate::memholder::NodeHolderKey::new(req_node_id.to_string(), holder_id), - holding_info, - ); + // Close the insertion-vs-MemberLeft cleanup race for the holder. If + // MemberLeft marked the shared tag before this check, remove the exact + // holder we just inserted. Otherwise its later cleanup must observe it. + if inflight_info.target_tomb_tag.is_tomb() { + if let Some(holder_key) = inserted_holder_key.as_ref() { + view.master_kv_router() + .inner() + .get_holding + .remove(holder_key); + } + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "GetDone target generation departed during holder publication: get_id={} key={} requester={}", + get_id, key, req_node_id + ), + }); + let terminal: GetDoneResp = + crate::rpcresp_kvresult_convert::FromError::from_error(&err); + let completed = CompletedGetInfo { + req_node_id: req_node_id.clone(), + response: terminal.clone(), + }; + if let Some(terminals) = deferred_terminals.as_deref_mut() { + terminals.push((get_id, completed)); + } else { + view.master_kv_router() + .inner() + .completed_gets + .insert(get_id, completed) + .await; + } + return MsgPack { + serialize_part: terminal, + raw_bytes: Vec::new(), + }; + } if allocation_mode == GetAllocationMode::DurableReplica { let mut promote_committed = false; let mut route_publish_event = None; - if let Some(one_kv_nodes_routes) = view.master_kv_router().inner().kv_routes.get(&key) { + if let Some(one_kv_nodes_routes) = view + .master_kv_router() + .inner() + .kv_routes + .get(&key) + .map(|route| route.clone()) + { if one_kv_nodes_routes.put_id == inflight_info.put_id { - let mut nodes_replicas = one_kv_nodes_routes.nodes_replicas.write(); - if let Some(tomb_tag) = - view.master_seg_manager().get_node_tomb_tag(&src_node_id) - { - if !tomb_tag.is_tomb() { - nodes_replicas.insert( - inflight_info.req_node_id.clone(), - KvRouteInfo { - node_id: inflight_info.req_node_id, - backing: super::KvReplicaBacking::Allocation( - inflight_info.allocation, - ), - owner_local_indexed: true, - tomb_tag, - }, - ); - promote_committed = true; - route_publish_event = Some(RoutePublishEvent::replica_append( - key.clone(), - inflight_info.put_id, - one_kv_nodes_routes.lease_id, + match view.master_kv_router().reserve_node_cache_capacity( + &req_node_id, + &inflight_info.target_tomb_tag, + ReservedCapacityReason::OwnerIndexedAllocation, + target_cap, + ) { + Ok(capacity_reservation) => { + let replica = KvRouteInfo { + node_id: req_node_id.clone(), + backing: super::KvReplicaBacking::Allocation(match &inflight_info + .target + { + InflightGetTarget::Allocation(allocation) => allocation.clone(), + InflightGetTarget::PreparedLocalReserveSlot(_) => { + unreachable!("durable Get mode must use Allocation target") + } + }), + owner_local_indexed: true, + get_durable_reservation: inflight_info.durable_reservation.clone(), + capacity_reservation, + tomb_tag: inflight_info.target_tomb_tag.clone(), + }; + if publish_route_replica_tomb_fenced( + &one_kv_nodes_routes, req_node_id.clone(), - alloc_cap, - )); - } else { - tracing::warn!( - "get node is tomb, get_id: {}, put_id: {:?}", - get_id, - one_kv_nodes_routes.put_id - ); + replica, + ) { + promote_committed = true; + route_publish_event = Some(RoutePublishEvent::replica_append( + key.clone(), + inflight_info.put_id, + one_kv_nodes_routes.lease_id, + req_node_id.clone(), + target_cap, + )); + } else { + tracing::warn!( + "durable Get replica publication rejected by generation/live-replica fence: get_id={} put_id={:?}", + get_id, + one_kv_nodes_routes.put_id + ); + } } - } else { - tracing::warn!( - "get node is tomb, get_id: {}, put_id: {:?}", + Err(err) => tracing::warn!( + "durable Get could not reserve owner-indexed Allocation capacity; keeping temporary: get_id={} key={} owner={} err={}", get_id, - one_kv_nodes_routes.put_id - ); + key, + req_node_id, + err, + ), } } else { tracing::warn!( @@ -499,29 +874,91 @@ pub async fn handle_get_done( ); } if let Some(event) = route_publish_event { - enqueue_post_route_maintenance(&view, event).await; + if let Some(events) = deferred_route_events.as_deref_mut() { + events.push(event); + } else { + apply_post_route_maintenance_batch(&view, vec![event]).await; + } } if !promote_committed { allocation_mode = GetAllocationMode::Temporary; - route.release_get_durable_slot(); } } else if allocation_mode == GetAllocationMode::ReuseReplica { let mut local_index_published = false; - if let Some(current_route) = view.master_kv_router().inner().kv_routes.get(&key) { - if current_route.put_id == inflight_info.put_id { - let mut replicas = current_route.nodes_replicas.write(); - if let Some(replica) = replicas.get_mut(&req_node_id) { - local_index_published = !replica.tomb_tag.is_tomb() - && matches!( - &replica.backing, - super::KvReplicaBacking::Allocation(allocation) - if Arc::ptr_eq(allocation, &inflight_info.allocation) - ); - if local_index_published { - replica.owner_local_indexed = true; + let mut route_lease_id = None; + let capacity_reservation = view.master_kv_router().reserve_node_cache_capacity( + &req_node_id, + &inflight_info.target_tomb_tag, + ReservedCapacityReason::OwnerIndexedAllocation, + target_cap, + ); + match capacity_reservation { + Ok(capacity_reservation) => { + if let Some(current_route) = view + .master_kv_router() + .inner() + .kv_routes + .get(&key) + .map(|route| route.clone()) + { + if current_route.put_id == inflight_info.put_id { + route_lease_id = current_route.lease_id; + let mut replicas = current_route.nodes_replicas.write(); + if let Some(replica) = replicas.get_mut(&req_node_id) { + local_index_published = !replica.tomb_tag.is_tomb() + && replica + .tomb_tag + .same_generation(&inflight_info.target_tomb_tag) + && matches!( + &replica.backing, + super::KvReplicaBacking::Allocation(allocation) + if matches!( + &inflight_info.target, + InflightGetTarget::Allocation(target) + if Arc::ptr_eq(allocation, target) + ) + ); + if local_index_published { + replica.owner_local_indexed = true; + replica.capacity_reservation = capacity_reservation; + } + } + } + } + if local_index_published { + let old_ring_b_desc = super::NodeValueReplicaDesc { + weight_bytes: u32::try_from(target_cap).unwrap_or(u32::MAX), + put_id: inflight_info.put_id, + }; + let _ = view + .master_kv_router() + .remove_node_cache_entry_exact( + req_node_id.as_ref(), + &key, + &old_ring_b_desc, + ) + .await; + let event = RoutePublishEvent::replica_append( + key.clone(), + inflight_info.put_id, + route_lease_id, + req_node_id.clone(), + target_cap, + ); + if let Some(events) = deferred_route_events.as_deref_mut() { + events.push(event); + } else { + apply_post_route_maintenance_batch(&view, vec![event]).await; } } } + Err(err) => tracing::warn!( + "reused Get allocation could not reserve owner-indexed capacity; keeping temporary: get_id={} key={} owner={} err={}", + get_id, + key, + req_node_id, + err, + ), } if !local_index_published { tracing::warn!( @@ -534,9 +971,78 @@ pub async fn handle_get_done( ); allocation_mode = GetAllocationMode::Temporary; } + } else if allocation_mode == GetAllocationMode::LocalCommittedSlot { + let slot = match &inflight_info.target { + InflightGetTarget::PreparedLocalReserveSlot(slot) => slot.clone(), + InflightGetTarget::Allocation(_) => { + unreachable!("local committed-slot Get mode must use a prepared slot") + } + }; + let mut published = false; + let mut route_publish_event = None; + if let Some(current_route) = view.master_kv_router().inner().kv_routes.get(&key) { + if current_route.put_id == inflight_info.put_id { + let replica = KvRouteInfo { + node_id: req_node_id.clone(), + backing: super::KvReplicaBacking::CommittedSlot(slot), + owner_local_indexed: true, + get_durable_reservation: None, + capacity_reservation: None, + tomb_tag: inflight_info.target_tomb_tag.clone(), + }; + if publish_route_replica_tomb_fenced( + ¤t_route, + req_node_id.clone(), + replica, + ) { + published = true; + route_publish_event = Some(RoutePublishEvent::replica_append( + key.clone(), + inflight_info.put_id, + current_route.lease_id, + req_node_id.clone(), + target_cap, + )); + } + } + } + if !published { + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::Unknown { + detail: format!( + "prepared local-reserve Get target could not publish current route: get_id={} key={} put_id=({},{}) owner={}", + get_id, key, inflight_info.put_id.0, inflight_info.put_id.1, req_node_id + ), + }); + let terminal: GetDoneResp = + crate::rpcresp_kvresult_convert::FromError::from_error(&err); + let completed = CompletedGetInfo { + req_node_id: req_node_id.clone(), + response: terminal.clone(), + }; + if let Some(terminals) = deferred_terminals.as_deref_mut() { + terminals.push((get_id, completed)); + } else { + view.master_kv_router() + .inner() + .completed_gets + .insert(get_id, completed) + .await; + } + return MsgPack { + serialize_part: terminal, + raw_bytes: Vec::new(), + }; + } + if let Some(event) = route_publish_event { + if let Some(events) = deferred_route_events.as_deref_mut() { + events.push(event); + } else { + apply_post_route_maintenance_batch(&view, vec![event]).await; + } + } } - tracing::info!( + tracing::debug!( "Completed get operation with get_id: {}, assigned holder_id: {}", get_id, holder_id @@ -549,19 +1055,58 @@ pub async fn handle_get_done( GetAllocationMode::Temporary => "temporary", GetAllocationMode::ReuseReplica => "reuse_replica", GetAllocationMode::DurableReplica => "durable_replica", + GetAllocationMode::LocalCommittedSlot => "local_committed_slot", }); + let terminal = GetDoneResp { + holder_id, + allocation_mode, + error_code: msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + }; + let completed = CompletedGetInfo { + req_node_id: req_node_id.clone(), + response: terminal.clone(), + }; + if let Some(terminals) = deferred_terminals.as_deref_mut() { + terminals.push((get_id, completed)); + } else { + view.master_kv_router() + .inner() + .completed_gets + .insert(get_id, completed) + .await; + } MsgPack { - serialize_part: GetDoneResp { - holder_id, - allocation_mode, - error_code: msg_and_error::OK, - error_json: String::new(), - server_process_us: 0, - }, + serialize_part: terminal, raw_bytes: Vec::new(), } } else { + if let Some(completed) = view + .master_kv_router() + .inner() + .completed_gets + .get(&get_id) + .await + { + if completed.req_node_id != req_node_id { + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { + detail: format!( + "GetDone requester mismatch after completion: get_id={} expected={} got={}", + get_id, completed.req_node_id, req_node_id + ), + }); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), + raw_bytes: Vec::new(), + }; + } + return MsgPack { + serialize_part: completed.response, + raw_bytes: Vec::new(), + }; + } tracing::warn!( "Get operation with get_id {} not found for completion", get_id @@ -583,6 +1128,20 @@ pub async fn handle_get_done( } } +pub async fn handle_get_done( + view: MasterKvRouterView, + req: MsgPack, + req_node_id: NodeID, +) -> MsgPack { + let done_lock = view + .master_kv_router() + .inner() + .get_done_locks + .get_lock(req.serialize_part.get_id); + let _done_guard = done_lock.lock().await; + handle_get_done_locked(view, req, req_node_id, None, None).await +} + // --- MemHolder Handler Functions --- // pub async fn handle_mem_holder_keep_alive( @@ -757,15 +1316,12 @@ pub async fn handle_batch_is_exist( let mut exists_list = Vec::with_capacity(req.serialize_part.keys.len()); - { - let _guard = view.master_kv_router().inner().route_lifetime_lock.lock(); - for key in &req.serialize_part.keys { - if let Some(one_kv_nodes_routes) = view.master_kv_router().inner().kv_routes.get(key) { - let exists = one_kv_routes_has_live_replica(&one_kv_nodes_routes); - exists_list.push(exists); - } else { - exists_list.push(false); - } + for key in &req.serialize_part.keys { + if let Some(one_kv_nodes_routes) = view.master_kv_router().inner().kv_routes.get(key) { + let exists = one_kv_routes_has_live_replica(&one_kv_nodes_routes); + exists_list.push(exists); + } else { + exists_list.push(false); } } @@ -784,12 +1340,43 @@ pub async fn handle_batch_get_start( req: MsgPack, req_node_id: NodeID, ) -> MsgPack { - let mut items = Vec::with_capacity(req.serialize_part.keys.len()); - for key in req.serialize_part.keys { + let BatchGetStartReq { + keys, + prepared_targets, + } = req.serialize_part; + if !prepared_targets.is_empty() && prepared_targets.len() != keys.len() { + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { + detail: format!( + "batch_get_start prepared target length mismatch: keys={} targets={}", + keys.len(), + prepared_targets.len() + ), + }); + let error: GetStartResp = crate::rpcresp_kvresult_convert::FromError::from_error(&err); + return MsgPack { + serialize_part: BatchGetStartResp { + items: Vec::new(), + error_code: error.error_code, + error_json: error.error_json, + server_process_us: 0, + }, + raw_bytes: Vec::new(), + }; + } + let prepared_targets = if prepared_targets.is_empty() { + vec![None; keys.len()] + } else { + prepared_targets + }; + let mut items = Vec::with_capacity(keys.len()); + for (key, prepared_target) in keys.into_iter().zip(prepared_targets) { let (_get_id, resp) = handle_get_start( view.clone(), MsgPack { - serialize_part: GetStartReq { key }, + serialize_part: GetStartReq { + key, + prepared_target, + }, raw_bytes: Vec::new(), }, req_node_id.clone(), @@ -805,6 +1392,8 @@ pub async fn handle_batch_get_start( target_base_addr: part.target_base_addr, src_base_addr: part.src_base_addr, len: part.len, + prepared_target: part.prepared_target, + atomic_group: part.atomic_group, error_code: part.error_code, error_json: part.error_json, }); @@ -823,6 +1412,7 @@ pub async fn handle_batch_get_start( pub async fn handle_batch_get_revoke( view: MasterKvRouterView, req: MsgPack, + req_node_id: NodeID, ) -> MsgPack { let mut items = Vec::with_capacity(req.serialize_part.get_ids.len()); for get_id in req.serialize_part.get_ids { @@ -832,6 +1422,7 @@ pub async fn handle_batch_get_revoke( serialize_part: GetRevokeReq { get_id }, raw_bytes: Vec::new(), }, + req_node_id.clone(), ) .await; let part = resp.serialize_part; @@ -854,18 +1445,50 @@ pub async fn handle_batch_get_revoke( pub async fn handle_batch_get_done( view: MasterKvRouterView, req: MsgPack, + req_node_id: NodeID, ) -> MsgPack { - let mut items = Vec::with_capacity(req.serialize_part.get_ids.len()); - for get_id in req.serialize_part.get_ids { - let resp = handle_get_done( - view.clone(), - MsgPack { - serialize_part: GetDoneReq { get_id }, - raw_bytes: Vec::new(), - }, - ) - .await; - let part = resp.serialize_part; + let started_at = Instant::now(); + let get_ids = req.serialize_part.get_ids; + + // Hold every per-get terminal lock until the combined route-maintenance + // batch and idempotency records are durable. Sorting gives overlapping + // retries one global acquisition order and avoids lock cycles. + let mut unique_get_ids = get_ids.clone(); + unique_get_ids.sort_unstable(); + unique_get_ids.dedup(); + let mut _done_guards = Vec::with_capacity(unique_get_ids.len()); + for get_id in unique_get_ids { + let lock = view + .master_kv_router() + .inner() + .get_done_locks + .get_lock(get_id); + _done_guards.push(lock.lock_owned().await); + } + + let mut items = Vec::with_capacity(get_ids.len()); + let mut route_events = Vec::new(); + let mut deferred_terminals = Vec::new(); + let mut response_by_get_id = HashMap::::new(); + for get_id in get_ids { + let part = if let Some(part) = response_by_get_id.get(&get_id) { + part.clone() + } else { + let part = handle_get_done_locked( + view.clone(), + MsgPack { + serialize_part: GetDoneReq { get_id }, + raw_bytes: Vec::new(), + }, + req_node_id.clone(), + Some(&mut route_events), + Some(&mut deferred_terminals), + ) + .await + .serialize_part; + response_by_get_id.insert(get_id, part.clone()); + part + }; items.push(BatchGetDoneItemResp { get_id, holder_id: part.holder_id, @@ -874,6 +1497,33 @@ pub async fn handle_batch_get_done( error_json: part.error_json, }); } + + let route_event_count = route_events.len(); + let maintenance_started_at = Instant::now(); + if !route_events.is_empty() { + // One Moka capacity decision for the entire Done RPC replaces the old + // per-key full-LRU scan while preserving the rule that no success ACK + // is visible before every route is admitted to resident policy state. + apply_post_route_maintenance_batch(&view, route_events).await; + } + let maintenance_elapsed = maintenance_started_at.elapsed(); + for (get_id, completed) in deferred_terminals { + view.master_kv_router() + .inner() + .completed_gets + .insert(get_id, completed) + .await; + } + let elapsed = started_at.elapsed(); + if elapsed.as_millis() >= 100 { + tracing::warn!( + "slow BatchGetDone convergence: items={} route_events={} maintenance_ms={} total_ms={}", + items.len(), + route_event_count, + maintenance_elapsed.as_millis(), + elapsed.as_millis() + ); + } MsgPack { serialize_part: BatchGetDoneResp { items, diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs index c0af49e..ccba45e 100644 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs @@ -21,24 +21,26 @@ use self::{ }, msg_pack::{ BatchDeleteAckReq, BatchDeleteClientKvMetaCacheReq, BatchEnqueueReplicaTaskReq, - BatchGetDoneReq, BatchGetRevokeReq, BatchGetStartReq, BatchIsExistReq, - BatchOwnerReclaimReq, BatchPreparePutKeysReq, BatchPutDoneReq, BatchPutRevokeReq, - BatchPutStartReq, BatchReleasePutKeyReservationsReq, CountPrefixReq, CountPrefixResp, - DeleteAckReq, DeleteReq, GetAllocationMode, GetDoneReq, GetMasterOnlyMetricPartReq, - GetMasterOnlyMetricPartResp, GetMetaReq, GetRevokeReq, GetStartReq, GroupedBatchPutDoneReq, - MemHolderKeepAliveReq, MemHolderReleaseReq, OwnerReclaimBacking, OwnerReclaimItem, + BatchEvictOwnerSourceReq, BatchGetDoneReq, BatchGetRevokeReq, BatchGetStartReq, + BatchIsExistReq, BatchOwnerReclaimReq, BatchPreparePutKeysReq, BatchPutAppendDoneReq, + BatchPutAppendStartReq, BatchPutDoneReq, BatchPutRevokeReq, BatchPutStartReq, + BatchReleasePutKeyReservationsReq, CountPrefixReq, CountPrefixResp, DeleteAckReq, + DeleteReq, GetAllocationMode, GetDoneReq, GetDoneResp, GetMetaReq, GetRevokeReq, + GetStartReq, GroupedBatchPutDoneReq, OwnerReclaimBacking, OwnerReclaimItem, OwnerReclaimReason, PutAppendDoneReq, PutAppendRevokeReq, PutAppendStartReq, PutAtomicGroup, PutDoneReq, PutRevokeReq, PutStartReq, ReleaseLocalGrantReq, ReserveLocalGrantReq, }, placement::{PlacementPolicy, build_placement_policy}, put::{ - handle_batch_prepare_put_keys, handle_batch_put_done, handle_batch_put_revoke, - handle_batch_put_start, handle_batch_release_put_key_reservations, - handle_grouped_batch_put_done, handle_put_append_done, handle_put_append_revoke, - handle_put_append_start, handle_put_done, handle_put_revoke, handle_put_start, - handle_release_local_grant, handle_reserve_local_grant, + handle_batch_prepare_put_keys, handle_batch_put_append_done, handle_batch_put_append_start, + handle_batch_put_done, handle_batch_put_revoke, handle_batch_put_start, + handle_batch_release_put_key_reservations, handle_grouped_batch_put_done, + handle_put_append_done, handle_put_append_revoke, handle_put_append_start, handle_put_done, + handle_put_revoke, handle_put_start, handle_release_local_grant, + handle_reserve_local_grant, }, + reclaim::handle_batch_evict_owner_source, }; use crate::ClientKvApiAccessTrait; use crate::client_kv_api::ClientKvApi; @@ -53,31 +55,26 @@ use crate::master_seg_manager::MasterSegManager; use crate::master_seg_manager::MasterSegManagerAccessTrait; use crate::master_seg_manager::NodeTombTag; use crate::master_seg_manager::one_seg_allocator::Allocation; -use crate::memholder::{ - EnsureMemholderMgmtDeleteHandle, MasterOwnerMemMgr, MemholderManagerTrait, NodeHolderKey, -}; +use crate::memholder::{EnsureMemholderMgmtDeleteHandle, MasterOwnerMemMgr, MemholderManagerTrait}; use crate::metric_reporter::{MetricReporter, MetricReporterAccessTrait}; use crate::p2p::msg_pack::{MsgPack, RPCCaller, RPCHandler}; use crate::p2p::p2p_module::{P2pModule, P2pModuleAccessTrait}; -use crate::rpcresp_kvresult_convert; use crate::rpcresp_kvresult_convert::msg_and_error::{KvError, OK}; use fluxon_framework::{LogicalModule, define_module}; -use fluxon_framework_compiled::upgrade_view_guard::UpgradeViewGuard; use fluxon_util::map_lock::AMapLock; use async_trait::async_trait; use chrono::Utc; -use dashmap::DashMap; -use limit_thirdparty::tokio::sync::{ARwLock, abroadcast}; +use dashmap::{DashMap, DashSet}; +use limit_thirdparty::tokio::sync::ARwLock; use limit_thirdparty::tokio::{self, sync::ampsc}; use moka::notification::RemovalCause; use parking_lot::Mutex; use parking_lot::RwLock; -use std::borrow::Cow; +use std::collections::HashMap; use std::collections::HashSet; -use std::collections::{HashMap, VecDeque}; -use std::sync::Arc; use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering}; +use std::sync::{Arc, Weak}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use tracing::{debug, error, info, warn}; @@ -85,7 +82,6 @@ const MAX_GET_DURABLE_REPLICA_SLOTS: u32 = 2; const PLACEMENT_REPORT_INTERVAL_SECS: u64 = 10; const INFLIGHT_PUT_TTL_SECONDS: u64 = 60; const INFLIGHT_PUT_TTL_SECONDS_SKIP_PUT_END_COMMIT: u64 = 5; -const EVICTION_RECLAIM_QUEUE_CAPACITY: usize = 4096; const POST_ROUTE_MAINTENANCE_QUEUE_CAPACITY: usize = 512; const TIER1_WRITEBACK_QUEUE_CAPACITY: usize = 4096; @@ -109,26 +105,39 @@ fn subtract_pending_eviction_weight( }); } -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -enum UnrecoverableCacheEvictionContext { - NormalCapacity, - OwnerLocalReserveNoSpace, +fn try_install_eviction_reclaim_identities( + inflight: &DashSet, + identities: Vec, +) -> bool { + let mut installed = Vec::with_capacity(identities.len()); + for identity in identities { + if inflight.insert(identity.clone()) { + installed.push(identity); + } else { + for identity in installed { + assert!(inflight.remove(&identity).is_some()); + } + return false; + } + } + true } -fn allow_unrecoverable_cache_eviction( - owner_is_remote_only: bool, - has_ready_remote_only_owner: bool, - context: UnrecoverableCacheEvictionContext, -) -> bool { - // A normal active-tier eviction must preserve the remote copy whenever a remote-only tier is - // available. Physical local-reserve exhaustion is the liveness boundary: if that remote tier - // has filled and no recoverable active-tier entry remains, refusing to evict the last cached - // copy prevents the owner from accepting any subsequent write-back. The existing three-phase - // owner reclaim transaction removes the route and slot atomically, so dropping that cold cache - // entry is safe and a future lookup simply recomputes it. - context == UnrecoverableCacheEvictionContext::OwnerLocalReserveNoSpace - || owner_is_remote_only - || !has_ready_remote_only_owner +fn classify_existing_eviction_reclaim( + inflight: &DashSet, + identities: &[reclaim::EvictionReclaimIdentity], +) -> reclaim::EnqueueEvictionReclaimResult { + let inflight_count = identities + .iter() + .filter(|identity| inflight.contains(identity)) + .count(); + if inflight_count == identities.len() { + reclaim::EnqueueEvictionReclaimResult::AlreadyInProgress + } else if inflight_count == 0 { + reclaim::EnqueueEvictionReclaimResult::NotInProgress + } else { + reclaim::EnqueueEvictionReclaimResult::PartialOverlap + } } #[derive(Clone, Copy, Debug)] @@ -139,21 +148,45 @@ pub enum PutPlacementMode { #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum ReservedCapacityReason { + LocalReserveGrant, + OwnerIndexedAllocation, LeaseBoundKv, } -#[derive(Debug, Default)] +#[derive(Debug)] pub struct NodeCacheReservedCapacity { + /// Exact node registration generation owning these counters. + generation: NodeTombTag, pub total_bytes: AtomicU64, + pub local_reserve_grant_bytes: AtomicU64, + pub owner_indexed_allocation_bytes: AtomicU64, pub lease_bound_kv_bytes: AtomicU64, } impl NodeCacheReservedCapacity { + fn new(generation: NodeTombTag) -> Self { + Self { + generation, + total_bytes: AtomicU64::new(0), + local_reserve_grant_bytes: AtomicU64::new(0), + owner_indexed_allocation_bytes: AtomicU64::new(0), + lease_bound_kv_bytes: AtomicU64::new(0), + } + } + fn apply_delta(&self, reason: ReservedCapacityReason, delta_bytes: i64) { if delta_bytes >= 0 { let delta = delta_bytes as u64; self.total_bytes.fetch_add(delta, Ordering::Relaxed); match reason { + ReservedCapacityReason::LocalReserveGrant => { + self.local_reserve_grant_bytes + .fetch_add(delta, Ordering::Relaxed); + } + ReservedCapacityReason::OwnerIndexedAllocation => { + self.owner_indexed_allocation_bytes + .fetch_add(delta, Ordering::Relaxed); + } ReservedCapacityReason::LeaseBoundKv => { self.lease_bound_kv_bytes .fetch_add(delta, Ordering::Relaxed); @@ -163,6 +196,14 @@ impl NodeCacheReservedCapacity { let delta = (-delta_bytes) as u64; self.total_bytes.fetch_sub(delta, Ordering::Relaxed); match reason { + ReservedCapacityReason::LocalReserveGrant => { + self.local_reserve_grant_bytes + .fetch_sub(delta, Ordering::Relaxed); + } + ReservedCapacityReason::OwnerIndexedAllocation => { + self.owner_indexed_allocation_bytes + .fetch_sub(delta, Ordering::Relaxed); + } ReservedCapacityReason::LeaseBoundKv => { self.lease_bound_kv_bytes .fetch_sub(delta, Ordering::Relaxed); @@ -176,6 +217,57 @@ impl NodeCacheReservedCapacity { } } +/// Version-scoped reservation that reduces the usable resident-cache capacity +/// while a lease-bound route is alive. The token owns the exact counter Arc; +/// dropping an old Allocation/route can therefore never decrement a newly +/// reconnected node's counters merely because it reused the same node id. +pub struct NodeCacheCapacityReservation { + view: MasterKvRouterView, + node_id: NodeIDString, + generation: NodeTombTag, + reserved_capacity: Arc, + reason: ReservedCapacityReason, + bytes: u64, + released: AtomicBool, +} + +impl std::fmt::Debug for NodeCacheCapacityReservation { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("NodeCacheCapacityReservation") + .field("node_id", &self.node_id) + .field("bytes", &self.bytes) + .field("released", &self.released.load(Ordering::Acquire)) + .finish() + } +} + +impl Drop for NodeCacheCapacityReservation { + fn drop(&mut self) { + if self.released.swap(true, Ordering::AcqRel) { + return; + } + let Some(_view_guard) = self.view.try_upgrade() else { + return; + }; + if let Err(err) = self + .view + .master_kv_router() + .adjust_node_cache_reserved_capacity_identity( + &self.node_id, + &self.generation, + &self.reserved_capacity, + self.reason, + -(self.bytes as i64), + ) + { + warn!( + "failed to release generation-scoped cache reservation: node={} bytes={} err={}", + self.node_id, self.bytes, err + ); + } + } +} + #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct RequesterTargetPair { requester_node_id: NodeIDString, @@ -198,7 +290,6 @@ pub struct ReplicaCacheNodeObserveSnapshot { pub writeback_tier1_owner_accepted: u64, pub writeback_tier1_failed: u64, pub reclaim_master_activity_deferred: u64, - pub reclaim_master_get_holder_observed: u64, pub reclaim_owner_holder_deferred: u64, pub reclaim_owner_other_deferred: u64, pub reclaim_route_changed: u64, @@ -206,21 +297,18 @@ pub struct ReplicaCacheNodeObserveSnapshot { pub reclaim_retry_completed: u64, pub reclaim_retry_restored: u64, pub reclaim_completed: u64, - pub owner_hot_demotion_attempts: u64, - pub owner_hot_demotion_cohorts: u64, - pub owner_hot_demotion_selected_bytes: u64, - pub owner_hot_demotion_precheck_rejected: u64, - pub owner_hot_demotion_partial_mismatch: u64, - pub recoverable_first_requested_bytes: u64, - pub recoverable_first_selected_bytes: u64, - pub recoverable_first_shortfall_bytes: u64, - pub recoverable_first_eligible_checks: u64, - pub recoverable_first_route_absent_checks: u64, - pub recoverable_first_version_changed_checks: u64, - pub recoverable_first_route_ineligible_checks: u64, - pub recoverable_first_cpu_route_absent_checks: u64, - pub recoverable_first_atomic_group_incomplete_checks: u64, - pub recoverable_first_tp_cohort_incomplete_checks: u64, + pub source_evict_rpc_requests: u64, + pub source_evict_cohorts: u64, + pub source_evict_requested_bytes: u64, + pub source_evict_accepted: u64, + pub source_evict_in_progress: u64, + pub source_evict_completed: u64, + pub source_evict_retryable_busy: u64, + pub source_evict_stale: u64, + pub source_evict_rejected: u64, + pub capacity_eviction_non_ring_b_entry_total: u64, + pub capacity_eviction_hit_committed_slot: u64, + pub eviction_reclaim_deduplicated: u64, } #[derive(Clone, Debug, Default)] @@ -267,6 +355,8 @@ pub enum InflightPutAllocation { #[derive(Clone)] pub struct InflightPutCommitInfo { pub node_id: NodeID, + /// Exact target registration generation captured while the allocation was current. + pub target_tomb_tag: NodeTombTag, pub src_target_allocation: Arc>>, pub replica_target: Option, } @@ -284,11 +374,12 @@ pub struct InflightPutInfo { #[derive(Clone)] pub struct InflightReplicaTaskInfo { pub node_id: NodeID, + /// Exact target registration generation that owns `target_allocation`. + pub target_tomb_tag: NodeTombTag, pub source_node_id: NodeID, pub key: String, pub put_id: PutIDForAKey, pub target_allocation: Arc>>, - pub demote_source_on_remote_complete: bool, /// Protect the source-owner copy only after this inclusive replica has been /// published successfully. Backend-admitted replicas set this bit; tiered /// write-back and owner-hot exclusive demotion deliberately do not. @@ -304,17 +395,57 @@ pub struct InflightGetInfo { pub key: String, pub req_node_id: NodeID, pub len: u64, - pub allocation: Arc, + pub target: InflightGetTarget, + /// Exact requester registration generation that owns `target`. + pub target_tomb_tag: NodeTombTag, pub route: Arc, pub allocation_mode: GetAllocationMode, + pub durable_reservation: Option>, pub(crate) _activity_lease: Arc, + /// Requester-scoped guard for prepared local-reserve Gets. Different GPU + /// owners may fetch the same key concurrently, but one owner must never + /// materialize two candidate committed slots for the same key. + pub(crate) _prepared_requester_lease: Option>, +} + +#[derive(Clone)] +pub struct CompletedGetInfo { + pub req_node_id: NodeID, + pub response: GetDoneResp, +} + +#[derive(Clone, Debug)] +pub enum InflightGetTarget { + Allocation(Arc), + PreparedLocalReserveSlot(CommittedSlotReplica), +} + +impl InflightGetTarget { + pub fn abs_addr(&self) -> u64 { + match self { + Self::Allocation(allocation) => allocation.base_addr() + allocation.addr(), + Self::PreparedLocalReserveSlot(slot) => slot.addr, + } + } + + pub fn base_addr(&self) -> u64 { + match self { + Self::Allocation(allocation) => allocation.base_addr(), + Self::PreparedLocalReserveSlot(slot) => slot.base_addr, + } + } + + pub fn capacity(&self) -> u64 { + match self { + Self::Allocation(allocation) => allocation.capcity(), + Self::PreparedLocalReserveSlot(slot) => slot.slot_size, + } + } } impl InflightGetInfo { pub fn release_durable_slot_if_needed(&self) { - if self.allocation_mode == GetAllocationMode::DurableReplica { - self.route.release_get_durable_slot(); - } + // Durable-slot capacity is returned by the reservation token's Drop. } } @@ -329,7 +460,11 @@ pub struct OwnerHoldingGetInfo { pub struct LocalReserveGrantInfo { pub owner_node_id: NodeID, + /// Exact owner registration generation that owns the grant allocation. + pub tomb_tag: NodeTombTag, pub allocation: Allocation, + /// Excludes this whole grant from the master unindexed-Allocation domain. + pub capacity_reservation: Option>, } pub struct PreparedPutKeyReservationInfo { @@ -341,7 +476,6 @@ pub struct PreparedPutKeyReservationInfo { #[derive(Default)] pub(crate) struct EvictionReclaimCounters { pub master_activity_deferred: AtomicU64, - pub master_get_holder_observed: AtomicU64, pub owner_holder_deferred: AtomicU64, pub owner_other_deferred: AtomicU64, pub route_changed: AtomicU64, @@ -349,21 +483,24 @@ pub(crate) struct EvictionReclaimCounters { pub retry_completed: AtomicU64, pub retry_restored: AtomicU64, pub completed: AtomicU64, - pub owner_hot_demotion_attempts: AtomicU64, - pub owner_hot_demotion_cohorts: AtomicU64, - pub owner_hot_demotion_selected_bytes: AtomicU64, - pub owner_hot_demotion_precheck_rejected: AtomicU64, - pub owner_hot_demotion_partial_mismatch: AtomicU64, - pub recoverable_first_requested_bytes: AtomicU64, - pub recoverable_first_selected_bytes: AtomicU64, - pub recoverable_first_shortfall_bytes: AtomicU64, - pub recoverable_first_eligible_checks: AtomicU64, - pub recoverable_first_route_absent_checks: AtomicU64, - pub recoverable_first_version_changed_checks: AtomicU64, - pub recoverable_first_route_ineligible_checks: AtomicU64, - pub recoverable_first_cpu_route_absent_checks: AtomicU64, - pub recoverable_first_atomic_group_incomplete_checks: AtomicU64, - pub recoverable_first_tp_cohort_incomplete_checks: AtomicU64, + pub source_evict_rpc_requests: AtomicU64, + pub source_evict_cohorts: AtomicU64, + pub source_evict_requested_bytes: AtomicU64, + pub source_evict_accepted: AtomicU64, + pub source_evict_in_progress: AtomicU64, + pub source_evict_completed: AtomicU64, + pub source_evict_retryable_busy: AtomicU64, + pub source_evict_stale: AtomicU64, + pub source_evict_rejected: AtomicU64, + /// A Size event from the ring-B controller resolved to any current route + /// outside `Allocation && !owner_local_indexed`. + pub capacity_eviction_non_ring_b_entry_total: AtomicU64, + /// More specific subset retained for diagnostics/backward-compatible + /// metrics: the non-ring-B route used a CommittedSlot backing. + pub capacity_eviction_hit_committed_slot: AtomicU64, + /// Duplicate listener/cohort events suppressed while the same physical + /// cache version already has an outstanding reclaim lifecycle. + pub eviction_reclaim_deduplicated: AtomicU64, } #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] @@ -423,6 +560,82 @@ pub(crate) struct MasterKeyActivityCompletionGuard { lease: Option>, } +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +struct PreparedGetRequesterKey { + key: String, + requester: NodeID, +} + +#[derive(Default)] +pub(crate) struct PreparedGetRequesterTable { + active: Mutex>, +} + +pub(crate) struct PreparedGetRequesterLease { + table: Arc, + identity: PreparedGetRequesterKey, + get_id: u64, + released: AtomicBool, +} + +impl PreparedGetRequesterTable { + fn reserve( + self: &Arc, + key: &str, + requester: &NodeID, + get_id: u64, + ) -> Option> { + let identity = PreparedGetRequesterKey { + key: key.to_string(), + requester: requester.clone(), + }; + let mut active = self.active.lock(); + if active.contains_key(&identity) { + return None; + } + active.insert(identity.clone(), get_id); + Some(Arc::new(PreparedGetRequesterLease { + table: self.clone(), + identity, + get_id, + released: AtomicBool::new(false), + })) + } + + #[cfg(test)] + fn active_get_id(&self, key: &str, requester: &NodeID) -> Option { + self.active + .lock() + .get(&PreparedGetRequesterKey { + key: key.to_string(), + requester: requester.clone(), + }) + .copied() + } +} + +impl PreparedGetRequesterLease { + pub(crate) fn release_now(&self) { + if self + .released + .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire) + .is_err() + { + return; + } + let mut active = self.table.active.lock(); + if active.get(&self.identity) == Some(&self.get_id) { + active.remove(&self.identity); + } + } +} + +impl Drop for PreparedGetRequesterLease { + fn drop(&mut self) { + self.release_now(); + } +} + impl MasterKeyActivityCompletionGuard { pub(crate) fn new(lease: Arc) -> Self { Self { lease: Some(lease) } @@ -640,6 +853,17 @@ impl KvReplicaBacking { Self::CommittedSlot(slot) => slot.len, } } + + /// Bytes owned by the physical backing. Capacity accounting must use + /// this value rather than the logical payload length: an Allocation owns + /// its allocator capacity and a committed local-reserve slot owns the + /// whole slot. + pub fn capacity_bytes(&self) -> u64 { + match self { + Self::Allocation(allocation) => allocation.capcity(), + Self::CommittedSlot(slot) => slot.slot_size, + } + } } #[derive(Clone, Debug)] @@ -650,9 +874,40 @@ pub struct KvRouteInfo { /// Replica-task and remote-put targets are raw master-owned allocations and have no /// owner-side key entry to fence during capacity eviction. pub owner_local_indexed: bool, + /// Present only for an allocation replica created by GetDone. The shared + /// token returns the per-key durable-replica budget when this route entry's + /// final clone is dropped. + pub get_durable_reservation: Option>, + /// Excludes a non-ring-B backing from the unindexed-Allocation budget and + /// is released with the exact route lifetime. + pub capacity_reservation: Option>, pub tomb_tag: NodeTombTag, } +pub struct GetDurableSlotReservation { + route: Weak, + released: AtomicBool, +} + +impl std::fmt::Debug for GetDurableSlotReservation { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("GetDurableSlotReservation") + .field("released", &self.released.load(Ordering::Acquire)) + .finish() + } +} + +impl Drop for GetDurableSlotReservation { + fn drop(&mut self) { + if self.released.swap(true, Ordering::AcqRel) { + return; + } + if let Some(route) = self.route.upgrade() { + route.release_get_durable_slot(); + } + } +} + #[derive(Debug)] pub struct OneKvNodesRoutes { /// the version id for a kv put operation @@ -705,7 +960,7 @@ impl OneKvNodesRoutes { return true; } - fn try_reserve_get_durable_slot(&self) -> bool { + fn try_reserve_get_durable_slot(self: &Arc) -> Option> { self.get_durable_slots_used .fetch_update(Ordering::AcqRel, Ordering::Acquire, |current| { if current < MAX_GET_DURABLE_REPLICA_SLOTS { @@ -714,7 +969,13 @@ impl OneKvNodesRoutes { None } }) - .is_ok() + .ok() + .map(|_| { + Arc::new(GetDurableSlotReservation { + route: Arc::downgrade(self), + released: AtomicBool::new(false), + }) + }) } fn release_get_durable_slot(&self) { @@ -726,40 +987,288 @@ impl OneKvNodesRoutes { } } -fn route_has_live_replica_on_node(route: &OneKvNodesRoutes, node_id: &str) -> bool { - route - .nodes_replicas - .read() - .iter() - .any(|(candidate, replica)| candidate.as_ref() == node_id && !replica.tomb_tag.is_tomb()) +/// Ring B contains exactly master-only, unindexed Allocation routes. Node +/// role is deliberately absent from this predicate: placement and capacity +/// ownership are orthogonal. +fn ring_b_route_replica_desc( + route: &OneKvNodesRoutes, + node_id: &str, +) -> Option { + if route.lease_id.is_some() { + return None; + } + let replicas = route.nodes_replicas.read(); + let replica = replicas.get(node_id)?; + if replica.tomb_tag.is_tomb() + || replica.owner_local_indexed + || !matches!(&replica.backing, KvReplicaBacking::Allocation(_)) + { + return None; + } + Some(NodeValueReplicaDesc { + weight_bytes: u32::try_from(replica.backing.capacity_bytes()).unwrap_or(u32::MAX), + put_id: route.put_id, + }) } -fn route_live_remote_cache_nodes( +/// True only while `tag` is the live registration generation currently bound to `node_id`. +/// Completion paths must validate their captured tag instead of borrowing the tag of a later +/// registration that happens to reuse the same node id. +pub(crate) fn node_generation_is_current_live( view: &MasterKvRouterView, + node_id: &NodeID, + tag: &NodeTombTag, +) -> bool { + !tag.is_tomb() + && view + .master_seg_manager() + .get_node_tomb_tag(node_id) + .is_some_and(|current| !current.is_tomb() && current.same_generation(tag)) +} + +/// Publish one replica under the route-local lock and close the MemberLeft snapshot race. +/// +/// There are only two possible linearizations: +/// - publication wins the final tag check, so a later MemberLeft snapshot observes the route; +/// - MemberLeft marks the shared tag first, so this function rolls back the exact generation +/// before releasing the route lock. +/// +/// A previous live generation is never overwritten on rollback. In normal operation such a +/// generation cannot coexist with `replica` (registration replacement tombs the old tag first), +/// but preserving it makes the identity rule explicit and keeps tests resistant to ABA setup. +pub(crate) fn publish_route_replica_tomb_fenced( route: &OneKvNodesRoutes, -) -> HashSet { - route - .nodes_replicas - .read() - .iter() - .filter_map(|(node_id, replica)| { - if replica.tomb_tag.is_tomb() { - return None; + node_id: NodeID, + replica: KvRouteInfo, +) -> bool { + let publish_tag = replica.tomb_tag.clone(); + if publish_tag.is_tomb() { + return false; + } + + let mut replicas = route.nodes_replicas.write(); + if publish_tag.is_tomb() { + return false; + } + // A completion pre-check is necessarily racy with another completion for + // the same requester. Never replace a live replica here: only a tombed + // generation may be superseded. + if replicas + .get(&node_id) + .is_some_and(|current| !current.tomb_tag.is_tomb()) + { + return false; + } + let previous = replicas.insert(node_id.clone(), replica); + + if publish_tag.is_tomb() { + let published_is_current = replicas.get(&node_id).is_some_and(|current| { + current.node_id == node_id && current.tomb_tag.same_generation(&publish_tag) + }); + if published_is_current { + replicas.remove(&node_id); + if let Some(previous) = previous.filter(|old| !old.tomb_tag.is_tomb()) { + replicas.insert(node_id, previous); } - let member = view - .cluster_manager() - .get_member_info_cached(node_id.as_ref()); - placement::member_matches_roles( - member.as_ref(), - &view - .master_kv_router() - .inner() - .replica_task_placement - .remote_only_node_roles, - ) - .then(|| node_id.as_ref().to_string()) + } + return false; + } + true +} + +/// Replace one key's primary route while closing the MemberLeft snapshot race. +/// +/// The DashMap entry guard is held through the final tomb check. Therefore a +/// MemberLeft cleanup that starts after a successful check must observe the new +/// route, while a MemberLeft that marks the generation first causes the exact +/// replacement to be rolled back. Restoring `previous` also protects a newer +/// key version from being lost when a stale completion races node departure. +pub(crate) fn publish_primary_route_tomb_fenced( + routes: &DashMap>, + key: &str, + new_route: Arc, + publish_tag: &NodeTombTag, +) -> Result>, ()> { + if publish_tag.is_tomb() { + return Err(()); + } + + let mut inserted = false; + let mut current = routes.entry(key.to_string()).or_insert_with(|| { + inserted = true; + new_route.clone() + }); + let previous = if inserted { + None + } else { + Some(std::mem::replace(&mut *current, new_route.clone())) + }; + + if publish_tag.is_tomb() { + if let Some(previous) = previous { + *current = previous; + } else { + // DashMap's vacant-entry guard cannot remove itself. Drop the + // shard guard first, then remove only our exact Arc. The route is + // tombed throughout this tiny window, so readers cannot use it. + drop(current); + routes.remove_if(key, |_, route| Arc::ptr_eq(route, &new_route)); + } + return Err(()); + } + + Ok(previous) +} + +fn member_left_can_forward_to_registration_actor(current_node_start_time: Option) -> bool { + // MemberLeft carries only a node id. If membership already exposes a live generation, + // forwarding the ambiguous old leave would cancel that generation's registration actor. + current_node_start_time.is_none() +} + +/// Remove one departed node generation from a single route. +/// +/// The route map and replica map deliberately use their normal fine-grained locking only: +/// MemberLeft is a cold path and must not introduce a process-wide lock around a full-table scan. +/// The tomb-tag identity fences a delayed cleanup from deleting a live replica published by a +/// reconnected generation that reused the same node id. +fn remove_departed_generation_from_route( + routes: &DashMap>, + key: &str, + route: &Arc, + node_id: &str, + departed_tag: &NodeTombTag, +) -> Option { + let became_empty = { + let mut replicas = route.nodes_replicas.write(); + let remove = replicas.get(node_id).is_some_and(|replica| { + replica.node_id.as_ref() == node_id + && replica.tomb_tag.is_tomb() + && replica.tomb_tag.same_generation(departed_tag) + }); + if !remove { + return None; + } + replicas.remove(node_id); + replicas.is_empty() + }; + + if !became_empty { + return None; + } + + routes + .remove_if(key, |_, current| { + // `Arc::ptr_eq` prevents an old cleanup from removing a replacement route (ABA). + // Recheck emptiness under the per-route read lock because another replica may have + // joined after the write lock above was released. + Arc::ptr_eq(current, route) && current.nodes_replicas.read().is_empty() + }) + .map(|(_, removed)| removed.put_id) +} + +const MEMBER_LEFT_ROUTE_CLEANUP_BATCH: usize = 512; + +async fn cleanup_departed_generation_routes( + view: MasterKvRouterView, + node_id: NodeIDString, + departed_tag: NodeTombTag, +) { + // Grants own master-side Allocation guards and therefore must be released + // for the exact departed generation as well. Collect ids without keeping + // DashMap guards across a removal or yield. + let departed_grant_ids: Vec = view + .master_kv_router() + .inner() + .local_reserve_grants + .iter() + .filter_map(|entry| { + (entry.value().owner_node_id.as_ref() == node_id.as_str() + && entry.value().tomb_tag.is_tomb() + && entry.value().tomb_tag.same_generation(&departed_tag)) + .then_some(*entry.key()) }) - .collect() + .collect(); + let mut removed_grants = 0usize; + for grant_id in departed_grant_ids { + if view + .master_kv_router() + .inner() + .local_reserve_grants + .remove_if(&grant_id, |_, grant| { + grant.owner_node_id.as_ref() == node_id.as_str() + && grant.tomb_tag.is_tomb() + && grant.tomb_tag.same_generation(&departed_tag) + }) + .is_some() + { + removed_grants = removed_grants.saturating_add(1); + } + } + + // Weak snapshots avoid pinning every route Allocation for the duration of a large scan. + // No DashMap guard or replica lock is held across an await. + let route_snapshot: Vec<(String, Weak)> = view + .master_kv_router() + .inner() + .kv_routes + .iter() + .map(|entry| (entry.key().clone(), Arc::downgrade(entry.value()))) + .collect(); + let mut removed_empty_routes = Vec::new(); + let mut removed_replicas = 0usize; + + for batch in route_snapshot.chunks(MEMBER_LEFT_ROUTE_CLEANUP_BATCH) { + for (key, weak_route) in batch { + let Some(route) = weak_route.upgrade() else { + continue; + }; + let had_departed_replica = route + .nodes_replicas + .read() + .get(node_id.as_str()) + .is_some_and(|replica| { + replica.node_id.as_ref() == node_id.as_str() + && replica.tomb_tag.is_tomb() + && replica.tomb_tag.same_generation(&departed_tag) + }); + if !had_departed_replica { + continue; + } + if let Some(put_id) = remove_departed_generation_from_route( + &view.master_kv_router().inner().kv_routes, + key, + &route, + node_id.as_str(), + &departed_tag, + ) { + removed_empty_routes.push((key.clone(), put_id)); + } + removed_replicas = removed_replicas.saturating_add(1); + } + tokio::task::yield_now().await; + } + + if view.master_kv_router().prefix_index_enabled() { + // Prefix cleanup is batched so one MemberLeft does not spawn one task or acquire one + // async write lock per key. + for batch in removed_empty_routes.chunks(MEMBER_LEFT_ROUTE_CLEANUP_BATCH) { + let mut tree = view.master_kv_router().inner().prefix_index.write().await; + for (key, put_id) in batch { + tree.remove(key, *put_id); + } + drop(tree); + tokio::task::yield_now().await; + } + } + + info!( + "MemberLeft route cleanup completed: node={} removed_grants={} removed_replicas={} removed_empty_routes={}", + node_id, + removed_grants, + removed_replicas, + removed_empty_routes.len() + ); } const MAX_INFERRED_TP_COHORT_SIZE: usize = 256; @@ -806,63 +1315,69 @@ pub(crate) fn infer_sglang_tp_key(key: &str) -> Option> { } #[derive(Clone, Copy, Debug, Eq, PartialEq)] -enum RecoverableReplicaStatus { - Recoverable, - RouteAbsent, - VersionChanged, - RouteIneligible, - CpuRouteAbsent, +enum CohortExpansionError { AtomicGroupIncomplete, TpCohortIncomplete, } -fn recoverable_cohort_weight( +fn take_exact_cache_entries( + cache: &moka::sync::SegmentedCache, expected_entries: &HashMap, - mut recoverable_status: F, -) -> Option -where - F: FnMut(&str, &NodeValueReplicaDesc) -> RecoverableReplicaStatus, -{ - let mut expected_weight = 0u64; - for (key, desc) in expected_entries { - if recoverable_status(key, desc) != RecoverableReplicaStatus::Recoverable { - return None; +) -> Option> { + let mut removed_entries = Vec::with_capacity(expected_entries.len()); + for (candidate_key, expected_desc) in expected_entries { + let result = cache + .entry(candidate_key.clone()) + .and_compute_with(|current| { + if current.as_ref().is_some_and(|entry| { + entry.value().put_id == expected_desc.put_id + && entry.value().weight_bytes == expected_desc.weight_bytes + }) { + moka::ops::compute::Op::Remove + } else { + moka::ops::compute::Op::Nop + } + }); + match result { + moka::ops::compute::CompResult::Removed(entry) => { + removed_entries.push((candidate_key.clone(), entry.into_value())); + } + _ => { + for (removed_key, removed_desc) in removed_entries { + cache.insert(removed_key, removed_desc); + } + return None; + } } - expected_weight = expected_weight.checked_add(u64::from(desc.weight_bytes))?; } - (expected_weight != 0).then_some(expected_weight) + Some(removed_entries) } -impl EvictionReclaimCounters { - fn record_recoverable_first_status(&self, status: RecoverableReplicaStatus) { - let counter = match status { - RecoverableReplicaStatus::Recoverable => &self.recoverable_first_eligible_checks, - RecoverableReplicaStatus::RouteAbsent => &self.recoverable_first_route_absent_checks, - RecoverableReplicaStatus::VersionChanged => { - &self.recoverable_first_version_changed_checks - } - RecoverableReplicaStatus::RouteIneligible => { - &self.recoverable_first_route_ineligible_checks - } - RecoverableReplicaStatus::CpuRouteAbsent => { - &self.recoverable_first_cpu_route_absent_checks - } - RecoverableReplicaStatus::AtomicGroupIncomplete => { - &self.recoverable_first_atomic_group_incomplete_checks - } - RecoverableReplicaStatus::TpCohortIncomplete => { - &self.recoverable_first_tp_cohort_incomplete_checks +fn remove_exact_cache_entry( + cache: &moka::sync::SegmentedCache, + key: &str, + expected_desc: &NodeValueReplicaDesc, +) -> bool { + matches!( + cache.entry(key.to_string()).and_compute_with(|current| { + if current.as_ref().is_some_and(|entry| { + entry.value().put_id == expected_desc.put_id + && entry.value().weight_bytes == expected_desc.weight_bytes + }) { + moka::ops::compute::Op::Remove + } else { + moka::ops::compute::Op::Nop } - }; - counter.fetch_add(1, Ordering::Relaxed); - } + }), + moka::ops::compute::CompResult::Removed(_) + ) } fn current_atomic_group_members( key: &str, route: &OneKvNodesRoutes, desc: &NodeValueReplicaDesc, -) -> Result, RecoverableReplicaStatus> { +) -> Result, CohortExpansionError> { let Some(group) = route.atomic_group.as_ref() else { return Ok(vec![msg_pack::PutAtomicGroupMember { key: key.to_string(), @@ -874,7 +1389,7 @@ fn current_atomic_group_members( .iter() .any(|member| member.key == key && member.put_id == desc.put_id) { - return Err(RecoverableReplicaStatus::AtomicGroupIncomplete); + return Err(CohortExpansionError::AtomicGroupIncomplete); } Ok(group.members.clone()) } @@ -883,7 +1398,7 @@ fn current_tp_cohort_keys( key: &str, route: &OneKvNodesRoutes, desc: &NodeValueReplicaDesc, -) -> Result, RecoverableReplicaStatus> { +) -> Result, CohortExpansionError> { let current_members = current_atomic_group_members(key, route, desc)?; let Some(key_tp) = infer_sglang_tp_key(key) else { return Ok(current_members @@ -901,10 +1416,10 @@ fn current_tp_cohort_keys( let mut logical_members = Vec::with_capacity(current_members.len()); for member in current_members { let Some(member_tp) = infer_sglang_tp_key(&member.key) else { - return Err(RecoverableReplicaStatus::TpCohortIncomplete); + return Err(CohortExpansionError::TpCohortIncomplete); }; if member_tp.rank != key_tp.rank || member_tp.size != key_tp.size { - return Err(RecoverableReplicaStatus::TpCohortIncomplete); + return Err(CohortExpansionError::TpCohortIncomplete); } logical_members.push(member_tp.logical_prefix.to_string()); } @@ -920,292 +1435,93 @@ fn current_tp_cohort_keys( Ok(cohort_keys) } -fn intersect_remote_nodes( - common_remote_nodes: &mut Option>, - mut member_remote_nodes: HashSet, - owner_node_id: &str, -) -> Result<(), RecoverableReplicaStatus> { - member_remote_nodes.remove(owner_node_id); - if member_remote_nodes.is_empty() { - return Err(RecoverableReplicaStatus::CpuRouteAbsent); - } - match common_remote_nodes.as_mut() { - Some(common) => common.retain(|node_id| member_remote_nodes.contains(node_id)), - None => *common_remote_nodes = Some(member_remote_nodes), - } - if common_remote_nodes.as_ref().is_some_and(HashSet::is_empty) { - return Err(RecoverableReplicaStatus::AtomicGroupIncomplete); - } - Ok(()) -} +#[cfg(test)] +mod tests { + use super::*; + use crate::cluster_manager::ClusterMember; + use std::collections::HashMap; -fn validate_recoverable_group( - owner_node_id: &str, - expected_keys: &[String], - expected_put_ids: Option<&[PutIDForAKey]>, - route_lookup: &dyn Fn(&str) -> Option>, - live_remote_nodes: &dyn Fn(&OneKvNodesRoutes) -> HashSet, -) -> Result, RecoverableReplicaStatus> { - if expected_put_ids.is_some_and(|put_ids| put_ids.len() != expected_keys.len()) { - return Err(RecoverableReplicaStatus::AtomicGroupIncomplete); - } - let Some(first_key) = expected_keys.first() else { - return Err(RecoverableReplicaStatus::AtomicGroupIncomplete); - }; - let Some(first_route) = route_lookup(first_key) else { - return Err(RecoverableReplicaStatus::RouteAbsent); - }; + #[test] + fn one_kv_nodes_routes_only_reserves_two_get_durable_slots() { + let routes = Arc::new(OneKvNodesRoutes { + put_id: (1, 0), + lease_id: None, + atomic_group: None, + nodes_replicas: RwLock::new(HashMap::new()), + get_durable_slots_used: AtomicU32::new(0), + }); - if expected_keys.len() == 1 { - if expected_put_ids.is_some_and(|put_ids| first_route.put_id != put_ids[0]) { - return Err(RecoverableReplicaStatus::VersionChanged); - } - if first_route.lease_id.is_some() || first_route.atomic_group.is_some() { - return Err(RecoverableReplicaStatus::AtomicGroupIncomplete); - } - let mut common_remote_nodes = None; - intersect_remote_nodes( - &mut common_remote_nodes, - live_remote_nodes(&first_route), - owner_node_id, - )?; - return common_remote_nodes.ok_or(RecoverableReplicaStatus::CpuRouteAbsent); - } - - let Some(group) = first_route.atomic_group.as_ref() else { - return Err(RecoverableReplicaStatus::AtomicGroupIncomplete); - }; - if group.members.len() != expected_keys.len() - || group - .members - .iter() - .zip(expected_keys) - .any(|(member, expected_key)| member.key != *expected_key) - || expected_put_ids.is_some_and(|put_ids| { - group - .members - .iter() - .zip(put_ids) - .any(|(member, expected_put_id)| member.put_id != *expected_put_id) - }) - { - return Err(RecoverableReplicaStatus::AtomicGroupIncomplete); - } - - let mut common_remote_nodes = None; - for member in &group.members { - let Some(member_route) = route_lookup(&member.key) else { - return Err(RecoverableReplicaStatus::RouteAbsent); - }; - if member_route.put_id != member.put_id - || member_route.lease_id.is_some() - || member_route.atomic_group.as_deref() != Some(group.as_ref()) - { - return Err(RecoverableReplicaStatus::AtomicGroupIncomplete); - } - intersect_remote_nodes( - &mut common_remote_nodes, - live_remote_nodes(&member_route), - owner_node_id, - )?; - } - common_remote_nodes.ok_or(RecoverableReplicaStatus::CpuRouteAbsent) -} - -fn validate_current_recoverable_group( - owner_node_id: &str, - route: &OneKvNodesRoutes, - current_members: &[msg_pack::PutAtomicGroupMember], - route_lookup: &dyn Fn(&str) -> Option>, - live_remote_nodes: &dyn Fn(&OneKvNodesRoutes) -> HashSet, -) -> Result, RecoverableReplicaStatus> { - if current_members.len() == 1 { - let mut common_remote_nodes = None; - intersect_remote_nodes( - &mut common_remote_nodes, - live_remote_nodes(route), - owner_node_id, - )?; - return common_remote_nodes.ok_or(RecoverableReplicaStatus::CpuRouteAbsent); - } - let current_keys = current_members - .iter() - .map(|member| member.key.clone()) - .collect::>(); - let current_put_ids = current_members - .iter() - .map(|member| member.put_id) - .collect::>(); - validate_recoverable_group( - owner_node_id, - ¤t_keys, - Some(¤t_put_ids), - route_lookup, - live_remote_nodes, - ) -} - -fn route_recoverable_replica_status_with( - owner_node_id: &str, - key: &str, - route: &OneKvNodesRoutes, - desc: &NodeValueReplicaDesc, - route_lookup: &dyn Fn(&str) -> Option>, - live_remote_nodes: &dyn Fn(&OneKvNodesRoutes) -> HashSet, -) -> RecoverableReplicaStatus { - if route.put_id != desc.put_id { - return RecoverableReplicaStatus::VersionChanged; - } - if route.lease_id.is_some() || !route_has_live_replica_on_node(route, owner_node_id) { - return RecoverableReplicaStatus::RouteIneligible; - } + let first = routes.try_reserve_get_durable_slot().unwrap(); + let second = routes.try_reserve_get_durable_slot().unwrap(); + assert!(routes.try_reserve_get_durable_slot().is_none()); - let current_members = match current_atomic_group_members(key, route, desc) { - Ok(members) => members, - Err(status) => return status, - }; - let Some(key_tp) = infer_sglang_tp_key(key) else { - return match validate_current_recoverable_group( - owner_node_id, - route, - ¤t_members, - route_lookup, - live_remote_nodes, - ) { - Ok(_) => RecoverableReplicaStatus::Recoverable, - Err(status) => status, - }; - }; - if key_tp.size == 1 { - return match validate_current_recoverable_group( - owner_node_id, - route, - ¤t_members, - route_lookup, - live_remote_nodes, - ) { - Ok(_) => RecoverableReplicaStatus::Recoverable, - Err(status) => status, - }; - } - - let mut logical_members = Vec::with_capacity(current_members.len()); - for member in ¤t_members { - let Some(member_tp) = infer_sglang_tp_key(&member.key) else { - return RecoverableReplicaStatus::TpCohortIncomplete; - }; - if member_tp.rank != key_tp.rank || member_tp.size != key_tp.size { - return RecoverableReplicaStatus::TpCohortIncomplete; - } - logical_members.push(member_tp.logical_prefix.to_string()); - } - - let mut cohort_remote_nodes: Option> = None; - for rank in 0..key_tp.size { - let peer_keys = logical_members - .iter() - .map(|logical_prefix| format!("{logical_prefix}_{rank}_{}", key_tp.size)) - .collect::>(); - let rank_result = if rank == key_tp.rank { - validate_current_recoverable_group( - owner_node_id, - route, - ¤t_members, - route_lookup, - live_remote_nodes, - ) - } else { - validate_recoverable_group( - owner_node_id, - &peer_keys, - None, - route_lookup, - live_remote_nodes, - ) - }; - let rank_remote_nodes = match rank_result { - Ok(nodes) => nodes, - Err(_) => return RecoverableReplicaStatus::TpCohortIncomplete, - }; - match cohort_remote_nodes.as_mut() { - Some(common) => common.retain(|node_id| rank_remote_nodes.contains(node_id)), - None => cohort_remote_nodes = Some(rank_remote_nodes), - } - if cohort_remote_nodes.as_ref().is_some_and(HashSet::is_empty) { - return RecoverableReplicaStatus::TpCohortIncomplete; - } + drop(first); + assert!(routes.try_reserve_get_durable_slot().is_some()); + drop(second); } - if cohort_remote_nodes.is_some_and(|nodes| !nodes.is_empty()) { - RecoverableReplicaStatus::Recoverable - } else { - RecoverableReplicaStatus::TpCohortIncomplete - } -} - -#[cfg(test)] -fn route_has_recoverable_replica_with( - owner_node_id: &str, - key: &str, - route: &OneKvNodesRoutes, - desc: &NodeValueReplicaDesc, - route_lookup: &dyn Fn(&str) -> Option>, - live_remote_nodes: &dyn Fn(&OneKvNodesRoutes) -> HashSet, -) -> bool { - route_recoverable_replica_status_with( - owner_node_id, - key, - route, - desc, - route_lookup, - live_remote_nodes, - ) == RecoverableReplicaStatus::Recoverable -} - -fn route_recoverable_replica_status( - view: &MasterKvRouterView, - owner_node_id: &str, - key: &str, - route: &OneKvNodesRoutes, - desc: &NodeValueReplicaDesc, -) -> RecoverableReplicaStatus { - route_recoverable_replica_status_with( - owner_node_id, - key, - route, - desc, - &|member_key| { - view.master_kv_router() - .inner() - .kv_routes - .get(member_key) - .map(|entry| entry.clone()) - }, - &|member_route| route_live_remote_cache_nodes(view, member_route), - ) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::cluster_manager::ClusterMember; - use std::collections::HashMap; #[test] - fn one_kv_nodes_routes_only_reserves_two_get_durable_slots() { - let routes = OneKvNodesRoutes { + fn durable_slot_token_returns_capacity_across_ten_fill_demote_cycles() { + let routes = Arc::new(OneKvNodesRoutes { put_id: (1, 0), lease_id: None, atomic_group: None, nodes_replicas: RwLock::new(HashMap::new()), get_durable_slots_used: AtomicU32::new(0), - }; + }); - assert!(routes.try_reserve_get_durable_slot()); - assert!(routes.try_reserve_get_durable_slot()); - assert!(!routes.try_reserve_get_durable_slot()); + for cycle in 0..10 { + let reservation = routes + .try_reserve_get_durable_slot() + .expect("each fill must reacquire durable capacity after demotion"); + assert_eq!(routes.get_durable_slots_used.load(Ordering::Acquire), 1); + let route_clone = reservation.clone(); + drop(reservation); + assert_eq!( + routes.get_durable_slots_used.load(Ordering::Acquire), + 1, + "route clone must retain the token during cycle {cycle}" + ); + drop(route_clone); + assert_eq!( + routes.get_durable_slots_used.load(Ordering::Acquire), + 0, + "demotion must return durable capacity during cycle {cycle}" + ); + } + } - routes.release_get_durable_slot(); - assert!(routes.try_reserve_get_durable_slot()); + #[test] + fn prepared_get_singleflight_is_same_owner_only_and_aba_safe() { + let table = Arc::new(PreparedGetRequesterTable::default()); + let gpu0: NodeID = "gpu-owner-0".to_string().into(); + let gpu1: NodeID = "gpu-owner-1".to_string().into(); + + let gpu0_first = table + .reserve("shared-key", &gpu0, 11) + .expect("first prepared Get on gpu0 must lead"); + assert!( + table.reserve("shared-key", &gpu0, 12).is_none(), + "same owner cannot materialize a second candidate slot" + ); + let gpu1_first = table + .reserve("shared-key", &gpu1, 13) + .expect("different requester owners remain parallel"); + assert_eq!(table.active_get_id("shared-key", &gpu0), Some(11)); + assert_eq!(table.active_get_id("shared-key", &gpu1), Some(13)); + + gpu0_first.release_now(); + let gpu0_second = table + .reserve("shared-key", &gpu0, 14) + .expect("released owner identity can be reused"); + // A delayed Drop/release of the old generation must not delete get 14. + gpu0_first.release_now(); + assert_eq!(table.active_get_id("shared-key", &gpu0), Some(14)); + + drop(gpu0_second); + drop(gpu1_first); + assert_eq!(table.active_get_id("shared-key", &gpu0), None); + assert_eq!(table.active_get_id("shared-key", &gpu1), None); } #[test] @@ -1220,7 +1536,7 @@ mod tests { slot_index: 17, slot_size: 8 * 1024 * 1024, }, - reason: OwnerReclaimReason::Reserve, + reason: OwnerReclaimReason::OwnerCapacityEviction, }; let get_lease = table @@ -1284,11 +1600,7 @@ mod tests { assert!(table.is_quiescent("retired-clone")); } - fn test_route_info(node_id: &str, tomb: bool) -> KvRouteInfo { - let tomb_tag = NodeTombTag::new(); - if tomb { - tomb_tag.set_tomb(); - } + fn test_route_info_with_tag(node_id: &str, tomb_tag: NodeTombTag) -> KvRouteInfo { KvRouteInfo { node_id: node_id.to_string().into(), backing: KvReplicaBacking::CommittedSlot(CommittedSlotReplica { @@ -1301,10 +1613,41 @@ mod tests { base_addr: 0, }), owner_local_indexed: true, + get_durable_reservation: None, + capacity_reservation: None, tomb_tag, } } + fn test_route_info(node_id: &str, tomb: bool) -> KvRouteInfo { + let tomb_tag = NodeTombTag::new(); + if tomb { + tomb_tag.set_tomb(); + } + test_route_info_with_tag(node_id, tomb_tag) + } + + fn test_allocation_route_info(node_id: &str, owner_local_indexed: bool) -> KvRouteInfo { + let allocator = Arc::new( + crate::master_seg_manager::one_seg_allocator::OneSegAllocator::new( + format!("{node_id}-segment"), + crate::master_seg_manager::msg_pack::SegmentDeviceDescription::Cpu, + 0, + 4096, + ) + .unwrap(), + ); + let allocation = allocator.allocate(1024).unwrap(); + KvRouteInfo { + node_id: node_id.to_string().into(), + backing: KvReplicaBacking::Allocation(Arc::new(allocation)), + owner_local_indexed, + get_durable_reservation: None, + capacity_reservation: None, + tomb_tag: NodeTombTag::new(), + } + } + fn test_route( put_id: PutIDForAKey, lease_id: Option, @@ -1326,123 +1669,279 @@ mod tests { } } - fn test_remote_nodes(route: &OneKvNodesRoutes) -> HashSet { - route - .nodes_replicas - .read() - .iter() - .filter_map(|(node_id, replica)| { - (!replica.tomb_tag.is_tomb() && node_id.as_ref().starts_with("cpu")) - .then(|| node_id.as_ref().to_string()) - }) - .collect() - } - #[test] - fn recoverable_route_requires_live_local_and_live_remote_cache_same_version() { - let desc = NodeValueReplicaDesc { - weight_bytes: 1024, - put_id: (7, 3), - }; - let no_lookup = |_key: &str| None; - let recoverable = |route: &OneKvNodesRoutes| { - route_has_recoverable_replica_with( - "gpu0", - "k", - route, - &desc, - &no_lookup, - &test_remote_nodes, - ) + fn ring_b_admission_depends_on_backing_and_local_index_not_node_role() { + let node: NodeID = "same-node".to_string().into(); + let make_route = |lease_id, replica| OneKvNodesRoutes { + put_id: (91, 3), + lease_id, + atomic_group: None, + nodes_replicas: RwLock::new(HashMap::from([(node.clone(), replica)])), + get_durable_slots_used: AtomicU32::new(0), }; - let cpu_copy = test_route((7, 3), None, vec![("gpu0", false), ("cpu0", false)]); - assert!(recoverable(&cpu_copy)); + let unindexed = make_route(None, test_allocation_route_info("same-node", false)); + let desc = ring_b_route_replica_desc(&unindexed, "same-node") + .expect("unindexed Allocation must enter ring B on any node role"); + assert_eq!(desc.put_id, (91, 3)); + assert_eq!(desc.weight_bytes, 4096); - let local_only = test_route((7, 3), None, vec![("gpu0", false)]); - assert!(!recoverable(&local_only)); + let indexed = make_route(None, test_allocation_route_info("same-node", true)); + assert!(ring_b_route_replica_desc(&indexed, "same-node").is_none()); - let gpu_copy = test_route((7, 3), None, vec![("gpu0", false), ("gpu1", false)]); - assert!(!recoverable(&gpu_copy)); + let leased = make_route(Some(7), test_allocation_route_info("same-node", false)); + assert!(ring_b_route_replica_desc(&leased, "same-node").is_none()); - let remote_tomb = test_route((7, 3), None, vec![("gpu0", false), ("cpu0", true)]); - assert!(!recoverable(&remote_tomb)); - - let local_tomb = test_route((7, 3), None, vec![("gpu0", true), ("cpu0", false)]); - assert!(!recoverable(&local_tomb)); + let mut committed = test_route_info("same-node", false); + committed.owner_local_indexed = false; + let committed = make_route(None, committed); + assert!(ring_b_route_replica_desc(&committed, "same-node").is_none()); + } - let stale = test_route((8, 0), None, vec![("gpu0", false), ("cpu0", false)]); - assert!(!recoverable(&stale)); + #[test] + fn member_left_cleanup_removes_only_the_exact_tomb_generation() { + let routes = DashMap::new(); + let departed_tag = NodeTombTag::new(); + departed_tag.set_tomb(); + let live_reconnect_tag = NodeTombTag::new(); + let newer_tomb_tag = NodeTombTag::new(); + newer_tomb_tag.set_tomb(); + + let departed_route = Arc::new(OneKvNodesRoutes { + put_id: (10, 0), + lease_id: None, + atomic_group: None, + nodes_replicas: RwLock::new(HashMap::from([( + "owner".to_string().into(), + test_route_info_with_tag("owner", departed_tag.clone()), + )])), + get_durable_slots_used: AtomicU32::new(0), + }); + let live_route = Arc::new(OneKvNodesRoutes { + put_id: (11, 0), + lease_id: None, + atomic_group: None, + nodes_replicas: RwLock::new(HashMap::from([( + "owner".to_string().into(), + test_route_info_with_tag("owner", live_reconnect_tag), + )])), + get_durable_slots_used: AtomicU32::new(0), + }); + let newer_tomb_route = Arc::new(OneKvNodesRoutes { + put_id: (12, 0), + lease_id: None, + atomic_group: None, + nodes_replicas: RwLock::new(HashMap::from([( + "owner".to_string().into(), + test_route_info_with_tag("owner", newer_tomb_tag), + )])), + get_durable_slots_used: AtomicU32::new(0), + }); + routes.insert("departed".to_string(), departed_route.clone()); + routes.insert("live".to_string(), live_route.clone()); + routes.insert("newer-tomb".to_string(), newer_tomb_route.clone()); - let leased = test_route((7, 3), Some(11), vec![("gpu0", false), ("cpu0", false)]); - assert!(!recoverable(&leased)); + assert_eq!( + remove_departed_generation_from_route( + &routes, + "departed", + &departed_route, + "owner", + &departed_tag, + ), + Some((10, 0)) + ); + assert!(routes.get("departed").is_none()); + assert_eq!( + remove_departed_generation_from_route( + &routes, + "live", + &live_route, + "owner", + &departed_tag, + ), + None + ); + assert!( + live_route + .nodes_replicas + .read() + .get("owner") + .is_some_and(|replica| !replica.tomb_tag.is_tomb()) + ); + assert_eq!( + remove_departed_generation_from_route( + &routes, + "newer-tomb", + &newer_tomb_route, + "owner", + &departed_tag, + ), + None + ); + assert!(newer_tomb_route.nodes_replicas.read().contains_key("owner")); } #[test] - fn recoverable_atomic_group_requires_one_common_remote_cache_owner() { - let group = Arc::new(PutAtomicGroup { - members: vec![ - msg_pack::PutAtomicGroupMember { - key: "k0".to_string(), - put_id: (7, 0), - }, - msg_pack::PutAtomicGroupMember { - key: "k1".to_string(), - put_id: (7, 1), - }, - ], + fn member_left_empty_route_removal_is_arc_identity_aba_safe() { + let routes = DashMap::new(); + let departed_tag = NodeTombTag::new(); + departed_tag.set_tomb(); + let old_route = Arc::new(OneKvNodesRoutes { + put_id: (20, 0), + lease_id: None, + atomic_group: None, + nodes_replicas: RwLock::new(HashMap::from([( + "owner".to_string().into(), + test_route_info_with_tag("owner", departed_tag.clone()), + )])), + get_durable_slots_used: AtomicU32::new(0), }); - let make_route = |put_id, remote_node: Option<&str>| { - let mut replicas = vec![("gpu0", false)]; - if let Some(remote_node) = remote_node { - replicas.push((remote_node, false)); - } - let mut route = test_route(put_id, None, replicas); - route.atomic_group = Some(group.clone()); - Arc::new(route) - }; - let desc = NodeValueReplicaDesc { - weight_bytes: 1024, - put_id: (7, 0), - }; + let replacement = Arc::new(test_route((21, 0), None, vec![("peer", false)])); + routes.insert("aba".to_string(), old_route.clone()); + routes.insert("aba".to_string(), replacement.clone()); + + assert_eq!( + remove_departed_generation_from_route( + &routes, + "aba", + &old_route, + "owner", + &departed_tag, + ), + None + ); + let current = routes.get("aba").expect("replacement route must survive"); + assert!(Arc::ptr_eq(current.value(), &replacement)); + assert!( + current + .nodes_replicas + .read() + .get("peer") + .is_some_and(|replica| !replica.tomb_tag.is_tomb()) + ); + } + + #[test] + fn replica_publish_fence_never_overwrites_live_or_publishes_tomb_generation() { + let old_tag = NodeTombTag::new(); + let route = test_route((30, 0), None, vec![]); + route.nodes_replicas.write().insert( + "owner".to_string().into(), + test_route_info_with_tag("owner", old_tag.clone()), + ); - let k0 = make_route((7, 0), Some("cpu0")); - let k1 = make_route((7, 1), Some("cpu0")); - let routes = HashMap::from([("k0".to_string(), k0.clone()), ("k1".to_string(), k1)]); - assert!(route_has_recoverable_replica_with( - "gpu0", - "k0", - &k0, - &desc, - &|key| routes.get(key).cloned(), - &test_remote_nodes, + let contender_tag = NodeTombTag::new(); + assert!(!publish_route_replica_tomb_fenced( + &route, + "owner".to_string().into(), + test_route_info_with_tag("owner", contender_tag), )); + assert!( + route + .nodes_replicas + .read() + .get("owner") + .is_some_and(|replica| replica.tomb_tag.same_generation(&old_tag)) + ); - let split_k1 = make_route((7, 1), Some("cpu1")); - let split_routes = - HashMap::from([("k0".to_string(), k0.clone()), ("k1".to_string(), split_k1)]); - assert!(!route_has_recoverable_replica_with( - "gpu0", - "k0", - &k0, - &desc, - &|key| split_routes.get(key).cloned(), - &test_remote_nodes, + old_tag.set_tomb(); + let replacement_tag = NodeTombTag::new(); + assert!(publish_route_replica_tomb_fenced( + &route, + "owner".to_string().into(), + test_route_info_with_tag("owner", replacement_tag.clone()), )); + assert!( + route + .nodes_replicas + .read() + .get("owner") + .is_some_and(|replica| replica.tomb_tag.same_generation(&replacement_tag)) + ); - let partial_k1 = make_route((7, 1), None); - let partial_routes = HashMap::from([ - ("k0".to_string(), k0.clone()), - ("k1".to_string(), partial_k1), - ]); - assert!(!route_has_recoverable_replica_with( - "gpu0", - "k0", - &k0, - &desc, - &|key| partial_routes.get(key).cloned(), - &test_remote_nodes, + let departed_tag = NodeTombTag::new(); + departed_tag.set_tomb(); + assert!(!publish_route_replica_tomb_fenced( + &route, + "departed".to_string().into(), + test_route_info_with_tag("departed", departed_tag), )); + assert!(!route.nodes_replicas.read().contains_key("departed")); + } + + #[test] + fn primary_publish_fence_restores_previous_route_on_tomb_generation() { + let routes = DashMap::new(); + let previous = Arc::new(test_route((40, 0), None, vec![("peer", false)])); + routes.insert("key".to_string(), previous.clone()); + + let departed_tag = NodeTombTag::new(); + departed_tag.set_tomb(); + let rejected = Arc::new(OneKvNodesRoutes { + put_id: (41, 0), + lease_id: None, + atomic_group: None, + nodes_replicas: RwLock::new(HashMap::from([( + "owner".to_string().into(), + test_route_info_with_tag("owner", departed_tag.clone()), + )])), + get_durable_slots_used: AtomicU32::new(0), + }); + assert!( + publish_primary_route_tomb_fenced(&routes, "key", rejected, &departed_tag).is_err() + ); + assert!( + routes + .get("key") + .is_some_and(|route| Arc::ptr_eq(route.value(), &previous)) + ); + + let live_tag = NodeTombTag::new(); + let accepted = Arc::new(OneKvNodesRoutes { + put_id: (42, 0), + lease_id: None, + atomic_group: None, + nodes_replicas: RwLock::new(HashMap::from([( + "owner".to_string().into(), + test_route_info_with_tag("owner", live_tag.clone()), + )])), + get_durable_slots_used: AtomicU32::new(0), + }); + let replaced = + publish_primary_route_tomb_fenced(&routes, "key", accepted.clone(), &live_tag) + .expect("live generation must publish") + .expect("previous route must be returned"); + assert!(Arc::ptr_eq(&replaced, &previous)); + assert!( + routes + .get("key") + .is_some_and(|route| Arc::ptr_eq(route.value(), &accepted)) + ); + } + + #[test] + fn reserved_capacity_counters_are_generation_and_arc_scoped() { + let old_tag = NodeTombTag::new(); + let new_tag = NodeTombTag::new(); + let old = Arc::new(NodeCacheReservedCapacity::new(old_tag.clone())); + let new = Arc::new(NodeCacheReservedCapacity::new(new_tag.clone())); + + old.apply_delta(ReservedCapacityReason::LeaseBoundKv, 4096); + new.apply_delta(ReservedCapacityReason::LeaseBoundKv, 8192); + old_tag.set_tomb(); + old.apply_delta(ReservedCapacityReason::LeaseBoundKv, -4096); + + assert_eq!(old.total_reserved_bytes(), 0); + assert_eq!(new.total_reserved_bytes(), 8192); + assert!(!old.generation.same_generation(&new.generation)); + assert!(!new_tag.is_tomb()); + } + + #[test] + fn delayed_member_left_is_not_forwarded_to_a_live_generation_actor() { + assert!(member_left_can_forward_to_registration_actor(None)); + assert!(!member_left_can_forward_to_registration_actor(Some(17))); } #[test] @@ -1462,7 +1961,7 @@ mod tests { } #[test] - fn recoverable_atomic_group_requires_complete_tp_cohort_on_one_cpu_owner() { + fn tp_cohort_expansion_preserves_every_atomic_member_across_ranks() { let rank0_group = Arc::new(PutAtomicGroup { members: vec![ msg_pack::PutAtomicGroupMember { @@ -1475,37 +1974,8 @@ mod tests { }, ], }); - let rank1_group = Arc::new(PutAtomicGroup { - members: vec![ - msg_pack::PutAtomicGroupMember { - key: "page0_model_1_2".to_string(), - put_id: (11, 0), - }, - msg_pack::PutAtomicGroupMember { - key: "page1_model_1_2".to_string(), - put_id: (11, 1), - }, - ], - }); - let make_route = |put_id, group: Arc, remote_node: Option<&str>| { - let mut replicas = vec![("gpu0", false)]; - if let Some(remote_node) = remote_node { - replicas.push((remote_node, false)); - } - let mut route = test_route(put_id, None, replicas); - route.atomic_group = Some(group); - Arc::new(route) - }; - let rank0_page0 = make_route((10, 0), rank0_group.clone(), Some("cpu0")); - let rank0_page1 = make_route((10, 1), rank0_group.clone(), Some("cpu0")); - let rank1_page0 = make_route((11, 0), rank1_group.clone(), Some("cpu0")); - let rank1_page1 = make_route((11, 1), rank1_group.clone(), Some("cpu0")); - let routes = HashMap::from([ - ("page0_model_0_2".to_string(), rank0_page0.clone()), - ("page1_model_0_2".to_string(), rank0_page1), - ("page0_model_1_2".to_string(), rank1_page0), - ("page1_model_1_2".to_string(), rank1_page1), - ]); + let mut rank0_page0 = test_route((10, 0), None, vec![("gpu0", false)]); + rank0_page0.atomic_group = Some(rank0_group); let desc = NodeValueReplicaDesc { weight_bytes: 1024, put_id: (10, 0), @@ -1519,95 +1989,16 @@ mod tests { "page1_model_1_2", ] ); - assert!(route_has_recoverable_replica_with( - "gpu0", - "page0_model_0_2", - &rank0_page0, - &desc, - &|key| routes.get(key).cloned(), - &test_remote_nodes, - )); - - let missing_peer_routes = routes - .iter() - .filter(|(key, _)| key.as_str() != "page1_model_1_2") - .map(|(key, route)| (key.clone(), route.clone())) - .collect::>(); - assert_eq!( - route_recoverable_replica_status_with( - "gpu0", - "page0_model_0_2", - &rank0_page0, - &desc, - &|key| missing_peer_routes.get(key).cloned(), - &test_remote_nodes, - ), - RecoverableReplicaStatus::TpCohortIncomplete - ); - - let rank1_page0_cpu1 = make_route((11, 0), rank1_group.clone(), Some("cpu1")); - let rank1_page1_cpu1 = make_route((11, 1), rank1_group, Some("cpu1")); - let split_cpu_routes = routes - .iter() - .map(|(key, route)| (key.clone(), route.clone())) - .chain([ - ("page0_model_1_2".to_string(), rank1_page0_cpu1), - ("page1_model_1_2".to_string(), rank1_page1_cpu1), - ]) - .collect::>(); - assert!(!route_has_recoverable_replica_with( - "gpu0", - "page0_model_0_2", - &rank0_page0, - &desc, - &|key| split_cpu_routes.get(key).cloned(), - &test_remote_nodes, - )); } #[test] - fn recoverable_single_page_requires_all_tp_ranks() { - let rank0 = Arc::new(test_route( - (20, 0), - None, - vec![("gpu0", false), ("cpu0", false)], - )); - let rank1 = Arc::new(test_route( - (21, 0), - None, - vec![("gpu0", false), ("cpu0", false)], - )); - let desc = NodeValueReplicaDesc { - weight_bytes: 1024, - put_id: (20, 0), - }; - let complete = HashMap::from([ - ("page_model_0_2".to_string(), rank0.clone()), - ("page_model_1_2".to_string(), rank1), - ]); - assert!(route_has_recoverable_replica_with( - "gpu0", - "page_model_0_2", - &rank0, - &desc, - &|key| complete.get(key).cloned(), - &test_remote_nodes, - )); - - let rank0_only = HashMap::from([("page_model_0_2".to_string(), rank0.clone())]); - assert!(!route_has_recoverable_replica_with( - "gpu0", - "page_model_0_2", - &rank0, - &desc, - &|key| rank0_only.get(key).cloned(), - &test_remote_nodes, - )); - } - - #[test] - fn owner_hot_demotion_rejects_the_whole_cohort_before_moka_selection() { - let expected_entries = HashMap::from([ + fn exact_cache_detach_rolls_back_identity_mismatch() { + let cache = moka::sync::SegmentedCache::builder(8) + .weigher(Box::new(|_key: &String, desc: &NodeValueReplicaDesc| { + desc.weight_bytes + })) + .build(); + let actual = HashMap::from([ ( "rank0".to_string(), NodeValueReplicaDesc { @@ -1623,77 +2014,48 @@ mod tests { }, ), ]); - let cache = moka::sync::SegmentedCache::builder(8) - .weigher(Box::new(|_key: &String, desc: &NodeValueReplicaDesc| { - desc.weight_bytes - })) - .build(); - for (key, desc) in &expected_entries { + for (key, desc) in &actual { cache.insert(key.clone(), desc.clone()); } - cache.run_pending_tasks(); + let mut stale_expected = actual.clone(); + stale_expected.get_mut("rank1").unwrap().put_id = (999, 0); - let selected_weight = recoverable_cohort_weight(&expected_entries, |key, _desc| { - if key == "rank0" { - RecoverableReplicaStatus::Recoverable - } else { - RecoverableReplicaStatus::TpCohortIncomplete - } - }) - .map_or(0, |expected_weight| { - cache.evict_some_if(expected_weight, |candidate_key, candidate_desc| { - expected_entries.get(candidate_key).is_some_and(|expected| { - expected.put_id == candidate_desc.put_id - && expected.weight_bytes == candidate_desc.weight_bytes - }) - }) - }); - - assert_eq!(selected_weight, 0); - assert!(cache.get("rank0").is_some()); - assert!(cache.get("rank1").is_some()); - } + assert!(take_exact_cache_entries(&cache, &stale_expected).is_none()); + assert_eq!(cache.get("rank0").unwrap().put_id, (30, 0)); + assert_eq!(cache.get("rank1").unwrap().put_id, (31, 0)); - #[test] - fn unrecoverable_fallback_is_only_for_last_level_or_no_remote_tier() { - assert!(allow_unrecoverable_cache_eviction( - false, - false, - UnrecoverableCacheEvictionContext::NormalCapacity, - )); - assert!(!allow_unrecoverable_cache_eviction( - false, - true, - UnrecoverableCacheEvictionContext::NormalCapacity, - )); - assert!(allow_unrecoverable_cache_eviction( - true, - true, - UnrecoverableCacheEvictionContext::NormalCapacity, - )); - assert!(allow_unrecoverable_cache_eviction( - false, - true, - UnrecoverableCacheEvictionContext::OwnerLocalReserveNoSpace, - )); + let removed = take_exact_cache_entries(&cache, &actual).unwrap(); + assert_eq!(removed.len(), 2); + assert!(cache.get("rank0").is_none()); + assert!(cache.get("rank1").is_none()); } #[test] - fn unbounded_segmented_metadata_cache_only_evicts_when_requested() { + fn ring_b_cache_is_bounded_for_every_node_role() { let cache = moka::sync::SegmentedCache::builder(8) + .max_capacity(64) .weigher(Box::new(|_key: &u64, weight: &u32| *weight)) .build(); - assert_eq!(cache.policy().max_capacity(), None); + assert_eq!(cache.policy().max_capacity(), Some(64)); for key in 0..128 { cache.insert(key, 8); } cache.run_pending_tasks(); - assert_eq!(cache.weighted_size(), 1024); + assert!(cache.weighted_size() <= 64); + } - let evicted = cache.evict_some_if(64, |_key, _weight| true); - assert!(evicted >= 64); - assert_eq!(cache.weighted_size(), 1024 - evicted); + #[test] + fn ring_b_live_capacity_update_never_clears_boundary() { + let cache = moka::sync::SegmentedCache::builder(8) + .max_capacity(1024) + .weigher(Box::new(|_key: &u64, weight: &u32| *weight)) + .build(); + assert_eq!(cache.policy().max_capacity(), Some(1024)); + cache.set_max_capacity(512).unwrap(); + assert_eq!(cache.policy().max_capacity(), Some(512)); + cache.set_max_capacity(2048).unwrap(); + assert_eq!(cache.policy().max_capacity(), Some(2048)); } #[test] @@ -1711,6 +2073,139 @@ mod tests { assert_eq!(pending.load(Ordering::Acquire), 0); } + #[test] + fn cohort_reclaim_identity_registration_is_all_or_nothing() { + let request = |keys: &[&str]| reclaim::EvictionReclaimRequest { + owner_node_id: "cpu0".to_string(), + owner_node_start_time: None, + members: keys + .iter() + .enumerate() + .map(|(index, key)| reclaim::EvictionReclaimMember { + key: (*key).to_string(), + desc: NodeValueReplicaDesc { + weight_bytes: 1024, + put_id: (7, index as u32), + }, + expected_backing: None, + }) + .collect(), + origin: reclaim::EvictionReclaimOrigin::MasterAllocationCapacity, + retry_count: 0, + }; + let inflight = DashSet::new(); + let first = request(&["a", "b"]); + assert!(try_install_eviction_reclaim_identities( + &inflight, + first.identities(), + )); + assert_eq!(inflight.len(), 2); + assert_eq!( + classify_existing_eviction_reclaim(&inflight, &first.identities()), + reclaim::EnqueueEvictionReclaimResult::AlreadyInProgress + ); + + // `c` is tentatively installed before the collision on `a`; failure + // must roll it back and preserve only the original cohort. + let overlapping = reclaim::EvictionReclaimRequest { + members: vec![ + reclaim::EvictionReclaimMember { + key: "c".to_string(), + desc: NodeValueReplicaDesc { + weight_bytes: 1024, + put_id: (7, 2), + }, + expected_backing: None, + }, + first.members[0].clone(), + ], + ..request(&[]) + }; + let tentative_identity = overlapping.identities()[0].clone(); + assert!(!try_install_eviction_reclaim_identities( + &inflight, + overlapping.identities(), + )); + assert_eq!(inflight.len(), 2); + assert!(!inflight.contains(&tentative_identity)); + assert_eq!( + classify_existing_eviction_reclaim(&inflight, &overlapping.identities()), + reclaim::EnqueueEvictionReclaimResult::PartialOverlap + ); + + for identity in first.identities() { + assert!(inflight.remove(&identity).is_some()); + } + assert_eq!( + classify_existing_eviction_reclaim(&inflight, &first.identities()), + reclaim::EnqueueEvictionReclaimResult::NotInProgress + ); + } + + #[test] + fn eviction_reclaim_metadata_channel_does_not_drop_at_old_queue_limit() { + let (tx, mut rx) = ampsc::unbounded_channel(); + let count = 4096 * 2 + 1; + for index in 0..count { + tx.send(reclaim::EvictionReclaimRequest { + owner_node_id: "cpu0".to_string(), + owner_node_start_time: None, + members: vec![reclaim::EvictionReclaimMember { + key: format!("key-{index}"), + desc: NodeValueReplicaDesc { + weight_bytes: 4096, + put_id: (7, index as u32), + }, + expected_backing: None, + }], + origin: reclaim::EvictionReclaimOrigin::MasterAllocationCapacity, + retry_count: 0, + }) + .unwrap(); + } + assert_eq!((0..count).filter(|_| rx.try_recv().is_ok()).count(), count); + } + + #[test] + fn closed_lossless_channel_rolls_back_identity_accounting_and_metadata() { + let cache = moka::sync::SegmentedCache::builder(8).build(); + let request = reclaim::EvictionReclaimRequest { + owner_node_id: "cpu0".to_string(), + owner_node_start_time: None, + members: vec![reclaim::EvictionReclaimMember { + key: "closed-channel".to_string(), + desc: NodeValueReplicaDesc { + weight_bytes: 4096, + put_id: (7, 1), + }, + expected_backing: None, + }], + origin: reclaim::EvictionReclaimOrigin::MasterAllocationCapacity, + retry_count: 0, + }; + let inflight = DashSet::new(); + assert!(try_install_eviction_reclaim_identities( + &inflight, + request.identities(), + )); + let pending = AtomicU64::new(request.weight_bytes()); + let (tx, rx) = ampsc::unbounded_channel(); + drop(rx); + + let returned = tx.send(request).unwrap_err().0; + for identity in returned.identities() { + assert!(inflight.remove(&identity).is_some()); + } + subtract_pending_eviction_weight(&pending, "cpu0", returned.weight_bytes()); + for member in returned.members { + cache.insert(member.key, member.desc); + } + + assert!(inflight.is_empty()); + assert_eq!(pending.load(Ordering::Acquire), 0); + assert!(cache.get("closed-channel").is_some()); + } + fn new_test_member(metadata: HashMap) -> ClusterMember { ClusterMember { id: "node-a".to_string(), @@ -1795,7 +2290,11 @@ pub struct MasterKvRouterInner { pub inflight_puts: moka::future::Cache<(String, u64, u32), InflightPutInfo>, pub inflight_replica_tasks: moka::future::Cache<(String, u64, u32), InflightReplicaTaskInfo>, pub inflight_gets: moka::future::Cache, + /// Idempotent terminal GetDone results retained across response loss/retry. + pub completed_gets: moka::future::Cache, + pub get_done_locks: AMapLock, pub(crate) key_activity: Arc, + pub(crate) prepared_get_requesters: Arc, /// Cache for holding get operations (owned, flattened by (node_id, holder_id)) pub get_holding: MasterOwnerMemMgr, @@ -1821,11 +2320,6 @@ pub struct MasterKvRouterInner { /// Interns recent multi-key put groups so all member routes share one descriptor. put_atomic_groups: moka::sync::SegmentedCache<(String, u64, u32), Arc>, - /// Serializes route-level existence checks with cache-eviction route cleanup. - /// This protects route metadata consistency only; it does not create MemHolders - /// or move payload data. - pub route_lifetime_lock: Mutex<()>, - /// Grants reserved for owner-local hot-path staging. pub local_reserve_grants: DashMap, @@ -1839,8 +2333,9 @@ pub struct MasterKvRouterInner { pub node_kv_cache_controller: DashMap>>, - /// Inclusive hot tier. L1 eviction starts a remote-only replica task while the owner copy - /// remains governed by `node_kv_cache_controller` at its unchanged resident capacity. + /// Independent pre-writeback tier. Its Size eviction starts a replica task + /// while owner residency remains governed by the owner's local hot cache; + /// `node_kv_cache_controller` tracks ring B only. pub node_writeback_tier1_controller: DashMap>>, @@ -1852,14 +2347,21 @@ pub struct MasterKvRouterInner { /// Moka weight already removed and queued for owner-side safe reclaim. pub eviction_reclaim_pending_weight: DashMap>, + /// Exact, versioned metadata identities currently owned by the lossless + /// eviction-reclaim pipeline. This bounds duplicate Size/cohort events; + /// payload memory is not retained here. + pub(crate) eviction_reclaim_inflight: DashSet, + /// Per-owner reclaim lifecycle counters. These distinguish transient holder/activity /// deferrals from terminal route changes and bounded retry restoration. pub(crate) eviction_reclaim_counters: DashMap>, - /// Serializes all append completions for one logical TP/atomic cohort. Without this lock, - /// several member completions can pass the recoverability precheck together and concurrently - /// select overlapping subsets from Moka. - owner_hot_demotion_locks: AMapLock, + /// Async admission gate in front of Moka's synchronous housekeeper lock. + /// Bounded maintenance can still process a batch of Size evictions; without + /// this gate, concurrent async tasks can park multiple Tokio workers on the + /// same blocking Moka lock. It is a scheduling gate, not a correctness or + /// cohort lock, and no cache/global scan occurs under it. + pub(crate) owner_cache_operation_locks: AMapLock, /// Historical final put placement decisions by target node. pub put_target_decision_counts: DashMap>, @@ -1884,8 +2386,8 @@ pub struct MasterKvRouterInner { pub delete_broadcast: EnsureMemholderMgmtDeleteHandle, post_route_maintenance_tx: ampsc::Sender, post_route_maintenance_rx: Mutex>>, - eviction_reclaim_tx: ampsc::Sender, - eviction_reclaim_rx: Mutex>>, + eviction_reclaim_tx: ampsc::UnboundedSender, + eviction_reclaim_rx: Mutex>>, tier1_writeback_tx: ampsc::Sender, tier1_writeback_rx: Mutex>>, tier1_writeback_dedupe: moka::sync::SegmentedCache<(String, u64, u32), ()>, @@ -1978,6 +2480,7 @@ impl MasterKvRouter { INFLIGHT_PUT_TTL_SECONDS }; let key_activity = Arc::new(MasterKeyActivityTable::default()); + let prepared_get_requesters = Arc::new(PreparedGetRequesterTable::default()); let inflight_puts = moka::future::Cache::builder() .time_to_live(Duration::from_secs(inflight_put_ttl_seconds)) .eviction_listener(|_put_id, inflight_info: InflightPutInfo, cause| { @@ -1999,6 +2502,9 @@ impl MasterKvRouter { } }) .build(); + let completed_gets = moka::future::Cache::builder() + .time_to_live(Duration::from_secs(120)) + .build(); let inflight_replica_tasks = moka::future::Cache::builder() .time_to_live(Duration::from_secs(60)) .eviction_listener(|_put_id, inflight_info: InflightReplicaTaskInfo, cause| { @@ -2007,8 +2513,10 @@ impl MasterKvRouter { } }) .build(); - let (eviction_reclaim_tx, eviction_reclaim_rx) = - ampsc::channel(EVICTION_RECLAIM_QUEUE_CAPACITY); + // A synchronous Moka listener must perform only constant-size metadata + // work and must never block or drop an Allocation reclaim event. The + // versioned inflight set deduplicates this unbounded channel. + let (eviction_reclaim_tx, eviction_reclaim_rx) = ampsc::unbounded_channel(); let (post_route_maintenance_tx, post_route_maintenance_rx) = ampsc::channel(POST_ROUTE_MAINTENANCE_QUEUE_CAPACITY); let (tier1_writeback_tx, tier1_writeback_rx) = @@ -2023,7 +2531,10 @@ impl MasterKvRouter { inflight_puts, inflight_replica_tasks, inflight_gets, + completed_gets, + get_done_locks: AMapLock::new(Duration::from_secs(10 * 60)), key_activity, + prepared_get_requesters, get_holding: MasterOwnerMemMgr::default(), next_get_id: AtomicU64::new(0), next_holder_id: AtomicU64::new(0), @@ -2035,7 +2546,6 @@ impl MasterKvRouter { .max_capacity(262_144) .time_to_idle(Duration::from_secs(30 * 60)) .build(), - route_lifetime_lock: Mutex::new(()), local_reserve_grants: DashMap::new(), prepared_put_key_reservations: DashMap::new(), prefix_index: ARwLock::new(PrefixRadixTree::new()), @@ -2043,8 +2553,9 @@ impl MasterKvRouter { node_writeback_tier1_controller: DashMap::new(), node_cache_reserved_capacity: DashMap::new(), eviction_reclaim_pending_weight: DashMap::new(), + eviction_reclaim_inflight: DashSet::new(), eviction_reclaim_counters: DashMap::new(), - owner_hot_demotion_locks: AMapLock::new(Duration::from_secs(10 * 60)), + owner_cache_operation_locks: AMapLock::new(Duration::from_secs(10 * 60)), put_target_decision_counts: DashMap::new(), put_requester_target_decision_counts: DashMap::new(), put_placement_mode_counts: DashMap::new(), @@ -2131,62 +2642,56 @@ impl MasterKvRouter { .inner() .node_cache_reserved_capacity .get(node_id) + .filter(|reserved| !reserved.generation.is_tomb()) .map(|reserved| reserved.total_reserved_bytes()) .unwrap_or(0); self.replica_cache_base_capacity(node_space_size) .saturating_sub(reserved_capacity) } - fn owner_cache_allows_unrecoverable_eviction_in_context( - &self, - owner_node_id: &str, - context: UnrecoverableCacheEvictionContext, - ) -> bool { - let remote_only_roles = &self.inner().replica_task_placement.remote_only_node_roles; - let owner = self + /// Refresh an already-created node controller after segment metadata or + /// reservation inputs change. The boundary is derived only from physical + /// node space and generation-scoped reservations, never placement roles. + fn reconcile_node_cache_capacity(&self, node_id: &str) { + let node_space_size = self .inner() .view() - .cluster_manager() - .get_member_info_cached(owner_node_id); - let owner_is_remote_only = - placement::member_matches_roles(owner.as_ref(), remote_only_roles); - let has_ready_remote_only_owner = self + .master_seg_manager() + .get_node_space_size(node_id); + if node_space_size == 0 { + return; + } + let capacity = self.replica_cache_effective_capacity(node_id, node_space_size); + if let Some(cache) = self .inner() - .view() - .cluster_manager() - .get_members() - .into_iter() - .any(|member| { - placement::member_matches_roles(Some(&member), remote_only_roles) - && self - .inner() - .view() - .master_seg_manager() - .get_node_space_size(member.id.as_str()) - != 0 - }); - allow_unrecoverable_cache_eviction( - owner_is_remote_only, - has_ready_remote_only_owner, - context, - ) - } - - pub(crate) fn owner_cache_allows_unrecoverable_eviction(&self, owner_node_id: &str) -> bool { - self.owner_cache_allows_unrecoverable_eviction_in_context( - owner_node_id, - UnrecoverableCacheEvictionContext::NormalCapacity, - ) - } - - pub(crate) fn owner_cache_allows_unrecoverable_reserve_pressure_eviction( - &self, - owner_node_id: &str, - ) -> bool { - self.owner_cache_allows_unrecoverable_eviction_in_context( - owner_node_id, - UnrecoverableCacheEvictionContext::OwnerLocalReserveNoSpace, - ) + .node_kv_cache_controller + .get(node_id) + .map(|entry| entry.value().clone()) + { + if let Err(err) = cache.set_max_capacity(capacity) { + error!( + "failed to refresh ring-B cache capacity: node={} capacity={} err={}", + node_id, capacity, err, + ); + } + } + if let Some(cache) = self + .inner() + .node_writeback_tier1_controller + .get(node_id) + .map(|entry| entry.value().clone()) + { + let tier1_capacity = self + .writeback_tier1_base_capacity(node_space_size) + .unwrap_or(0) + .min(capacity); + if let Err(err) = cache.set_max_capacity(tier1_capacity) { + error!( + "failed to refresh tier1 cache capacity: node={} capacity={} err={}", + node_id, tier1_capacity, err, + ); + } + } } fn writeback_tier1_base_capacity(&self, node_space_size: u64) -> Option { @@ -2265,6 +2770,24 @@ impl MasterKvRouter { }) } + pub(crate) fn reserve_prepared_get_requester( + &self, + key: &str, + requester: &NodeID, + get_id: u64, + ) -> Result, KvError> { + self.inner() + .prepared_get_requesters + .reserve(key, requester, get_id) + .ok_or_else(|| { + KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::KeyBeingWritten { + key: key.to_string(), + }, + ) + }) + } + pub(crate) fn reserve_inflight_replica_key( &self, key: &str, @@ -2376,40 +2899,151 @@ impl MasterKvRouter { owner_node_id: NodeIDString, key: String, desc: NodeValueReplicaDesc, - ) { - let weight_bytes = desc.weight_bytes; - let pending_weight = self - .inner() - .eviction_reclaim_pending_weight - .entry(owner_node_id.clone()) - .or_insert_with(|| Arc::new(AtomicU64::new(0))) - .value() - .clone(); - pending_weight.fetch_add(u64::from(weight_bytes), Ordering::AcqRel); + origin: reclaim::EvictionReclaimOrigin, + ) -> bool { + self.enqueue_eviction_reclaim_cohort( + owner_node_id, + vec![reclaim::EvictionReclaimMember { + key, + desc, + expected_backing: None, + }], + origin, + ) + } + + fn enqueue_eviction_reclaim_cohort( + &self, + owner_node_id: NodeIDString, + members: Vec, + origin: reclaim::EvictionReclaimOrigin, + ) -> bool { + matches!( + self.enqueue_eviction_reclaim_cohort_exact(owner_node_id, None, members, origin, true,), + reclaim::EnqueueEvictionReclaimResult::Accepted + | reclaim::EnqueueEvictionReclaimResult::AlreadyInProgress + ) + } + + pub(crate) fn enqueue_owner_capacity_eviction_cohort( + &self, + owner_node_id: NodeIDString, + owner_node_start_time: i64, + members: Vec, + allow_new_request: bool, + ) -> reclaim::EnqueueEvictionReclaimResult { + self.enqueue_eviction_reclaim_cohort_exact( + owner_node_id, + Some(owner_node_start_time), + members, + reclaim::EvictionReclaimOrigin::OwnerCapacityEviction, + allow_new_request, + ) + } + + fn enqueue_eviction_reclaim_cohort_exact( + &self, + owner_node_id: NodeIDString, + owner_node_start_time: Option, + members: Vec, + origin: reclaim::EvictionReclaimOrigin, + allow_new_request: bool, + ) -> reclaim::EnqueueEvictionReclaimResult { + if members.is_empty() { + return reclaim::EnqueueEvictionReclaimResult::PartialOverlap; + } let request = reclaim::EvictionReclaimRequest { owner_node_id, - key, - desc, + owner_node_start_time, + members, + origin, retry_count: 0, }; - if let Err(err) = self.inner().eviction_reclaim_tx.try_send(request) { - let queue_error = err.to_string(); - let request = err.into_inner(); - subtract_pending_eviction_weight( - pending_weight.as_ref(), - request.owner_node_id.as_str(), - u64::from(weight_bytes), - ); - let restored = self.restore_eviction_cache_entry_if_current( - request.owner_node_id.as_str(), - request.key, - request.desc, + if !allow_new_request { + let identities = request.identities(); + return classify_existing_eviction_reclaim( + &self.inner().eviction_reclaim_inflight, + &identities, ); + } + if !self.register_eviction_reclaim(&request) { + self.eviction_reclaim_counters(&request.owner_node_id) + .eviction_reclaim_deduplicated + .fetch_add(1, Ordering::Relaxed); + // An idempotent retry is accepted only when the complete cohort + // is already owned by the pipeline. A partial overlap is not a + // valid source handoff. + return if request + .identities() + .iter() + .all(|identity| self.inner().eviction_reclaim_inflight.contains(identity)) + { + reclaim::EnqueueEvictionReclaimResult::AlreadyInProgress + } else { + reclaim::EnqueueEvictionReclaimResult::PartialOverlap + }; + } + if let Err(err) = self.inner().eviction_reclaim_tx.send(request) { + let request = err.0; + self.complete_eviction_reclaim(&request); + if request.origin == reclaim::EvictionReclaimOrigin::MasterAllocationCapacity { + // This branch can run inside Moka's synchronous Size listener. + // Never re-enter that cache while its housekeeper lock is + // held; restore by key after yielding out of the callback. + let restore_view = self.inner().view().clone(); + let restore_request = request.clone(); + let spawn_view = restore_view.clone(); + let _ = spawn_view.spawn("closed_eviction_reclaim_restore", async move { + tokio::task::yield_now().await; + let mut restored = 0usize; + for member in &restore_request.members { + if restore_view.master_kv_router().restore_eviction_cache_entry_if_current( + &restore_request.owner_node_id, + member.key.clone(), + member.desc.clone(), + ) { + restored += 1; + } + } + warn!( + "restored master Allocation metadata after reclaim actor closed: owner={} members={} restored={}", + restore_request.owner_node_id, + restore_request.members.len(), + restored, + ); + }); + } warn!( - "safe eviction reclaim queue is full or closed: {}; restored={}", - queue_error, restored + "lossless eviction reclaim actor is closed: owner={} members={} origin={:?} restore_deferred={}", + request.owner_node_id, + request.members.len(), + request.origin, + request.origin == reclaim::EvictionReclaimOrigin::MasterAllocationCapacity, ); + return reclaim::EnqueueEvictionReclaimResult::Closed; } + reclaim::EnqueueEvictionReclaimResult::Accepted + } + + pub(crate) fn register_eviction_reclaim( + &self, + request: &reclaim::EvictionReclaimRequest, + ) -> bool { + if !try_install_eviction_reclaim_identities( + &self.inner().eviction_reclaim_inflight, + request.identities(), + ) { + return false; + } + let pending_weight = self + .inner() + .eviction_reclaim_pending_weight + .entry(request.owner_node_id.clone()) + .or_insert_with(|| Arc::new(AtomicU64::new(0))) + .value() + .clone(); + pending_weight.fetch_add(request.weight_bytes(), Ordering::AcqRel); + true } pub(crate) fn eviction_reclaim_pending_weight(&self, owner_node_id: &str) -> u64 { @@ -2432,27 +3066,31 @@ impl MasterKvRouter { .clone() } - pub(crate) fn complete_eviction_reclaim_weight( - &self, - owner_node_id: &str, - completed_weight: u64, - ) { - if completed_weight == 0 { - return; + pub(crate) fn complete_eviction_reclaim(&self, request: &reclaim::EvictionReclaimRequest) { + for identity in request.identities() { + assert!( + self.inner() + .eviction_reclaim_inflight + .remove(&identity) + .is_some(), + "eviction reclaim identity completed without registration: {:?}", + identity, + ); } + let completed_weight = request.weight_bytes(); let pending_weight = self .inner() .eviction_reclaim_pending_weight - .get(owner_node_id) + .get(&request.owner_node_id) .unwrap_or_else(|| { panic!( "eviction reclaim pending weight missing for owner {}", - owner_node_id + request.owner_node_id ) }); subtract_pending_eviction_weight( pending_weight.value().as_ref(), - owner_node_id, + &request.owner_node_id, completed_weight, ); } @@ -2464,233 +3102,82 @@ impl MasterKvRouter { desc: NodeValueReplicaDesc, ) -> bool { if !self.eviction_cache_entry_is_current(owner_node_id, &key, &desc) { - return false; - } - self.insert_node_cache_entry(owner_node_id, key, desc) - } - - pub(crate) fn eviction_cache_entry_is_current( - &self, - owner_node_id: &str, - key: &str, - desc: &NodeValueReplicaDesc, - ) -> bool { - self.inner().kv_routes.get(key).is_some_and(|route| { - route.put_id == desc.put_id - && route.lease_id.is_none() - && route - .nodes_replicas - .read() - .iter() - .any(|(node_id, replica)| { - node_id.as_ref() == owner_node_id && !replica.tomb_tag.is_tomb() - }) - }) - } - - fn eviction_cache_entry_recoverable_status( - &self, - owner_node_id: &str, - key: &str, - desc: &NodeValueReplicaDesc, - ) -> RecoverableReplicaStatus { - let Some(route) = self.inner().kv_routes.get(key).map(|route| route.clone()) else { - return RecoverableReplicaStatus::RouteAbsent; - }; - route_recoverable_replica_status(self.inner().view(), owner_node_id, key, &route, desc) - } - - pub(crate) fn evict_recoverable_cache_weight( - &self, - owner_node_id: &str, - requested_weight: u64, - ) -> u64 { - self.evict_recoverable_cache_weight_excluding( - owner_node_id, - requested_weight, - &HashSet::new(), - ) - } - - pub(crate) fn evict_recoverable_cache_weight_excluding( - &self, - owner_node_id: &str, - requested_weight: u64, - excluded_keys: &HashSet, - ) -> u64 { - if requested_weight == 0 { - return 0; - } - let Some(cache) = self.get_node_cache_controller(owner_node_id) else { - return 0; - }; - let counters = self.eviction_reclaim_counters(owner_node_id); - counters - .recoverable_first_requested_bytes - .fetch_add(requested_weight, Ordering::Relaxed); - let selected_weight = cache.evict_some_if(requested_weight, |key, desc| { - if excluded_keys.contains(key) { - return false; - } - let status = self.eviction_cache_entry_recoverable_status(owner_node_id, key, desc); - counters.record_recoverable_first_status(status); - status == RecoverableReplicaStatus::Recoverable - }); - counters - .recoverable_first_selected_bytes - .fetch_add(selected_weight, Ordering::Relaxed); - counters.recoverable_first_shortfall_bytes.fetch_add( - requested_weight.saturating_sub(selected_weight), - Ordering::Relaxed, - ); - selected_weight + return false; + } + self.insert_node_cache_entry(owner_node_id, key, desc) } - pub(crate) async fn demote_owner_hot_cohort_if_recoverable( + pub(crate) fn eviction_cache_entry_is_current( &self, owner_node_id: &str, key: &str, - put_id: PutIDForAKey, - ) -> u64 { - let counters = self.eviction_reclaim_counters(owner_node_id); - counters - .owner_hot_demotion_attempts - .fetch_add(1, Ordering::Relaxed); + desc: &NodeValueReplicaDesc, + ) -> bool { + self.inner().kv_routes.get(key).is_some_and(|route| { + ring_b_route_replica_desc(&route, owner_node_id).is_some_and(|current| { + current.put_id == desc.put_id && current.weight_bytes == desc.weight_bytes + }) + }) + } - let Some(cache) = self.get_node_cache_controller(owner_node_id) else { - return 0; - }; - cache.run_pending_tasks(); - let Some(anchor_desc) = cache.get(key) else { - return 0; - }; - if anchor_desc.put_id != put_id { - return 0; - } - let Some(anchor_route) = self.inner().kv_routes.get(key).map(|route| route.clone()) else { - return 0; - }; - let Ok(cohort_keys) = current_tp_cohort_keys(key, &anchor_route, &anchor_desc) else { - return 0; - }; - let Some(cohort_anchor) = cohort_keys.iter().min() else { - return 0; - }; - let cohort_lock = self + /// Point-remove one exact ring-B metadata identity. Callers use the + /// async per-node gate before entering Moka's synchronous housekeeper, so + /// route conversion never falls back to a cache scan. + pub(crate) async fn remove_node_cache_entry_exact( + &self, + owner_node_id: &str, + key: &str, + desc: &NodeValueReplicaDesc, + ) -> bool { + let owner_cache_lock = self .inner() - .owner_hot_demotion_locks - .get_lock(format!("{owner_node_id}\0{cohort_anchor}")); - let _cohort_guard = cohort_lock.lock().await; - - // The route and Moka state may have changed while another member completion held the - // cohort lock. Recompute the complete cohort under the lock before selecting anything. - cache.run_pending_tasks(); - let Some(anchor_desc) = cache.get(key) else { - return 0; - }; - if anchor_desc.put_id != put_id { - return 0; - } - let Some(anchor_route) = self.inner().kv_routes.get(key).map(|route| route.clone()) else { - return 0; - }; - let Ok(locked_cohort_keys) = current_tp_cohort_keys(key, &anchor_route, &anchor_desc) - else { - return 0; - }; - if locked_cohort_keys != cohort_keys { - counters - .owner_hot_demotion_precheck_rejected - .fetch_add(1, Ordering::Relaxed); - return 0; - } - - // Demotion is an all-or-nothing TP/atomic-cohort transition. Do not - // silently shrink the cohort when one of its source entries has - // already disappeared from this owner's cache: doing so can recreate - // the mixed local/remote layout that made the prefix unrecoverable in - // E23. - let expected_cohort_len = locked_cohort_keys.len(); - let expected_entries = locked_cohort_keys - .into_iter() - .map(|cohort_key| cache.get(&cohort_key).map(|desc| (cohort_key, desc))) - .collect::>>(); - let Some(expected_entries) = expected_entries else { - counters - .owner_hot_demotion_precheck_rejected - .fetch_add(1, Ordering::Relaxed); - return 0; - }; - if expected_entries.len() != expected_cohort_len || expected_entries.is_empty() { - counters - .owner_hot_demotion_precheck_rejected - .fetch_add(1, Ordering::Relaxed); - return 0; - } + .owner_cache_operation_locks + .get_lock(owner_node_id.to_string()); + let _owner_cache_guard = owner_cache_lock.lock().await; + self.inner() + .node_kv_cache_controller + .get(owner_node_id) + .is_some_and(|cache| remove_exact_cache_entry(cache.value(), key, desc)) + } - // Validate the whole TP/atomic cohort before asking Moka to select anything. Performing - // this check in the eviction predicate allowed one recoverable member to be selected even - // when a later member was not recoverable, which turned an intended exclusive transition - // into a partial source demotion. - let Some(expected_weight) = - recoverable_cohort_weight(&expected_entries, |candidate_key, candidate_desc| { - let status = self.eviction_cache_entry_recoverable_status( - owner_node_id, - candidate_key, - candidate_desc, - ); - counters.record_recoverable_first_status(status); - status + /// Remove one superseded route version from both metadata policies using + /// only the route's own replica list. This is O(replica count), never a + /// Moka or global-route scan, and cannot delete a newer same-key version. + pub(crate) async fn remove_route_cache_entries_exact( + &self, + key: &str, + route: &OneKvNodesRoutes, + ) { + let replicas = route + .nodes_replicas + .read() + .iter() + .filter_map(|(node_id, replica)| { + (!replica.tomb_tag.is_tomb()).then(|| { + ( + node_id.as_ref().to_string(), + NodeValueReplicaDesc { + weight_bytes: u32::try_from(replica.backing.capacity_bytes()) + .unwrap_or(u32::MAX), + put_id: route.put_id, + }, + ) + }) }) - else { - counters - .owner_hot_demotion_precheck_rejected - .fetch_add(1, Ordering::Relaxed); - return 0; - }; - - let selected_weight = - cache.evict_some_if(expected_weight, |candidate_key, candidate_desc| { - expected_entries - .get(candidate_key) - .is_some_and(|expected_desc| { - expected_desc.put_id == candidate_desc.put_id - && expected_desc.weight_bytes == candidate_desc.weight_bytes - }) - }); - if selected_weight != expected_weight { - counters - .owner_hot_demotion_partial_mismatch - .fetch_add(1, Ordering::Relaxed); - tracing::error!( - "owner hot TP-cohort demotion selected a partial cohort: owner={} key={} put_id=({},{}) cohort_entries={} expected_weight={} selected_weight={}", - owner_node_id, - key, - put_id.0, - put_id.1, - expected_entries.len(), - expected_weight, - selected_weight - ); - } - if selected_weight == expected_weight { - counters - .owner_hot_demotion_cohorts - .fetch_add(1, Ordering::Relaxed); - counters - .owner_hot_demotion_selected_bytes - .fetch_add(selected_weight, Ordering::Relaxed); - tracing::debug!( - "owner hot complete TP-cohort demotion selected: owner={} key={} put_id=({},{}) cohort_entries={} selected_weight={}", - owner_node_id, - key, - put_id.0, - put_id.1, - expected_entries.len(), - selected_weight - ); + .collect::>(); + for (node_id, desc) in replicas { + let owner_cache_lock = self + .inner() + .owner_cache_operation_locks + .get_lock(node_id.clone()); + let _owner_cache_guard = owner_cache_lock.lock().await; + if let Some(cache) = self.inner().node_kv_cache_controller.get(&node_id) { + let _ = remove_exact_cache_entry(cache.value(), key, &desc); + } + if let Some(cache) = self.inner().node_writeback_tier1_controller.get(&node_id) { + let _ = remove_exact_cache_entry(cache.value(), key, &desc); + } } - selected_weight } pub(crate) fn insert_node_cache_entry( @@ -2702,45 +3189,8 @@ impl MasterKvRouter { let Some(cache) = self.get_node_cache_controller(owner_node_id) else { return false; }; - cache.run_pending_tasks(); - let existing_weight = cache - .get(&key) - .map(|existing| u64::from(existing.weight_bytes)) - .unwrap_or(0); - let projected_weight = cache - .weighted_size() - .saturating_sub(existing_weight) - .saturating_add(u64::from(desc.weight_bytes)); - let node_space_size = self - .inner() - .view() - .master_seg_manager() - .get_node_space_size(owner_node_id); - let capacity = self.replica_cache_effective_capacity(owner_node_id, node_space_size); - let requested_weight = projected_weight.saturating_sub(capacity); - if requested_weight != 0 { - let recoverable_selected_weight = - self.evict_recoverable_cache_weight(owner_node_id, requested_weight); - let fallback_requested_weight = - requested_weight.saturating_sub(recoverable_selected_weight); - let fallback_selected_weight = - if self.owner_cache_allows_unrecoverable_eviction(owner_node_id) { - cache.evict_some(fallback_requested_weight) - } else { - 0 - }; - tracing::debug!( - "recoverable-first cache admission: owner={} key={} requested_weight={} recoverable_selected_weight={} fallback_requested_weight={} fallback_selected_weight={} projected_weight={} capacity={}", - owner_node_id, - key, - requested_weight, - recoverable_selected_weight, - fallback_requested_weight, - fallback_selected_weight, - projected_weight, - capacity - ); - } + // Restoration is an exact metadata repair after a failed reclaim + // dispatch. It must never search for or evict an unrelated victim. cache.insert(key, desc); true } @@ -2792,8 +3242,9 @@ impl MasterKvRouter { let view = view.clone(); let view2 = view.clone(); let view_task = view2.clone(); + let req_node_id = resp.node_id().clone(); let _ = view.spawn("rpc_get_revoke", async move { - let ack = handle_get_revoke(view_task, msg).await; + let ack = handle_get_revoke(view_task, msg, req_node_id).await; if let Err(e) = resp.send_resp(ack).await { error!("Failed to send GetRevokeResp: {:?}", e); } @@ -2806,9 +3257,10 @@ impl MasterKvRouter { let view = view.clone(); let view2 = view.clone(); let view_task = view2.clone(); + let req_node_id = resp.node_id().clone(); let _ = view.spawn("rpc_get_done", async move { let t0 = Utc::now().timestamp_micros(); - let mut ack = handle_get_done(view_task, msg).await; + let mut ack = handle_get_done(view_task, msg, req_node_id).await; ack.serialize_part.server_process_us = Utc::now().timestamp_micros() - t0; if let Err(e) = resp.send_resp(ack).await { error!("Failed to send GetDoneResp: {:?}", e); @@ -3070,6 +3522,20 @@ impl MasterKvRouter { Ok(()) }); + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let owner = resp.node_id().clone(); + let view_task = view.clone(); + let _ = view.spawn("rpc_batch_evict_owner_source", async move { + let ack = handle_batch_evict_owner_source(&view_task, msg, owner).await; + if let Err(err) = resp.send_resp(ack).await { + error!("Failed to send BatchEvictOwnerSourceResp: {:?}", err); + } + }); + Ok(()) + }); + let view = self.0.view().clone(); RPCHandler::::new().regist(p2p, move |resp, msg| { let view = view.clone(); @@ -3087,6 +3553,23 @@ impl MasterKvRouter { Ok(()) }); + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let view2 = view.clone(); + let req_node_id = resp.node_id().clone(); + let view_task = view2.clone(); + let _ = view.spawn("rpc_batch_put_append_start", async move { + let t0 = Utc::now().timestamp_micros(); + let mut ack = handle_batch_put_append_start(view_task, msg, req_node_id).await; + ack.serialize_part.server_process_us = Utc::now().timestamp_micros() - t0; + if let Err(e) = resp.send_resp(ack).await { + error!("Failed to send BatchPutAppendStartResp: {:?}", e); + } + }); + Ok(()) + }); + let view = self.0.view().clone(); RPCHandler::::new().regist(p2p, move |resp, msg| { let view = view.clone(); @@ -3117,6 +3600,22 @@ impl MasterKvRouter { Ok(()) }); + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let view2 = view.clone(); + let view_task = view2.clone(); + let _ = view.spawn("rpc_batch_put_append_done", async move { + let t0 = Utc::now().timestamp_micros(); + let mut ack = handle_batch_put_append_done(view_task, msg).await; + ack.serialize_part.server_process_us = Utc::now().timestamp_micros() - t0; + if let Err(e) = resp.send_resp(ack).await { + error!("Failed to send BatchPutAppendDoneResp: {:?}", e); + } + }); + Ok(()) + }); + // --- GetMeta Handler --- let view = self.0.view().clone(); RPCHandler::::new().regist(p2p, move |resp, msg| { @@ -3247,8 +3746,9 @@ impl MasterKvRouter { RPCHandler::::new().regist(p2p, move |resp, msg| { let view = view.clone(); let view2 = view.clone(); + let req_node_id = resp.node_id().clone(); view.spawn("rpc_batch_get_revoke", async move { - let ack = handle_batch_get_revoke(view2, msg).await; + let ack = handle_batch_get_revoke(view2, msg, req_node_id).await; if let Err(e) = resp.send_resp(ack).await { error!("Failed to send BatchGetRevokeResp: {:?}", e); } @@ -3260,9 +3760,10 @@ impl MasterKvRouter { RPCHandler::::new().regist(p2p, move |resp, msg| { let view = view.clone(); let view2 = view.clone(); + let req_node_id = resp.node_id().clone(); view.spawn("rpc_batch_get_done", async move { let t0 = Utc::now().timestamp_micros(); - let mut ack = handle_batch_get_done(view2, msg).await; + let mut ack = handle_batch_get_done(view2, msg, req_node_id).await; ack.serialize_part.server_process_us = Utc::now().timestamp_micros() - t0; if let Err(e) = resp.send_resp(ack).await { error!("Failed to send BatchGetDoneResp: {:?}", e); @@ -3272,6 +3773,65 @@ impl MasterKvRouter { }); } + /// Start cleanup for one exact departed membership generation. + /// + /// Tomb publication and O(1) controller detachment happen synchronously in the cluster + /// listener. The potentially large route scan is then performed by a yielding async task. + fn begin_departed_generation_cleanup( + &self, + node_id: &str, + expected_node_start_time: Option, + ) -> bool { + let node: NodeID = node_id.to_string().into(); + let Some(departed_tag) = self + .inner() + .view() + .master_seg_manager() + .mark_node_tomb_generation(&node, expected_node_start_time) + else { + debug!( + "MemberLeft generation cleanup skipped because the registered generation changed or no segment was registered: node={} expected_node_start_time={:?}", + node_id, expected_node_start_time + ); + return false; + }; + + // Detach generation-scoped controllers before starting the full route scan. A tombed + // segment reports zero usable space, so old-generation work cannot recreate the caches. + let resident_cache_detached = self + .inner() + .node_kv_cache_controller + .remove(node_id) + .is_some(); + let tier1_cache_detached = self + .inner() + .node_writeback_tier1_controller + .remove(node_id) + .is_some(); + self.inner() + .node_cache_reserved_capacity + .remove_if(node_id, |_, reserved| { + reserved.generation.same_generation(&departed_tag) + }); + + let removed_holdings = self.inner().get_holding.cleanup_node(node_id); + let view = self.inner().view().clone(); + let node_id_owned = node_id.to_string(); + let _ = view.clone().spawn("member_left_route_cleanup", async move { + cleanup_departed_generation_routes(view, node_id_owned, departed_tag).await; + }); + + info!( + "MemberLeft generation marked and controllers detached: node={} expected_node_start_time={:?} resident_cache_detached={} tier1_cache_detached={} removed_holdings={}", + node_id, + expected_node_start_time, + resident_cache_detached, + tier1_cache_detached, + removed_holdings + ); + true + } + fn spawn_node_segement_registration_caller(&self) -> ampsc::Sender { const KEEP_ALIVE_TIME: Duration = Duration::from_secs(30); const NODE_EVENT_QUEUE_CAPACITY: usize = 64; @@ -3338,8 +3898,8 @@ impl MasterKvRouter { let epoch = member.node_start_time; if let Some(prev) = *last_seen_epoch { if prev != epoch { - view.master_seg_manager() - .mark_node_tomb(&node_id.clone().into()); + view.master_kv_router() + .begin_departed_generation_cleanup(&node_id, Some(prev)); } } *last_seen_epoch = Some(epoch); @@ -3397,10 +3957,9 @@ impl MasterKvRouter { inflight = None; debug!( - "MasterKvRouter received node leave event: {:?}, mark it as tomb", + "MasterKvRouter registration actor canceled departed node: {:?}", node_id ); - view_task.master_seg_manager().mark_node_tomb(&node_id.into()); } } } @@ -3476,10 +4035,9 @@ impl MasterKvRouter { inflight = None; debug!( - "MasterKvRouter received node leave event: {:?}, mark it as tomb", + "MasterKvRouter registration actor canceled departed node: {:?}", node_id ); - view_task.master_seg_manager().mark_node_tomb(&node_id.into()); } } } @@ -3504,6 +4062,11 @@ impl MasterKvRouter { registered_epoch = Some(epoch); desired_epoch = None; backoff = INITIAL_BACKOFF; + if let Some(node_id) = actor_node_id.as_deref() { + view_task + .master_kv_router() + .reconcile_node_cache_capacity(node_id); + } info!( "Successfully requested segment registration from client {}", actor_node_id.clone().unwrap_or_default() @@ -3561,10 +4124,9 @@ impl MasterKvRouter { inflight = None; debug!( - "MasterKvRouter received node leave event: {:?}, mark it as tomb", + "MasterKvRouter registration actor canceled departed node: {:?}", node_id ); - view_task.master_seg_manager().mark_node_tomb(&node_id.into()); } } } @@ -3630,17 +4192,66 @@ impl MasterKvRouter { event: ClusterEvent, ) { match &event { + ClusterEvent::MemberJoined(member) | ClusterEvent::MemberUpdated(member) => { + view.master_kv_router() + .reconcile_node_cache_capacity(&member.id); + } ClusterEvent::MemberLeft(node_id) => { - let removed = view + let departed_epoch = view + .cluster_manager() + .get_prev_member_info(node_id) + .map(|member| member.node_start_time); + let current_member = view + .cluster_manager() + .get_member_info_cached(node_id); + let current_epoch = current_member + .as_ref() + .map(|member| member.node_start_time); + + // MemberLeft has no epoch. Once a live generation is visible, this leave + // is ambiguous and must neither clean state nor reach the per-node actor: + // forwarding it would clear desired/registered_epoch for the reconnect. + if !member_left_can_forward_to_registration_actor(current_epoch) { + debug!( + "ignoring delayed MemberLeft after reconnect: node={} current_node_start_time={}", + node_id, + current_epoch.unwrap_or_default() + ); + return; + } + + let registered_tag_before = view + .master_seg_manager() + .get_node_tomb_tag(&node_id.clone().into()); + if !view .master_kv_router() - .inner() - .get_holding - .cleanup_node(&node_id); - if removed > 0 { - info!("Cleaned up {} holdings for left member {}", removed, node_id); + .begin_departed_generation_cleanup(node_id, departed_epoch) + { + // A registered segment exists but did not match `departed_epoch`: + // preserve it and do not forward the old leave to the actor. + if registered_tag_before.is_some() { + debug!( + "ignoring generation-mismatched MemberLeft: node={} departed_epoch={:?}", + node_id, departed_epoch + ); + return; + } + + // External/zero-contribution members do not register a segment or + // own route backing, but they can still own get holdings. + let removed = view + .master_kv_router() + .inner() + .get_holding + .cleanup_node(node_id); + if removed > 0 { + info!( + "Cleaned up {} holdings for segmentless left member {}", + removed, node_id + ); + } } } - _ => {} } let node_id = event.node_id(); @@ -3787,6 +4398,7 @@ impl MasterKvRouter { GetAllocationMode::Temporary => "temporary", GetAllocationMode::ReuseReplica => "reuse_replica", GetAllocationMode::DurableReplica => "durable_replica", + GetAllocationMode::LocalCommittedSlot => "local_committed_slot", }; let mode_count = self .inner() @@ -3901,6 +4513,11 @@ impl MasterKvRouter { if node_space_size == 0 { return None; } + // Ring B is a backing/index domain, not a placement-role domain. A + // GPU owner can also hold master-only Allocation replicas, so every + // live segment gets the same bounded controller. Non-ring-B bytes + // are subtracted through generation-scoped reservation tokens. + let allocation_capacity = self.replica_cache_effective_capacity(node_id, node_space_size); let view = self.inner().view().clone(); let node_id_owned = node_id.to_string(); Some( @@ -3910,46 +4527,32 @@ impl MasterKvRouter { .or_insert_with(move || { let view = view.clone(); let cache_node_id = node_id_owned.clone(); - Arc::new( - moka::sync::SegmentedCache::builder(8) - // The resident cache is a metadata/LRU controller. Its aggregate - // effective capacity is enforced explicitly with `evict_some_if`. - // Leaving the Moka segments unbounded prevents per-segment hash skew - // from performing an independent Size eviction outside that policy. - // Use the actual allocated/rounded size as weight to - // make eviction reflect real memory usage. - .weigher(Box::new(|_key: &String, value: &NodeValueReplicaDesc| { - value.weight_bytes - })) - .eviction_listener(Box::new( - move |key: Arc, - _value: NodeValueReplicaDesc, - cause: RemovalCause| { - debug!("Evicted key: {:?}, caused by: {:?}", key, cause); - match cause { - // timeout or size exceed - RemovalCause::Size | RemovalCause::Expired => { - let k = (*key).clone(); - let evicted_put_id = _value.put_id; - tracing::debug!( - "Eviction-triggered local replica cleanup for key {} on node {} put_id=({},{})", - k, - cache_node_id, - evicted_put_id.0, - evicted_put_id.1 - ); - view.master_kv_router().enqueue_eviction_reclaim( - cache_node_id.clone(), - k, - _value, - ); - } - _ => {} - } - }, - )) - .build(), - ) + let builder = moka::sync::SegmentedCache::builder(8) + // Admission is restricted to unindexed Allocation + // routes. CommittedSlot and owner-indexed Allocation + // entries belong to ring A and never enter this cache. + .weigher(Box::new(|_key: &String, value: &NodeValueReplicaDesc| { + value.weight_bytes + })) + .eviction_listener(Box::new( + move |key: Arc, + _value: NodeValueReplicaDesc, + cause: RemovalCause| { + if cause == RemovalCause::Size { + // Listener work is deliberately O(1): + // clone fixed metadata, dedupe, and send + // to a lossless channel. Route/cohort + // lookup belongs to the async actor. + let _ = view.master_kv_router().enqueue_eviction_reclaim( + cache_node_id.clone(), + (*key).clone(), + _value, + reclaim::EvictionReclaimOrigin::MasterAllocationCapacity, + ); + } + }, + )); + Arc::new(builder.max_capacity(allocation_capacity).build()) }) .value() .clone(), @@ -4034,17 +4637,6 @@ impl MasterKvRouter { ) } - pub fn remove_node_writeback_tier1_entry(&self, node_id: &str, key: &str) { - if let Some(cache) = self - .inner() - .node_writeback_tier1_controller - .get(node_id) - .map(|entry| entry.value().clone()) - { - let _ = cache.remove(key); - } - } - pub(crate) fn tier1_writeback_entry_is_current( &self, source_node_id: &str, @@ -4160,28 +4752,67 @@ impl MasterKvRouter { )); } - /// Atomically adjust a node's moka usable-capacity reservation by `delta_bytes`. - /// Positive delta reserves capacity (fetch_sub from usable capacity), - /// negative delta releases reservation (fetch_add back to usable capacity). - pub fn adjust_node_cache_reserved_capacity( + /// Adjust one exact generation/counter identity and refresh its live cache + /// boundary. Negative releases always stay applied to the captured Arc, + /// even when the node has already left and its controller was detached. + fn adjust_node_cache_reserved_capacity_identity( &self, node_id: &str, + generation: &NodeTombTag, + reserved_capacity: &Arc, reason: ReservedCapacityReason, delta_bytes: i64, ) -> crate::rpcresp_kvresult_convert::msg_and_error::KvResult<()> { if !self.replica_cache_enabled() { return Ok(()); } - let reserved_capacity = self - .inner() - .node_cache_reserved_capacity - .entry(node_id.to_string()) - .or_insert_with(|| Arc::new(NodeCacheReservedCapacity::default())) - .value() - .clone(); + if !reserved_capacity.generation.same_generation(generation) { + return Err( + crate::rpcresp_kvresult_convert::msg_and_error::KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "cache reservation generation/counter identity mismatch: node_id={}", + node_id + ), + }, + ), + ); + } reserved_capacity.apply_delta(reason, delta_bytes); + let current_identity = self + .inner() + .node_cache_reserved_capacity + .get(node_id) + .is_some_and(|current| { + Arc::ptr_eq(current.value(), reserved_capacity) + && current.generation.same_generation(generation) + }) + && node_generation_is_current_live( + self.inner().view(), + &node_id.to_string().into(), + generation, + ); + if !current_identity { + if delta_bytes >= 0 { + reserved_capacity.apply_delta(reason, -delta_bytes); + return Err( + crate::rpcresp_kvresult_convert::msg_and_error::KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "cache reservation target generation changed: node_id={}", + node_id + ), + }, + ), + ); + } + // The old generation has been detached. Its exact counter Arc is + // now balanced, and no live controller must be modified. + return Ok(()); + } + // Recompute target capacity from the configured base ratio minus live reservations. let reserved_total = reserved_capacity.total_reserved_bytes(); let node_space_size = self @@ -4190,9 +4821,9 @@ impl MasterKvRouter { .master_seg_manager() .get_node_space_size(node_id); if node_space_size == 0 { - // Node not ready: this should not happen in a successful put_done path. - // Revert the counter delta before returning error. - reserved_capacity.apply_delta(reason, -delta_bytes); + if delta_bytes >= 0 { + reserved_capacity.apply_delta(reason, -delta_bytes); + } return Err( crate::rpcresp_kvresult_convert::msg_and_error::KvError::Unreachable( crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::OwnerNoSeg { @@ -4219,7 +4850,9 @@ impl MasterKvRouter { .unwrap_or(0) .min(new_capacity); if let Err(e) = tier1_cache.set_max_capacity(tier1_capacity) { - reserved_capacity.apply_delta(reason, -delta_bytes); + if delta_bytes >= 0 { + reserved_capacity.apply_delta(reason, -delta_bytes); + } return Err( crate::rpcresp_kvresult_convert::msg_and_error::KvError::Unreachable( crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::RpcDecodeError { @@ -4232,33 +4865,26 @@ impl MasterKvRouter { ); } } - cache.run_pending_tasks(); - let requested_weight = cache.weighted_size().saturating_sub(new_capacity); - let recoverable_selected_weight = - self.evict_recoverable_cache_weight(node_id, requested_weight); - let fallback_requested_weight = - requested_weight.saturating_sub(recoverable_selected_weight); - let fallback_selected_weight = - if self.owner_cache_allows_unrecoverable_eviction(node_id) { - cache.evict_some(fallback_requested_weight) - } else { - 0 - }; - if requested_weight != 0 { - tracing::debug!( - "resident cache effective-capacity adjustment: owner={} effective_capacity={} requested_weight={} recoverable_selected_weight={} fallback_requested_weight={} fallback_selected_weight={}", - node_id, - new_capacity, - requested_weight, - recoverable_selected_weight, - fallback_requested_weight, - fallback_selected_weight + if let Err(e) = cache.set_max_capacity(new_capacity) { + if delta_bytes >= 0 { + reserved_capacity.apply_delta(reason, -delta_bytes); + } + return Err( + crate::rpcresp_kvresult_convert::msg_and_error::KvError::Unreachable( + crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::RpcDecodeError { + rpc_input_json: format!( + "ring-B allocation moka.set_max_capacity failed: node_id={}, new_capacity={}, err={}", + node_id, new_capacity, e + ), + }, + ), ); } Ok(()) } else { - // Revert counter and return error. - reserved_capacity.apply_delta(reason, -delta_bytes); + if delta_bytes >= 0 { + reserved_capacity.apply_delta(reason, -delta_bytes); + } Err( crate::rpcresp_kvresult_convert::msg_and_error::KvError::Unreachable( crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::OwnerNoSeg { @@ -4269,6 +4895,83 @@ impl MasterKvRouter { } } + /// Reserve cache capacity for one exact live node generation. The returned + /// route-lifetime token releases the same counter identity on Drop. + pub fn reserve_node_cache_capacity( + &self, + node_id: &NodeID, + generation: &NodeTombTag, + reason: ReservedCapacityReason, + bytes: u64, + ) -> crate::rpcresp_kvresult_convert::msg_and_error::KvResult< + Option>, + > { + if !self.replica_cache_enabled() { + return Ok(None); + } + if !node_generation_is_current_live(self.inner().view(), node_id, generation) { + return Err( + crate::rpcresp_kvresult_convert::msg_and_error::KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "cannot reserve cache capacity for departed generation: node_id={}", + node_id + ), + }, + ), + ); + } + + let reserved_capacity = match self + .inner() + .node_cache_reserved_capacity + .entry(node_id.to_string()) + { + dashmap::mapref::entry::Entry::Occupied(mut entry) => { + if entry.get().generation.same_generation(generation) { + entry.get().clone() + } else if entry.get().generation.is_tomb() { + let replacement = Arc::new(NodeCacheReservedCapacity::new(generation.clone())); + entry.insert(replacement.clone()); + replacement + } else { + return Err( + crate::rpcresp_kvresult_convert::msg_and_error::KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "live cache reservation counter belongs to another generation: node_id={}", + node_id + ), + }, + ), + ); + } + } + dashmap::mapref::entry::Entry::Vacant(entry) => { + let counter = Arc::new(NodeCacheReservedCapacity::new(generation.clone())); + entry.insert(counter.clone()); + counter + } + }; + + self.adjust_node_cache_reserved_capacity_identity( + node_id.as_ref(), + generation, + &reserved_capacity, + reason, + bytes as i64, + )?; + Ok(Some(Arc::new(NodeCacheCapacityReservation { + view: self.inner().view().clone(), + node_id: node_id.to_string(), + generation: generation.clone(), + reserved_capacity, + reason, + bytes, + released: AtomicBool::new(false), + }))) + } + pub fn next_local_reserve_grant_id(&self) -> u64 { self.inner() .next_local_reserve_grant_id @@ -4350,10 +5053,15 @@ impl MasterKvRouter { .inner() .node_cache_reserved_capacity .get(owner_node.as_str()) + .filter(|reserved| !reserved.generation.is_tomb()) .map(|reserved| reserved.total_reserved_bytes()) .unwrap_or(0); - let effective_capacity_bytes = - self.replica_cache_effective_capacity(owner_node.as_str(), node_space_size); + // Every live node's ring-B controller is bounded, independent of + // its placement role. + let effective_capacity_bytes = cache + .policy() + .max_capacity() + .expect("ring-B controller must always be bounded"); let pending_eviction_reclaim_bytes = self.eviction_reclaim_pending_weight(owner_node.as_str()); let reclaim_counters = self.eviction_reclaim_counters(owner_node.as_str()); @@ -4397,9 +5105,6 @@ impl MasterKvRouter { reclaim_master_activity_deferred: reclaim_counters .master_activity_deferred .load(Ordering::Relaxed), - reclaim_master_get_holder_observed: reclaim_counters - .master_get_holder_observed - .load(Ordering::Relaxed), reclaim_owner_holder_deferred: reclaim_counters .owner_holder_deferred .load(Ordering::Relaxed), @@ -4411,50 +5116,39 @@ impl MasterKvRouter { reclaim_retry_completed: reclaim_counters.retry_completed.load(Ordering::Relaxed), reclaim_retry_restored: reclaim_counters.retry_restored.load(Ordering::Relaxed), reclaim_completed: reclaim_counters.completed.load(Ordering::Relaxed), - owner_hot_demotion_attempts: reclaim_counters - .owner_hot_demotion_attempts - .load(Ordering::Relaxed), - owner_hot_demotion_cohorts: reclaim_counters - .owner_hot_demotion_cohorts - .load(Ordering::Relaxed), - owner_hot_demotion_selected_bytes: reclaim_counters - .owner_hot_demotion_selected_bytes - .load(Ordering::Relaxed), - owner_hot_demotion_precheck_rejected: reclaim_counters - .owner_hot_demotion_precheck_rejected - .load(Ordering::Relaxed), - owner_hot_demotion_partial_mismatch: reclaim_counters - .owner_hot_demotion_partial_mismatch + source_evict_rpc_requests: reclaim_counters + .source_evict_rpc_requests .load(Ordering::Relaxed), - recoverable_first_requested_bytes: reclaim_counters - .recoverable_first_requested_bytes + source_evict_cohorts: reclaim_counters + .source_evict_cohorts .load(Ordering::Relaxed), - recoverable_first_selected_bytes: reclaim_counters - .recoverable_first_selected_bytes + source_evict_requested_bytes: reclaim_counters + .source_evict_requested_bytes .load(Ordering::Relaxed), - recoverable_first_shortfall_bytes: reclaim_counters - .recoverable_first_shortfall_bytes + source_evict_accepted: reclaim_counters + .source_evict_accepted .load(Ordering::Relaxed), - recoverable_first_eligible_checks: reclaim_counters - .recoverable_first_eligible_checks + source_evict_in_progress: reclaim_counters + .source_evict_in_progress .load(Ordering::Relaxed), - recoverable_first_route_absent_checks: reclaim_counters - .recoverable_first_route_absent_checks + source_evict_completed: reclaim_counters + .source_evict_completed .load(Ordering::Relaxed), - recoverable_first_version_changed_checks: reclaim_counters - .recoverable_first_version_changed_checks + source_evict_retryable_busy: reclaim_counters + .source_evict_retryable_busy .load(Ordering::Relaxed), - recoverable_first_route_ineligible_checks: reclaim_counters - .recoverable_first_route_ineligible_checks + source_evict_stale: reclaim_counters.source_evict_stale.load(Ordering::Relaxed), + source_evict_rejected: reclaim_counters + .source_evict_rejected .load(Ordering::Relaxed), - recoverable_first_cpu_route_absent_checks: reclaim_counters - .recoverable_first_cpu_route_absent_checks + capacity_eviction_non_ring_b_entry_total: reclaim_counters + .capacity_eviction_non_ring_b_entry_total .load(Ordering::Relaxed), - recoverable_first_atomic_group_incomplete_checks: reclaim_counters - .recoverable_first_atomic_group_incomplete_checks + capacity_eviction_hit_committed_slot: reclaim_counters + .capacity_eviction_hit_committed_slot .load(Ordering::Relaxed), - recoverable_first_tp_cohort_incomplete_checks: reclaim_counters - .recoverable_first_tp_cohort_incomplete_checks + eviction_reclaim_deduplicated: reclaim_counters + .eviction_reclaim_deduplicated .load(Ordering::Relaxed), }); } @@ -4493,7 +5187,7 @@ impl MasterKvRouter { ); for node in snapshot.replica_cache_nodes { tracing::info!( - "replica cache runtime: owner={} entries={} weighted_bytes={} effective_capacity_bytes={} base_capacity_bytes={} reserved_capacity_bytes={} pending_eviction_reclaim_bytes={} writeback_tier1_entries={} writeback_tier1_weighted_bytes={} writeback_tier1_capacity_bytes={} writeback_tier1_triggered={} writeback_tier1_owner_accepted={} writeback_tier1_failed={} reclaim_master_activity_deferred={} reclaim_master_get_holder_observed={} reclaim_owner_holder_deferred={} reclaim_owner_other_deferred={} reclaim_route_changed={} reclaim_retry_queued={} reclaim_retry_completed={} reclaim_retry_restored={} reclaim_completed={} owner_hot_demotion_attempts={} owner_hot_demotion_cohorts={} owner_hot_demotion_selected_bytes={} owner_hot_demotion_precheck_rejected={} owner_hot_demotion_partial_mismatch={} recoverable_first_requested_bytes={} recoverable_first_selected_bytes={} recoverable_first_shortfall_bytes={} recoverable_first_eligible_checks={} recoverable_first_route_absent_checks={} recoverable_first_version_changed_checks={} recoverable_first_route_ineligible_checks={} recoverable_first_cpu_route_absent_checks={} recoverable_first_atomic_group_incomplete_checks={} recoverable_first_tp_cohort_incomplete_checks={}", + "replica cache runtime: owner={} entries={} weighted_bytes={} effective_capacity_bytes={} base_capacity_bytes={} reserved_capacity_bytes={} pending_eviction_reclaim_bytes={} writeback_tier1_entries={} writeback_tier1_weighted_bytes={} writeback_tier1_capacity_bytes={} writeback_tier1_triggered={} writeback_tier1_owner_accepted={} writeback_tier1_failed={} reclaim_master_activity_deferred={} reclaim_owner_holder_deferred={} reclaim_owner_other_deferred={} reclaim_route_changed={} reclaim_retry_queued={} reclaim_retry_completed={} reclaim_retry_restored={} reclaim_completed={} source_evict_rpc_requests={} source_evict_cohorts={} source_evict_requested_bytes={} source_evict_accepted={} source_evict_in_progress={} source_evict_completed={} source_evict_retryable_busy={} source_evict_stale={} source_evict_rejected={} capacity_eviction_non_ring_b_entry_total={} capacity_eviction_hit_committed_slot={} eviction_reclaim_deduplicated={}", node.owner_node, node.entries, node.weighted_bytes, @@ -4508,7 +5202,6 @@ impl MasterKvRouter { node.writeback_tier1_owner_accepted, node.writeback_tier1_failed, node.reclaim_master_activity_deferred, - node.reclaim_master_get_holder_observed, node.reclaim_owner_holder_deferred, node.reclaim_owner_other_deferred, node.reclaim_route_changed, @@ -4516,21 +5209,18 @@ impl MasterKvRouter { node.reclaim_retry_completed, node.reclaim_retry_restored, node.reclaim_completed, - node.owner_hot_demotion_attempts, - node.owner_hot_demotion_cohorts, - node.owner_hot_demotion_selected_bytes, - node.owner_hot_demotion_precheck_rejected, - node.owner_hot_demotion_partial_mismatch, - node.recoverable_first_requested_bytes, - node.recoverable_first_selected_bytes, - node.recoverable_first_shortfall_bytes, - node.recoverable_first_eligible_checks, - node.recoverable_first_route_absent_checks, - node.recoverable_first_version_changed_checks, - node.recoverable_first_route_ineligible_checks, - node.recoverable_first_cpu_route_absent_checks, - node.recoverable_first_atomic_group_incomplete_checks, - node.recoverable_first_tp_cohort_incomplete_checks + node.source_evict_rpc_requests, + node.source_evict_cohorts, + node.source_evict_requested_bytes, + node.source_evict_accepted, + node.source_evict_in_progress, + node.source_evict_completed, + node.source_evict_retryable_busy, + node.source_evict_stale, + node.source_evict_rejected, + node.capacity_eviction_non_ring_b_entry_total, + node.capacity_eviction_hit_committed_slot, + node.eviction_reclaim_deduplicated, ); metrics.set_kv_replica_cache_entries( node.owner_node.as_str(), diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs index 9f7717b..048732e 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs @@ -17,11 +17,22 @@ pub enum GetAllocationMode { Temporary = 0, ReuseReplica = 1, DurableReplica = 2, + LocalCommittedSlot = 3, +} + +#[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)] +pub struct GetPreparedLocalReserveTarget { + pub grant_id: u64, + pub slot_index: u32, + pub slot_size: u64, + pub addr: u64, + pub base_addr: u64, } #[derive(Default, Debug, Clone, Encode, Decode)] pub struct GetStartReq { pub key: String, + pub prepared_target: Option, } impl MsgPackSerializePart for GetStartReq { fn msg_id(&self) -> u32 { @@ -40,6 +51,9 @@ pub struct GetStartResp { pub target_base_addr: u64, pub src_base_addr: u64, pub len: u64, + /// Echoes the owner-local slot accepted as this Get's target. + pub prepared_target: Option, + pub atomic_group: Option, pub error_code: ErrorCode, pub error_json: String, /// Server-side processing time in microseconds for this RPC handler @@ -107,6 +121,9 @@ impl RPCReq for GetDoneReq { #[derive(Default, Debug, Clone, Encode, Decode)] pub struct BatchGetStartReq { pub keys: Vec, + /// Empty selects ordinary master allocations. Otherwise this must contain + /// exactly one entry per key. + pub prepared_targets: Vec>, } impl MsgPackSerializePart for BatchGetStartReq { fn msg_id(&self) -> u32 { @@ -124,6 +141,8 @@ pub struct BatchGetStartItemResp { pub target_base_addr: u64, pub src_base_addr: u64, pub len: u64, + pub prepared_target: Option, + pub atomic_group: Option, pub error_code: ErrorCode, pub error_json: String, } @@ -265,15 +284,7 @@ impl RPCReq for GetMasterOnlyMetricPartReq { } #[derive(Default, Debug, Clone, Encode, Decode)] -pub struct ReserveLocalGrantReq { - /// Slot class that needs capacity. Zero means a raw grant request with no reclaim fallback. - pub slot_size: u64, - /// Number of slots the owner is currently short of in this class. - pub required_free_slots: u32, - /// Reclaim committed slots before growing the physical grant pool. This keeps owner-local - /// free-slot headroom without changing the owner's advertised capacity. - pub reclaim_before_grow: bool, -} +pub struct ReserveLocalGrantReq {} impl MsgPackSerializePart for ReserveLocalGrantReq { fn msg_id(&self) -> u32 { MsgId::ReserveLocalGrantReq as u32 @@ -292,10 +303,6 @@ pub enum ReserveLocalGrantOutcome { base_addr: u64, len: u64, }, - Reclaimed { - slot_size: u64, - reclaimed_slots: u32, - }, } #[derive(Default, Debug, Clone, Encode, Decode)] @@ -334,7 +341,7 @@ pub enum OwnerReclaimItemState { Stale, } -#[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)] +#[derive(Default, Debug, Clone, Hash, PartialEq, Eq, Encode, Decode)] pub enum OwnerReclaimBacking { #[default] Allocation, @@ -351,8 +358,73 @@ pub enum OwnerReclaimBacking { #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)] pub enum OwnerReclaimReason { #[default] - Reserve, - CapacityEviction, + OwnerCapacityEviction, + MasterAllocationCapacity, +} + +/// One exact owner-local source selected for capacity eviction. +#[derive(Default, Debug, Clone, Hash, PartialEq, Eq, Encode, Decode)] +pub struct OwnerSourceEvictionMember { + pub key: String, + pub put_id: PutIDForAKey, + pub backing: OwnerReclaimBacking, +} + +/// Atomic/TP members which must enter the reclaim pipeline together. +#[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)] +pub struct OwnerSourceEvictionCohort { + pub members: Vec, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchEvictOwnerSourceReq { + pub operation_id: u64, + /// Membership generation of the authenticated source owner. + pub owner_node_start_time: i64, + pub cohorts: Vec, +} + +impl MsgPackSerializePart for BatchEvictOwnerSourceReq { + fn msg_id(&self) -> u32 { + MsgId::BatchEvictOwnerSourceReq as u32 + } +} + +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)] +pub enum OwnerSourceEvictionOutcome { + #[default] + Unspecified, + Accepted, + AlreadyInProgress, + Completed, + RetryableBusy, + Stale, + RejectedNotEvictable, +} + +#[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)] +pub struct OwnerSourceEvictionCohortResp { + pub cohort_index: u32, + pub outcome: OwnerSourceEvictionOutcome, + pub detail: String, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchEvictOwnerSourceResp { + pub operation_id: u64, + pub cohorts: Vec, + pub error_code: ErrorCode, + pub error_json: String, +} + +impl MsgPackSerializePart for BatchEvictOwnerSourceResp { + fn msg_id(&self) -> u32 { + MsgId::BatchEvictOwnerSourceResp as u32 + } +} + +impl RPCReq for BatchEvictOwnerSourceReq { + type Resp = BatchEvictOwnerSourceResp; } #[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)] @@ -919,7 +991,6 @@ pub struct PutAppendStartReq { pub put_id: PutIDForAKey, pub len: u64, pub preferred_sub_cluster: Option, - pub demote_source_on_remote_complete: bool, pub protect_source_on_remote_complete: bool, } impl MsgPackSerializePart for PutAppendStartReq { @@ -927,9 +998,26 @@ impl MsgPackSerializePart for PutAppendStartReq { MsgId::PutAppendStartReq as u32 } } + +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)] +pub enum PutAppendStartOutcome { + /// Missing/old peers must not accidentally interpret a zero value as + /// successful completion. + #[default] + Unspecified, + Scheduled, + /// A complete non-source replica already exists for this exact put_id. + AlreadySatisfied, + /// The source route/version no longer exists; retry would target stale data. + Obsolete, + /// No remote allocation is available now. The owner keeps its local slot + /// and retries with backoff; this is never a demotion/drop instruction. + RetryableNoSpace, +} + #[derive(Default, Debug, Clone, Encode, Decode)] pub struct PutAppendStartResp { - pub scheduled: bool, + pub outcome: PutAppendStartOutcome, pub node_id: NodeIDString, pub target_addr: u64, pub target_base_addr: u64, @@ -947,6 +1035,54 @@ impl RPCReq for PutAppendStartReq { type Resp = PutAppendStartResp; } +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPutAppendStartItemReq { + pub key: String, + pub put_id: PutIDForAKey, + pub len: u64, + pub preferred_sub_cluster: Option, + pub protect_source_on_remote_complete: bool, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPutAppendStartReq { + pub items: Vec, +} +impl MsgPackSerializePart for BatchPutAppendStartReq { + fn msg_id(&self) -> u32 { + MsgId::BatchPutAppendStartReq as u32 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPutAppendStartItemResp { + pub key: String, + pub put_id: PutIDForAKey, + pub outcome: PutAppendStartOutcome, + pub node_id: NodeIDString, + pub target_addr: u64, + pub target_base_addr: u64, + pub len: u64, + pub error_code: ErrorCode, + pub error_json: String, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPutAppendStartResp { + pub items: Vec, + pub error_code: ErrorCode, + pub error_json: String, + pub server_process_us: i64, +} +impl MsgPackSerializePart for BatchPutAppendStartResp { + fn msg_id(&self) -> u32 { + MsgId::BatchPutAppendStartResp as u32 + } +} +impl RPCReq for BatchPutAppendStartReq { + type Resp = BatchPutAppendStartResp; +} + #[derive(Default, Debug, Clone, Encode, Decode)] pub struct PutAppendRevokeReq { pub key: String, @@ -997,6 +1133,47 @@ impl RPCReq for PutAppendDoneReq { type Resp = PutAppendDoneResp; } +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPutAppendDoneItemReq { + pub key: String, + pub put_id: PutIDForAKey, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPutAppendDoneReq { + pub items: Vec, +} +impl MsgPackSerializePart for BatchPutAppendDoneReq { + fn msg_id(&self) -> u32 { + MsgId::BatchPutAppendDoneReq as u32 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPutAppendDoneItemResp { + pub key: String, + pub put_id: PutIDForAKey, + pub appended: bool, + pub error_code: ErrorCode, + pub error_json: String, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPutAppendDoneResp { + pub items: Vec, + pub error_code: ErrorCode, + pub error_json: String, + pub server_process_us: i64, +} +impl MsgPackSerializePart for BatchPutAppendDoneResp { + fn msg_id(&self) -> u32 { + MsgId::BatchPutAppendDoneResp as u32 + } +} +impl RPCReq for BatchPutAppendDoneReq { + type Resp = BatchPutAppendDoneResp; +} + // --- RPC for MemHolder KeepAlive --- #[derive(Default, Debug, Clone, Encode, Decode)] diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs index ccdf281..4992419 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs @@ -1,21 +1,28 @@ use super::{ CommittedSlotReplica, InflightPutAllocation, InflightPutCommitInfo, InflightPutInfo, InflightReplicaTaskInfo, KvReplicaBacking, KvRouteInfo, LocalReserveGrantInfo, - MasterKeyActivityCompletionGuard, MasterKvRouterView, OwnerHoldingGetInfo, - PreparedPutKeyReservationInfo, PutPlacementMode, ReservedCapacityReason, + MasterKeyActivityCompletionGuard, MasterKvRouterView, NodeCacheCapacityReservation, + OwnerHoldingGetInfo, PreparedPutKeyReservationInfo, PutPlacementMode, ReservedCapacityReason, msg_pack::{ - BatchPreparePutKeysReq, BatchPreparePutKeysResp, BatchPutDoneItemResp, BatchPutDoneReq, + BatchPreparePutKeysReq, BatchPreparePutKeysResp, BatchPutAppendDoneItemResp, + BatchPutAppendDoneReq, BatchPutAppendDoneResp, BatchPutAppendStartItemResp, + BatchPutAppendStartReq, BatchPutAppendStartResp, BatchPutDoneItemResp, BatchPutDoneReq, BatchPutDoneResp, BatchPutRevokeItemResp, BatchPutRevokeReq, BatchPutRevokeResp, BatchPutStartItemResp, BatchPutStartReq, BatchPutStartResp, BatchReleasePutKeyReservationsReq, BatchReleasePutKeyReservationsResp, GroupedBatchPutDoneReq, GroupedBatchPutDoneResp, PutAppendDoneReq, PutAppendDoneResp, - PutAppendRevokeReq, PutAppendRevokeResp, PutAppendStartReq, PutAppendStartResp, - PutAtomicGroup, PutDoneReq, PutDoneResp, PutRevokeReq, PutRevokeResp, PutStartReq, - PutStartResp, ReleaseLocalGrantReq, ReleaseLocalGrantResp, ReserveLocalGrantOutcome, - ReserveLocalGrantReq, ReserveLocalGrantResp, build_shared_put_atomic_group_assignments, + PutAppendRevokeReq, PutAppendRevokeResp, PutAppendStartOutcome, PutAppendStartReq, + PutAppendStartResp, PutAtomicGroup, PutDoneCommittedSlot, PutDoneReq, PutDoneResp, + PutRevokeReq, PutRevokeResp, PutStartReq, PutStartResp, ReleaseLocalGrantReq, + ReleaseLocalGrantResp, ReserveLocalGrantOutcome, ReserveLocalGrantReq, + ReserveLocalGrantResp, build_shared_put_atomic_group_assignments, }, + node_generation_is_current_live, placement::PutPlacementTarget, - route_maintenance::{RoutePublishEvent, enqueue_post_route_maintenance}, + publish_primary_route_tomb_fenced, publish_route_replica_tomb_fenced, + route_maintenance::{ + RoutePublishEvent, apply_post_route_maintenance_batch, enqueue_post_route_maintenance, + }, }; use crate::master_kv_router::OneKvNodesRoutes; use crate::master_kv_router::delete::DeleteKeyInfo; @@ -142,19 +149,55 @@ fn validate_put_start_source_node_override( Ok(()) } -fn current_route_needs_remote_replica( +fn current_route_append_outcome( route: &OneKvNodesRoutes, source_node_id: &NodeID, verify_put_id: PutIDForAKey, -) -> bool { - if route.put_id != verify_put_id { - return false; - } - route +) -> PutAppendStartOutcome { + let has_complete_remote = route .nodes_replicas .read() .values() - .all(|replica| replica.tomb_tag.is_tomb() || replica.node_id == *source_node_id) + .any(|replica| !replica.tomb_tag.is_tomb() && replica.node_id != *source_node_id); + classify_put_append_start_outcome(route.put_id == verify_put_id, has_complete_remote) +} + +fn classify_put_append_start_outcome( + current_identity: bool, + has_complete_remote: bool, +) -> PutAppendStartOutcome { + if !current_identity { + PutAppendStartOutcome::Obsolete + } else if has_complete_remote { + PutAppendStartOutcome::AlreadySatisfied + } else { + PutAppendStartOutcome::Scheduled + } +} + +#[cfg(test)] +mod append_start_outcome_tests { + use super::{PutAppendStartOutcome, classify_put_append_start_outcome}; + + #[test] + fn append_start_never_conflates_no_remote_with_already_satisfied() { + assert_eq!( + classify_put_append_start_outcome(true, false), + PutAppendStartOutcome::Scheduled + ); + assert_eq!( + classify_put_append_start_outcome(true, true), + PutAppendStartOutcome::AlreadySatisfied + ); + assert_eq!( + classify_put_append_start_outcome(false, true), + PutAppendStartOutcome::Obsolete + ); + assert_ne!( + PutAppendStartOutcome::RetryableNoSpace, + PutAppendStartOutcome::AlreadySatisfied + ); + } } fn append_current_route_replica_if_matching( @@ -162,6 +205,7 @@ fn append_current_route_replica_if_matching( key: &str, put_id: PutIDForAKey, node_id: NodeID, + target_tomb_tag: crate::master_seg_manager::NodeTombTag, allocation: Allocation, ) -> Option { let Some(one_kv_nodes_routes) = view.master_kv_router().inner().kv_routes.get(key) else { @@ -184,19 +228,9 @@ fn append_current_route_replica_if_matching( ); return None; } - let Some(tomb_tag) = view.master_seg_manager().get_node_tomb_tag(&node_id) else { + if !node_generation_is_current_live(view, &node_id, &target_tomb_tag) { tracing::warn!( - "append_current_route_replica_if_matching skipped because target node tomb-tag missing: key={} put_id=({},{}) node_id={}", - key, - put_id.0, - put_id.1, - node_id - ); - return None; - }; - if tomb_tag.is_tomb() { - tracing::warn!( - "append_current_route_replica_if_matching skipped because target node is tomb: key={} put_id=({},{}) node_id={}", + "append_current_route_replica_if_matching skipped because target generation departed: key={} put_id=({},{}) node_id={}", key, put_id.0, put_id.1, @@ -206,15 +240,50 @@ fn append_current_route_replica_if_matching( } let capacity_bytes = allocation.capcity(); let lease_id = one_kv_nodes_routes.lease_id; - one_kv_nodes_routes.nodes_replicas.write().insert( + let capacity_reservation = match lease_id { + Some(_) => match view.master_kv_router().reserve_node_cache_capacity( + &node_id, + &target_tomb_tag, + ReservedCapacityReason::LeaseBoundKv, + capacity_bytes, + ) { + Ok(reservation) => reservation, + Err(err) => { + tracing::warn!( + "append_current_route_replica_if_matching could not reserve lease-bound capacity: key={} put_id=({},{}) node_id={} err={}", + key, + put_id.0, + put_id.1, + node_id, + err, + ); + return None; + } + }, + None => None, + }; + let published = publish_route_replica_tomb_fenced( + &one_kv_nodes_routes, node_id.clone(), KvRouteInfo { node_id: node_id.clone(), backing: KvReplicaBacking::Allocation(Arc::new(allocation)), owner_local_indexed: false, - tomb_tag, + get_durable_reservation: None, + capacity_reservation, + tomb_tag: target_tomb_tag, }, ); + if !published { + tracing::warn!( + "append_current_route_replica_if_matching rejected by generation/live-replica fence: key={} put_id=({},{}) node_id={}", + key, + put_id.0, + put_id.1, + node_id + ); + return None; + } Some(RoutePublishEvent::replica_append( key.to_string(), put_id, @@ -270,6 +339,123 @@ fn allocate_from_node_local_segment( )) } +fn validate_put_done_committed_slot( + view: &MasterKvRouterView, + node_id: &NodeID, + slot: &PutDoneCommittedSlot, + expected_tomb_tag: Option<&crate::master_seg_manager::NodeTombTag>, +) -> msg_and_error::KvResult<(CommittedSlotReplica, crate::master_seg_manager::NodeTombTag)> { + let invalid = |detail: String| { + msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { detail }) + }; + if slot.slot_size == 0 || slot.len > slot.slot_size { + return Err(invalid(format!( + "invalid committed local slot geometry: grant_id={} slot_size={} len={}", + slot.grant_id, slot.slot_size, slot.len + ))); + } + let Some(grant) = view + .master_kv_router() + .inner() + .local_reserve_grants + .get(&slot.grant_id) + else { + return Err(invalid(format!( + "committed local slot references unknown grant_id={}", + slot.grant_id + ))); + }; + if grant.owner_node_id != *node_id { + return Err(invalid(format!( + "committed local slot owner mismatch: grant_id={} owner={} requester={}", + slot.grant_id, grant.owner_node_id, node_id + ))); + } + let tomb_tag = grant.tomb_tag.clone(); + if !node_generation_is_current_live(view, node_id, &tomb_tag) + || expected_tomb_tag.is_some_and(|expected| !expected.same_generation(&tomb_tag)) + { + return Err(invalid(format!( + "committed local slot belongs to a different/departed owner generation: grant_id={} requester={}", + slot.grant_id, node_id + ))); + } + + let grant_base = grant.allocation.base_addr(); + let grant_addr = grant_base + .checked_add(grant.allocation.addr()) + .ok_or_else(|| invalid("committed local slot grant address overflow".to_string()))?; + let slot_offset = slot + .slot_size + .checked_mul(u64::from(slot.slot_index)) + .ok_or_else(|| invalid("committed local slot offset overflow".to_string()))?; + let slot_end = slot_offset + .checked_add(slot.slot_size) + .ok_or_else(|| invalid("committed local slot end overflow".to_string()))?; + if slot_end > grant.allocation.capcity() { + return Err(invalid(format!( + "committed local slot is outside grant: grant_id={} slot_index={} slot_size={} grant_len={}", + slot.grant_id, + slot.slot_index, + slot.slot_size, + grant.allocation.capcity() + ))); + } + let expected_addr = grant_addr + .checked_add(slot_offset) + .ok_or_else(|| invalid("committed local slot address overflow".to_string()))?; + if slot.base_addr != grant_base || slot.addr != expected_addr { + return Err(invalid(format!( + "committed local slot address mismatch: grant_id={} expected_base={:#x} got_base={:#x} expected_addr={:#x} got_addr={:#x}", + slot.grant_id, grant_base, slot.base_addr, expected_addr, slot.addr + ))); + } + + Ok(( + CommittedSlotReplica { + owner_node_id: node_id.clone(), + grant_id: slot.grant_id, + slot_index: slot.slot_index, + slot_size: slot.slot_size, + addr: slot.addr, + len: slot.len, + base_addr: slot.base_addr, + }, + tomb_tag, + )) +} + +async fn prepare_route_state( + view: &MasterKvRouterView, + lease_id: Option, + key: &str, + put_id: PutIDForAKey, + node_id: &NodeID, + tomb_tag: &crate::master_seg_manager::NodeTombTag, + reservation_reason: Option, + target_cap_bytes: u64, +) -> msg_and_error::KvResult>> { + // Reserve first. If lease attachment fails, dropping this local token + // restores the exact generation-scoped counter automatically. Committed + // slots do not reserve again because their whole grant is already excluded. + let reservation = match reservation_reason { + Some(reason) => view.master_kv_router().reserve_node_cache_capacity( + node_id, + tomb_tag, + reason, + target_cap_bytes, + )?, + None => None, + }; + if let Some(lease_id) = lease_id { + view.master_lease_manager() + .attach_key(lease_id, key.to_string(), put_id) + .await + .map_err(|err| -> msg_and_error::KvError { err.into() })?; + } + Ok(reservation) +} + fn reserve_replica_task( view: &MasterKvRouterView, key: &str, @@ -286,7 +472,6 @@ fn reserve_replica_task( preferred_sub_cluster, len, &HashSet::new(), - false, true, ) } @@ -299,7 +484,6 @@ fn reserve_replica_task_excluding( preferred_sub_cluster: Option<&str>, len: u64, excluded_nodes: &HashSet, - demote_source_on_remote_complete: bool, protect_source_on_remote_complete: bool, ) -> msg_and_error::KvResult { let activity_lease = view.master_kv_router().reserve_inflight_replica_key(key)?; @@ -314,6 +498,19 @@ fn reserve_replica_task_excluding( preferred_sub_cluster, len, )?; + let Some(target_tomb_tag) = view + .master_seg_manager() + .get_allocation_tomb_tag(&target_node_id, &target_allocation) + else { + return Err(msg_and_error::KvError::Api( + msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "replica target generation changed during reservation: key={} put_id=({},{}) target_node_id={}", + key, put_id.0, put_id.1, target_node_id + ), + }, + )); + }; tracing::debug!( "replica task reserved: key={} put_id=({},{}) source_node_id={} target_node_id={} preferred_sub_cluster={:?} len={}", key, @@ -326,11 +523,11 @@ fn reserve_replica_task_excluding( ); Ok(InflightReplicaTaskInfo { node_id: target_node_id, + target_tomb_tag, source_node_id: source_node_id.clone(), key: key.to_string(), put_id, target_allocation: Arc::new(Mutex::new(Some(target_allocation))), - demote_source_on_remote_complete, protect_source_on_remote_complete, _activity_lease: activity_lease, }) @@ -347,41 +544,43 @@ async fn publish_completed_put_route( target_cap_bytes: u64, local_cache_holder_id: Option, ) -> MsgPack { - let mut old_one_kv_routes: Option> = None; - let mut inserted = false; - { - let mut one_kv_routes = view - .master_kv_router() - .inner() - .kv_routes - .entry(key.clone()) - .or_insert_with(|| { - inserted = true; - Arc::new(OneKvNodesRoutes { - put_id, - lease_id: lease_id_opt, - atomic_group: atomic_group.clone(), - nodes_replicas: RwLock::new(HashMap::new()), - get_durable_slots_used: AtomicU32::new(0), - }) - }); - if !inserted { - old_one_kv_routes = Some(one_kv_routes.clone()); - *one_kv_routes = Arc::new(OneKvNodesRoutes { - put_id, - lease_id: lease_id_opt, - atomic_group: atomic_group.clone(), - nodes_replicas: RwLock::new(HashMap::new()), - get_durable_slots_used: AtomicU32::new(0), + let publish_tag = completed_info.tomb_tag.clone(); + let new_route = Arc::new(OneKvNodesRoutes { + put_id, + lease_id: lease_id_opt, + atomic_group: atomic_group.clone(), + nodes_replicas: RwLock::new(HashMap::from([(node_id.clone(), completed_info)])), + get_durable_slots_used: AtomicU32::new(0), + }); + let old_one_kv_routes = match publish_primary_route_tomb_fenced( + &view.master_kv_router().inner().kv_routes, + &key, + new_route, + &publish_tag, + ) { + Ok(previous) => previous, + Err(()) => { + if let Some(lease_id) = lease_id_opt { + view.master_lease_manager() + .detach_key_if_version(lease_id, &key, put_id); + } + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "primary route publication rejected because target generation departed: key={} put_id=({},{}) node_id={}", + key, put_id.0, put_id.1, node_id + ), }); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), + raw_bytes: Vec::new(), + }; } - one_kv_routes - .nodes_replicas - .write() - .insert(node_id.clone(), completed_info); - } + }; if let Some(old) = old_one_kv_routes { + view.master_kv_router() + .remove_route_cache_entries_exact(&key, &old) + .await; if let Err(err) = view .master_kv_router() .inner() @@ -397,15 +596,15 @@ async fn publish_completed_put_route( } } - enqueue_post_route_maintenance( + apply_post_route_maintenance_batch( &view, - RoutePublishEvent::primary_put( + vec![RoutePublishEvent::primary_put( key.clone(), put_id, lease_id_opt, node_id.clone(), target_cap_bytes, - ), + )], ) .await; @@ -498,6 +697,7 @@ pub async fn handle_put_start( let mut src_allocation = Some(src_allocation); let finalize = |commit_node_id: NodeID, + target_tomb_tag: crate::master_seg_manager::NodeTombTag, response_node_id: NodeID, inflight_alloc: InflightPutAllocation, src_addr: u64, @@ -512,6 +712,7 @@ pub async fn handle_put_start( req_node_id: req_node_id.clone(), commit_info: InflightPutCommitInfo { node_id: commit_node_id, + target_tomb_tag, src_target_allocation: Arc::new(Mutex::new(Some(inflight_alloc))), replica_target: replica_target.clone(), }, @@ -618,6 +819,28 @@ pub async fn handle_put_start( let src = src_allocation .take() .expect("src_allocation must exist when finalizing local put"); + let Some(target_tomb_tag) = view + .master_seg_manager() + .get_allocation_tomb_tag(&node_id, &src) + else { + let err = msg_and_error::KvError::Api( + msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "local put target generation changed before start publication: key={} put_id=({},{}) node_id={}", + key, put_id.0, put_id.1, node_id + ), + }, + ); + return ( + (0, 0), + MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error( + &err, + ), + raw_bytes: Vec::new(), + }, + ); + }; let replica_target = if req.serialize_part.make_replica_task { match reserve_replica_task( &view, @@ -670,6 +893,7 @@ pub async fn handle_put_start( }; let fut = finalize( node_id.clone(), + target_tomb_tag, node_id, InflightPutAllocation::Local(src), abs, @@ -718,8 +942,31 @@ pub async fn handle_put_start( let src = src_allocation .take() .expect("src_allocation must exist when finalizing remote put"); + let Some(target_tomb_tag) = view + .master_seg_manager() + .get_allocation_tomb_tag(&node_id, &target_allocation) + else { + let err = msg_and_error::KvError::Api( + msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "remote put target generation changed before start publication: key={} put_id=({},{}) node_id={}", + key, put_id.0, put_id.1, node_id + ), + }, + ); + return ( + (0, 0), + MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error( + &err, + ), + raw_bytes: Vec::new(), + }, + ); + }; let fut = finalize( node_id.clone(), + target_tomb_tag, node_id, InflightPutAllocation::Remote { src, @@ -749,44 +996,9 @@ pub async fn handle_put_start( pub async fn handle_reserve_local_grant( view: MasterKvRouterView, - req: MsgPack, + _req: MsgPack, req_node_id: NodeID, ) -> (u64, MsgPack) { - if req.serialize_part.reclaim_before_grow - && req.serialize_part.slot_size != 0 - && req.serialize_part.required_free_slots != 0 - { - let reclaimed = crate::master_kv_router::reclaim::reclaim_owner_slots_for_reserve( - &view, - &req_node_id, - req.serialize_part.slot_size, - req.serialize_part.required_free_slots, - ) - .await; - tracing::info!( - "owner reserve proactive headroom reclaim: owner={} slot_size={} requested_slots={} reclaimed={}", - req_node_id, - req.serialize_part.slot_size, - req.serialize_part.required_free_slots, - reclaimed - ); - if reclaimed != 0 { - return ( - 0, - MsgPack { - serialize_part: ReserveLocalGrantResp { - outcome: ReserveLocalGrantOutcome::Reclaimed { - slot_size: req.serialize_part.slot_size, - reclaimed_slots: reclaimed, - }, - error_code: msg_and_error::OK, - ..Default::default() - }, - raw_bytes: Vec::new(), - }, - ); - } - } let allocation = match allocate_from_node_local_segment( &view, &req_node_id, @@ -795,85 +1007,6 @@ pub async fn handle_reserve_local_grant( ) { Ok(allocation) => allocation, Err(err) => { - let physical_no_space = matches!( - &err, - msg_and_error::KvError::Api(msg_and_error::ApiError::NoSpace { .. }) - ); - if physical_no_space - && req.serialize_part.slot_size != 0 - && req.serialize_part.required_free_slots != 0 - { - let requested_eviction_weight = req - .serialize_part - .slot_size - .saturating_mul(u64::from(req.serialize_part.required_free_slots)); - let pending_eviction_weight = view - .master_kv_router() - .eviction_reclaim_pending_weight(req_node_id.as_ref()); - let additional_eviction_weight = - requested_eviction_weight.saturating_sub(pending_eviction_weight); - if additional_eviction_weight != 0 { - if let Some(cache) = view - .master_kv_router() - .get_node_cache_controller(req_node_id.as_ref()) - { - let weighted_size_before = cache.weighted_size(); - let recoverable_evicted_weight = - view.master_kv_router().evict_recoverable_cache_weight( - req_node_id.as_ref(), - additional_eviction_weight, - ); - let fallback_requested_weight = - additional_eviction_weight.saturating_sub(recoverable_evicted_weight); - let fallback_evicted_weight = if view - .master_kv_router() - .owner_cache_allows_unrecoverable_reserve_pressure_eviction( - req_node_id.as_ref(), - ) { - cache.evict_some(fallback_requested_weight) - } else { - 0 - }; - tracing::info!( - "owner reserve requested moka eviction: owner={} slot_size={} requested_slots={} requested_weight={} pending_weight_before={} recoverable_evicted_weight={} fallback_requested_weight={} fallback_evicted_weight={} shortfall_weight={} weighted_size_before={} weighted_size_after={}", - req_node_id, - req.serialize_part.slot_size, - req.serialize_part.required_free_slots, - requested_eviction_weight, - pending_eviction_weight, - recoverable_evicted_weight, - fallback_requested_weight, - fallback_evicted_weight, - fallback_requested_weight.saturating_sub(fallback_evicted_weight), - weighted_size_before, - cache.weighted_size() - ); - } - } - let reclaimed = crate::master_kv_router::reclaim::reclaim_owner_slots_for_reserve( - &view, - &req_node_id, - req.serialize_part.slot_size, - req.serialize_part.required_free_slots, - ) - .await; - if reclaimed != 0 { - return ( - 0, - MsgPack { - serialize_part: ReserveLocalGrantResp { - outcome: ReserveLocalGrantOutcome::Reclaimed { - slot_size: req.serialize_part.slot_size, - reclaimed_slots: reclaimed, - }, - error_code: msg_and_error::OK, - ..Default::default() - }, - raw_bytes: Vec::new(), - }, - ); - } - } let resp: ReserveLocalGrantResp = crate::rpcresp_kvresult_convert::FromError::from_error(&err); return ( @@ -890,13 +1023,75 @@ pub async fn handle_reserve_local_grant( let grant_base_addr = allocation.base_addr(); let grant_abs_addr = grant_base_addr + allocation.addr(); let grant_len = allocation.capcity(); + let Some(tomb_tag) = view + .master_seg_manager() + .get_allocation_tomb_tag(&req_node_id, &allocation) + else { + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "local reserve grant generation changed before publication: owner={}", + req_node_id + ), + }); + let resp: ReserveLocalGrantResp = + crate::rpcresp_kvresult_convert::FromError::from_error(&err); + return ( + 0, + MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + }, + ); + }; + let capacity_reservation = match view.master_kv_router().reserve_node_cache_capacity( + &req_node_id, + &tomb_tag, + ReservedCapacityReason::LocalReserveGrant, + grant_len, + ) { + Ok(reservation) => reservation, + Err(err) => { + let resp: ReserveLocalGrantResp = + crate::rpcresp_kvresult_convert::FromError::from_error(&err); + return ( + 0, + MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + }, + ); + } + }; view.master_kv_router().install_local_reserve_grant( grant_id, LocalReserveGrantInfo { owner_node_id: req_node_id.clone(), + tomb_tag: tomb_tag.clone(), allocation, + capacity_reservation, }, ); + if tomb_tag.is_tomb() { + // MemberLeft may mark the shared tag between allocation and map + // insertion. Remove the exact grant before returning so the old + // allocator cannot be pinned after its cleanup snapshot. + drop(view.master_kv_router().take_local_reserve_grant(grant_id)); + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "local reserve grant owner departed during publication: owner={} grant_id={}", + req_node_id, grant_id + ), + }); + let resp: ReserveLocalGrantResp = + crate::rpcresp_kvresult_convert::FromError::from_error(&err); + return ( + 0, + MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + }, + ); + } ( grant_id, @@ -952,6 +1147,23 @@ pub async fn handle_release_local_grant( }; } + if !node_generation_is_current_live(&view, &req_node_id, &grant.tomb_tag) { + // Do not reinsert an old-generation allocation: MemberLeft cleanup may + // already have taken its snapshot. Dropping it here is the exact + // generation-safe release. + drop(grant); + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { + detail: format!( + "release_local_grant references a departed owner generation: grant_id={} requester_node_id={}", + grant_id, req_node_id + ), + }); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), + raw_bytes: Vec::new(), + }; + } + drop(grant); MsgPack { serialize_part: ReleaseLocalGrantResp::default(), @@ -1123,7 +1335,7 @@ async fn handle_put_done_with_resolved_group( let put_id = req.serialize_part.put_id; let lease_id_opt = req.serialize_part.lease_id; let full_put_id: (String, u64, u32) = (req.serialize_part.key.clone(), put_id.0, put_id.1); - let local_cache_holder_id: Option; + let mut local_cache_holder_id: Option; let atomic_group = if let Some(group) = resolved_atomic_group { Some(group) } else { @@ -1161,6 +1373,7 @@ async fn handle_put_done_with_resolved_group( .as_ref() .map(|target| MasterKeyActivityCompletionGuard::new(target._activity_lease.clone())); let node_id = commit_info.node_id; + let tomb_tag = commit_info.target_tomb_tag.clone(); let Some(allocs) = commit_info.src_target_allocation.lock().take() else { tracing::warn!( "Put operation with put_id {:?} not found for completion", @@ -1178,14 +1391,14 @@ async fn handle_put_done_with_resolved_group( }; }; - let Some(tomb_tag) = view.master_seg_manager().get_node_tomb_tag(&node_id) else { - tracing::warn!( - "Put operation with put_id {:?} not found for completion", + if !node_generation_is_current_live(&view, &node_id, &tomb_tag) { + tracing::info!( + "Put operation with put_id {:?} belongs to a departed target generation, skip", put_id ); let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { detail: format!( - "Put operation with put_id {:?} not found for completion", + "Put operation with put_id {:?} belongs to a departed target generation", put_id ), }); @@ -1193,205 +1406,153 @@ async fn handle_put_done_with_resolved_group( serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), raw_bytes: Vec::new(), }; - }; + } - if tomb_tag.is_tomb() { - tracing::info!("Put operation with put_id {:?} is tomb, skip", put_id); + let route_committed_slot = req.serialize_part.committed_slot.clone(); + if req.serialize_part.publish_local_cache + && (!matches!(&allocs, InflightPutAllocation::Local(_)) + || route_committed_slot.is_some()) + { let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { - detail: format!("Put operation with put_id {:?} is tomb, skip", put_id), + detail: format!( + "publish_local_cache requires owner-local allocation backing; key={} put_id=({},{})", + key, put_id.0, put_id.1 + ), }); return MsgPack { serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), raw_bytes: Vec::new(), }; } - - let route_committed_slot = req.serialize_part.committed_slot.clone(); let (target_cap_bytes, completed_info, local_cache_publish_supported) = match allocs { - InflightPutAllocation::Local(mut target_allocation) => { + InflightPutAllocation::Local(target_allocation) => { if let Some(slot) = route_committed_slot { - let target_cap_bytes = slot.slot_size; - if let Some(lease_id) = lease_id_opt { - if let Err(e) = view - .master_lease_manager() - .attach_key(lease_id, key.clone(), put_id) - .await - { - let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = - e.into(); + let (committed_slot, slot_tomb_tag) = match validate_put_done_committed_slot( + &view, + &node_id, + &slot, + Some(&tomb_tag), + ) { + Ok(validated) => validated, + Err(err) => { return MsgPack { serialize_part: - crate::rpcresp_kvresult_convert::FromError::from_error(&kv_err), + crate::rpcresp_kvresult_convert::FromError::from_error(&err), raw_bytes: Vec::new(), }; } - if let Err(e) = view.master_kv_router().adjust_node_cache_reserved_capacity( - node_id.as_ref(), - ReservedCapacityReason::LeaseBoundKv, - target_cap_bytes as i64, - ) { - let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = - e.into(); + }; + let target_cap_bytes = committed_slot.slot_size; + let capacity_reservation = match prepare_route_state( + &view, + lease_id_opt, + &key, + put_id, + &node_id, + &slot_tomb_tag, + None, + target_cap_bytes, + ) + .await + { + Ok(reservation) => reservation, + Err(err) => { return MsgPack { serialize_part: - crate::rpcresp_kvresult_convert::FromError::from_error(&kv_err), + crate::rpcresp_kvresult_convert::FromError::from_error(&err), raw_bytes: Vec::new(), }; } - } + }; drop(target_allocation); ( target_cap_bytes, KvRouteInfo { node_id: node_id.clone(), - backing: KvReplicaBacking::CommittedSlot(CommittedSlotReplica { - owner_node_id: node_id.clone(), - grant_id: slot.grant_id, - slot_index: slot.slot_index, - slot_size: slot.slot_size, - addr: slot.addr, - len: slot.len, - base_addr: slot.base_addr, - }), + backing: KvReplicaBacking::CommittedSlot(committed_slot), owner_local_indexed: true, - tomb_tag, + get_durable_reservation: None, + capacity_reservation, + tomb_tag: slot_tomb_tag, }, false, ) } else { let target_cap_bytes = target_allocation.capcity(); - if let Some(lease_id) = lease_id_opt { - if let Err(e) = view - .master_lease_manager() - .attach_key(lease_id, key.clone(), put_id) - .await - { - let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = - e.into(); - return MsgPack { - serialize_part: - crate::rpcresp_kvresult_convert::FromError::from_error(&kv_err), - raw_bytes: Vec::new(), - }; - } - if let Err(e) = view.master_kv_router().adjust_node_cache_reserved_capacity( - node_id.as_ref(), - ReservedCapacityReason::LeaseBoundKv, - target_cap_bytes as i64, - ) { - let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = - e.into(); + let reservation_reason = if req.serialize_part.publish_local_cache { + Some(ReservedCapacityReason::OwnerIndexedAllocation) + } else if lease_id_opt.is_some() { + Some(ReservedCapacityReason::LeaseBoundKv) + } else { + None + }; + let capacity_reservation = match prepare_route_state( + &view, + lease_id_opt, + &key, + put_id, + &node_id, + &tomb_tag, + reservation_reason, + target_cap_bytes, + ) + .await + { + Ok(reservation) => reservation, + Err(err) => { return MsgPack { serialize_part: - crate::rpcresp_kvresult_convert::FromError::from_error(&kv_err), + crate::rpcresp_kvresult_convert::FromError::from_error(&err), raw_bytes: Vec::new(), }; } - let view_clone = view.clone(); - let node_id_string = node_id.as_ref().to_string(); - target_allocation.set_on_drop(move || { - // The allocation can be released while FrameworkInner itself is - // being dropped. At that point the weak module view can no longer - // be upgraded and restoring the runtime Moka reservation is both - // impossible and unnecessary. Keep an upgrade guard alive for the - // whole callback so dependency access cannot race the final drop. - let Some(_view_guard) = view_clone.try_upgrade() else { - return; - }; - if let Err(e) = view_clone - .master_kv_router() - .adjust_node_cache_reserved_capacity( - &node_id_string, - ReservedCapacityReason::LeaseBoundKv, - -(target_cap_bytes as i64), - ) - { - tracing::warn!( - "Failed to restore moka capacity on drop: node_id={}, bytes={}, err={}", - node_id_string, - target_cap_bytes, - e - ); - } - }); - } + }; ( target_cap_bytes, KvRouteInfo { node_id: node_id.clone(), backing: KvReplicaBacking::Allocation(Arc::new(target_allocation)), owner_local_indexed: req.serialize_part.publish_local_cache, + get_durable_reservation: None, + capacity_reservation, tomb_tag, }, true, ) } } - InflightPutAllocation::Remote { - src: _src, - mut target, - } => { + InflightPutAllocation::Remote { src: _src, target } => { let target_cap_bytes = target.capcity(); - if let Some(lease_id) = lease_id_opt { - if let Err(e) = view - .master_lease_manager() - .attach_key(lease_id, key.clone(), put_id) - .await - { - let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = - e.into(); - return MsgPack { - serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error( - &kv_err, - ), - raw_bytes: Vec::new(), - }; - } - if let Err(e) = view.master_kv_router().adjust_node_cache_reserved_capacity( - node_id.as_ref(), - ReservedCapacityReason::LeaseBoundKv, - target_cap_bytes as i64, - ) { - let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = - e.into(); + let capacity_reservation = match prepare_route_state( + &view, + lease_id_opt, + &key, + put_id, + &node_id, + &tomb_tag, + lease_id_opt.map(|_| ReservedCapacityReason::LeaseBoundKv), + target_cap_bytes, + ) + .await + { + Ok(reservation) => reservation, + Err(err) => { return MsgPack { serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error( - &kv_err, + &err, ), raw_bytes: Vec::new(), }; } - let view_clone = view.clone(); - let node_id_string = node_id.as_ref().to_string(); - target.set_on_drop(move || { - // See the equivalent local-placement callback above. A final framework - // teardown must not call back into the module currently being destroyed. - let Some(_view_guard) = view_clone.try_upgrade() else { - return; - }; - if let Err(e) = view_clone - .master_kv_router() - .adjust_node_cache_reserved_capacity( - &node_id_string, - ReservedCapacityReason::LeaseBoundKv, - -(target_cap_bytes as i64), - ) - { - tracing::warn!( - "Failed to restore moka capacity on drop: node_id={}, bytes={}, err={}", - node_id_string, - target_cap_bytes, - e - ); - } - }); - } + }; ( target_cap_bytes, KvRouteInfo { node_id: node_id.clone(), backing: KvReplicaBacking::Allocation(Arc::new(target)), owner_local_indexed: false, + get_durable_reservation: None, + capacity_reservation, tomb_tag, }, false, @@ -1399,42 +1560,36 @@ async fn handle_put_done_with_resolved_group( } InflightPutAllocation::LocalCommittedSlot(slot) => { let target_cap_bytes = slot.slot_size; - if let Some(lease_id) = lease_id_opt { - if let Err(e) = view - .master_lease_manager() - .attach_key(lease_id, key.clone(), put_id) - .await - { - let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = - e.into(); - return MsgPack { - serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error( - &kv_err, - ), - raw_bytes: Vec::new(), - }; - } - if let Err(e) = view.master_kv_router().adjust_node_cache_reserved_capacity( - node_id.as_ref(), - ReservedCapacityReason::LeaseBoundKv, - target_cap_bytes as i64, - ) { - let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = - e.into(); + let capacity_reservation = match prepare_route_state( + &view, + lease_id_opt, + &key, + put_id, + &node_id, + &tomb_tag, + None, + target_cap_bytes, + ) + .await + { + Ok(reservation) => reservation, + Err(err) => { return MsgPack { serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error( - &kv_err, + &err, ), raw_bytes: Vec::new(), }; } - } + }; ( target_cap_bytes, KvRouteInfo { node_id: node_id.clone(), backing: KvReplicaBacking::CommittedSlot(slot), owner_local_indexed: true, + get_durable_reservation: None, + capacity_reservation, tomb_tag, }, false, @@ -1490,41 +1645,48 @@ async fn handle_put_done_with_resolved_group( None }; - // Insert into kv_routes with replica support - let mut old_one_kv_routes: Option> = None; - let mut inserted = false; - { - let mut one_kv_routes = view - .master_kv_router() - .inner() - .kv_routes - .entry(key.clone()) - .or_insert_with(|| { - inserted = true; - Arc::new(OneKvNodesRoutes { - put_id, - lease_id: lease_id_opt, - atomic_group: atomic_group.clone(), - nodes_replicas: RwLock::new(HashMap::new()), - get_durable_slots_used: AtomicU32::new(0), - }) - }); - // we need to take out old one_kv_routes if it is not inserted - if !inserted { - old_one_kv_routes = Some(one_kv_routes.clone()); - *one_kv_routes = Arc::new(OneKvNodesRoutes { - put_id, - lease_id: lease_id_opt, - atomic_group: atomic_group.clone(), - nodes_replicas: RwLock::new(HashMap::new()), - get_durable_slots_used: AtomicU32::new(0), - }); + // Publish the primary route under the node-generation fence. This + // closes the gap where MemberLeft marked/snapshotted routes between a + // pre-check and a later DashMap insert. + let publish_tag = completed_info.tomb_tag.clone(); + let new_route = Arc::new(OneKvNodesRoutes { + put_id, + lease_id: lease_id_opt, + atomic_group: atomic_group.clone(), + nodes_replicas: RwLock::new(HashMap::from([(node_id.clone(), completed_info)])), + get_durable_slots_used: AtomicU32::new(0), + }); + let old_one_kv_routes = match publish_primary_route_tomb_fenced( + &view.master_kv_router().inner().kv_routes, + &key, + new_route, + &publish_tag, + ) { + Ok(previous) => previous, + Err(()) => { + if let Some(lease_id) = lease_id_opt { + view.master_lease_manager() + .detach_key_if_version(lease_id, &key, put_id); + } + if let Some(holder_id) = local_cache_holder_id.take() { + view.master_kv_router().inner().get_holding.remove( + &crate::memholder::NodeHolderKey::new(node_id.to_string(), holder_id), + ); + } + let err = msg_and_error::KvError::Api( + msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "primary route publication rejected because target generation departed: key={} put_id=({},{}) node_id={}", + key, put_id.0, put_id.1, node_id + ), + }, + ); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), + raw_bytes: Vec::new(), + }; } - one_kv_routes - .nodes_replicas - .write() - .insert(node_id.clone(), completed_info); - } + }; if let Some(replica_target) = commit_info.replica_target { view.master_kv_router() @@ -1546,6 +1708,9 @@ async fn handle_put_done_with_resolved_group( } if let Some(old) = old_one_kv_routes { + view.master_kv_router() + .remove_route_cache_entries_exact(&key, &old) + .await; if let Err(err) = view .master_kv_router() .inner() @@ -1598,33 +1763,18 @@ async fn handle_put_done_with_resolved_group( } }; let node_id = req_node_id; - let Some(tomb_tag) = view.master_seg_manager().get_node_tomb_tag(&node_id) else { - let err = msg_and_error::KvError::Api( - msg_and_error::ApiError::InvalidPutMasterState { - detail: format!( - "local-first put_done node tomb tag missing: key={} put_id=({},{}) node_id={}", - key, put_id.0, put_id.1, node_id - ), - }, - ); - return MsgPack { - serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), - raw_bytes: Vec::new(), - }; - }; - if tomb_tag.is_tomb() { - let err = - msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { - detail: format!( - "local-first put_done node is tomb: key={} put_id=({},{}) node_id={}", - key, put_id.0, put_id.1, node_id - ), - }); - return MsgPack { - serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), - raw_bytes: Vec::new(), + let (committed_slot, tomb_tag) = + match validate_put_done_committed_slot(&view, &node_id, &slot, None) { + Ok(validated) => validated, + Err(err) => { + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error( + &err, + ), + raw_bytes: Vec::new(), + }; + } }; - } if req.serialize_part.publish_local_cache { let err = msg_and_error::KvError::Api( msg_and_error::ApiError::InvalidPutMasterState { @@ -1639,47 +1789,35 @@ async fn handle_put_done_with_resolved_group( raw_bytes: Vec::new(), }; } - let target_cap_bytes = slot.slot_size; - if let Some(lease_id) = lease_id_opt { - if let Err(e) = view - .master_lease_manager() - .attach_key(lease_id, key.clone(), put_id) - .await - { - let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = e.into(); - return MsgPack { - serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error( - &kv_err, - ), - raw_bytes: Vec::new(), - }; - } - if let Err(e) = view.master_kv_router().adjust_node_cache_reserved_capacity( - node_id.as_ref(), - ReservedCapacityReason::LeaseBoundKv, - target_cap_bytes as i64, - ) { - let kv_err: crate::rpcresp_kvresult_convert::msg_and_error::KvError = e.into(); + let target_cap_bytes = committed_slot.slot_size; + let capacity_reservation = match prepare_route_state( + &view, + lease_id_opt, + &key, + put_id, + &node_id, + &tomb_tag, + None, + target_cap_bytes, + ) + .await + { + Ok(reservation) => reservation, + Err(err) => { return MsgPack { serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error( - &kv_err, + &err, ), raw_bytes: Vec::new(), }; } - } + }; let completed_info = KvRouteInfo { node_id: node_id.clone(), - backing: KvReplicaBacking::CommittedSlot(CommittedSlotReplica { - owner_node_id: node_id.clone(), - grant_id: slot.grant_id, - slot_index: slot.slot_index, - slot_size: slot.slot_size, - addr: slot.addr, - len: slot.len, - base_addr: slot.base_addr, - }), + backing: KvReplicaBacking::CommittedSlot(committed_slot), owner_local_indexed: true, + get_durable_reservation: None, + capacity_reservation, tomb_tag, }; return publish_completed_put_route( @@ -1957,7 +2095,7 @@ pub async fn handle_grouped_batch_put_done( } } -pub async fn handle_put_append_start( +async fn handle_put_append_start_inner( view: MasterKvRouterView, req: MsgPack, req_node_id: NodeID, @@ -1970,11 +2108,11 @@ pub async fn handle_put_append_start( .kv_routes .get(&key) .map(|route| route.clone()); - let current_route_still_needs_remote = route_snapshot + let current_outcome = route_snapshot .as_ref() - .map(|route| current_route_needs_remote_replica(route, &req_node_id, put_id)) - .unwrap_or(false); - if !current_route_still_needs_remote { + .map(|route| current_route_append_outcome(route, &req_node_id, put_id)) + .unwrap_or(PutAppendStartOutcome::Obsolete); + if current_outcome != PutAppendStartOutcome::Scheduled { if let Some(inflight) = view .master_kv_router() .inner() @@ -1984,14 +2122,9 @@ pub async fn handle_put_append_start( { inflight._activity_lease.release_now(); } - if req.serialize_part.demote_source_on_remote_complete { - view.master_kv_router() - .demote_owner_hot_cohort_if_recoverable(req_node_id.as_ref(), &key, put_id) - .await; - } return MsgPack { serialize_part: PutAppendStartResp { - scheduled: false, + outcome: current_outcome, error_code: msg_and_error::OK, error_json: String::new(), ..Default::default() @@ -2031,7 +2164,6 @@ pub async fn handle_put_append_start( req.serialize_part.preferred_sub_cluster.as_deref(), req.serialize_part.len, &excluded_nodes, - req.serialize_part.demote_source_on_remote_complete, req.serialize_part.protect_source_on_remote_complete, ) { Ok(reservation) => reservation, @@ -2055,7 +2187,7 @@ pub async fn handle_put_append_start( ); return MsgPack { serialize_part: PutAppendStartResp { - scheduled: false, + outcome: PutAppendStartOutcome::RetryableNoSpace, error_code: msg_and_error::OK, error_json: String::new(), ..Default::default() @@ -2105,7 +2237,7 @@ pub async fn handle_put_append_start( MsgPack { serialize_part: PutAppendStartResp { - scheduled: true, + outcome: PutAppendStartOutcome::Scheduled, node_id: inflight.node_id.clone().into(), target_addr, target_base_addr, @@ -2118,6 +2250,62 @@ pub async fn handle_put_append_start( } } +pub async fn handle_put_append_start( + view: MasterKvRouterView, + req: MsgPack, + req_node_id: NodeID, +) -> MsgPack { + handle_put_append_start_inner(view, req, req_node_id).await +} + +pub async fn handle_batch_put_append_start( + view: MasterKvRouterView, + req: MsgPack, + req_node_id: NodeID, +) -> MsgPack { + let mut items = Vec::with_capacity(req.serialize_part.items.len()); + for item in req.serialize_part.items { + let key = item.key.clone(); + let put_id = item.put_id; + let resp = handle_put_append_start_inner( + view.clone(), + MsgPack { + serialize_part: PutAppendStartReq { + key, + put_id, + len: item.len, + preferred_sub_cluster: item.preferred_sub_cluster, + protect_source_on_remote_complete: item.protect_source_on_remote_complete, + }, + raw_bytes: Vec::new(), + }, + req_node_id.clone(), + ) + .await; + let part = resp.serialize_part; + items.push(BatchPutAppendStartItemResp { + key: item.key, + put_id: item.put_id, + outcome: part.outcome, + node_id: part.node_id, + target_addr: part.target_addr, + target_base_addr: part.target_base_addr, + len: part.len, + error_code: part.error_code, + error_json: part.error_json, + }); + } + MsgPack { + serialize_part: BatchPutAppendStartResp { + items, + error_code: msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + }, + raw_bytes: Vec::new(), + } +} + pub async fn handle_put_append_revoke( view: MasterKvRouterView, req: MsgPack, @@ -2142,7 +2330,7 @@ pub async fn handle_put_append_revoke( } } -pub async fn handle_put_append_done( +async fn handle_put_append_done_inner( view: MasterKvRouterView, req: MsgPack, ) -> MsgPack { @@ -2185,17 +2373,13 @@ pub async fn handle_put_append_done( &key, inflight.put_id, inflight.node_id, + inflight.target_tomb_tag, allocation, ); let appended = published.is_some(); if let Some(event) = published { enqueue_post_route_maintenance(&view, event).await; } - if inflight.demote_source_on_remote_complete { - view.master_kv_router() - .demote_owner_hot_cohort_if_recoverable(inflight.source_node_id.as_ref(), &key, put_id) - .await; - } MsgPack { serialize_part: PutAppendDoneResp { appended, @@ -2206,3 +2390,46 @@ pub async fn handle_put_append_done( raw_bytes: Vec::new(), } } + +pub async fn handle_put_append_done( + view: MasterKvRouterView, + req: MsgPack, +) -> MsgPack { + handle_put_append_done_inner(view, req).await +} + +pub async fn handle_batch_put_append_done( + view: MasterKvRouterView, + req: MsgPack, +) -> MsgPack { + let mut items = Vec::with_capacity(req.serialize_part.items.len()); + for item in req.serialize_part.items { + let key = item.key.clone(); + let put_id = item.put_id; + let resp = handle_put_append_done_inner( + view.clone(), + MsgPack { + serialize_part: PutAppendDoneReq { key, put_id }, + raw_bytes: Vec::new(), + }, + ) + .await; + let part = resp.serialize_part; + items.push(BatchPutAppendDoneItemResp { + key: item.key, + put_id: item.put_id, + appended: part.appended, + error_code: part.error_code, + error_json: part.error_json, + }); + } + MsgPack { + serialize_part: BatchPutAppendDoneResp { + items, + error_code: msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + }, + raw_bytes: Vec::new(), + } +} diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs index 8a4223c..39f2ee7 100644 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs @@ -1,18 +1,19 @@ use super::{KvReplicaBacking, MasterKvRouterView, NodeValueReplicaDesc}; use crate::cluster_manager::{NodeID, NodeIDString}; use crate::master_kv_router::msg_pack::{ - BatchOwnerReclaimReq, OwnerReclaimBacking, OwnerReclaimItem, OwnerReclaimItemResp, - OwnerReclaimItemState, OwnerReclaimPhase, OwnerReclaimReason, + BatchEvictOwnerSourceReq, BatchEvictOwnerSourceResp, BatchOwnerReclaimReq, OwnerReclaimBacking, + OwnerReclaimItem, OwnerReclaimItemResp, OwnerReclaimItemState, OwnerReclaimPhase, + OwnerReclaimReason, OwnerSourceEvictionCohort, OwnerSourceEvictionCohortResp, + OwnerSourceEvictionOutcome, }; -use crate::memholder::MemholderManagerTrait; use crate::p2p::msg_pack::{MIN_EXPLICIT_RPC_TIMEOUT_SECS, MsgPack, RPCCaller}; -use crate::rpcresp_kvresult_convert::msg_and_error::OK; +use crate::rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, OK}; use limit_thirdparty::tokio; use std::collections::HashMap; use std::collections::HashSet; -use std::future::Future; +use std::sync::Arc; use std::sync::atomic::Ordering; -use std::time::{Duration, Instant}; +use std::time::Duration; const OWNER_RECLAIM_RPC_TIMEOUT: Duration = Duration::from_secs(MIN_EXPLICIT_RPC_TIMEOUT_SECS); const OWNER_RECLAIM_MAX_BATCH: usize = 256; @@ -64,14 +65,532 @@ mod timeout_contract_tests { } } +#[cfg(test)] +mod cohort_transaction_tests { + use super::*; + use crate::master_kv_router::msg_pack::{ + OwnerSourceEvictionMember, PutAtomicGroup, PutAtomicGroupMember, + }; + use crate::master_kv_router::{ + CommittedSlotReplica, KvRouteInfo, MasterKeyActivityKind, MasterKeyActivityTable, + OneKvNodesRoutes, + }; + use crate::master_seg_manager::NodeTombTag; + use parking_lot::RwLock; + use std::collections::HashMap; + use std::sync::Arc; + use std::sync::atomic::AtomicU32; + + fn item(key: &str, epoch: u64) -> OwnerReclaimItem { + OwnerReclaimItem { + key: key.to_string(), + put_id: (7, epoch as u32), + epoch, + backing: OwnerReclaimBacking::CommittedSlot { + grant_id: 1, + slot_index: epoch as u32, + slot_size: 4096, + }, + reason: OwnerReclaimReason::OwnerCapacityEviction, + } + } + + #[test] + fn cohort_master_fences_roll_back_all_members_when_one_is_busy() { + let activity = Arc::new(MasterKeyActivityTable::default()); + let items = vec![item("rank0", 1), item("rank1", 2)]; + let _busy = activity + .reserve("rank1", MasterKeyActivityKind::Get, false) + .unwrap(); + + assert!(try_install_cohort_master_fences(&activity, &items).is_err()); + assert!(!activity.has_reclaim("rank0")); + assert!(!activity.has_reclaim("rank1")); + } + + #[test] + fn cohort_master_fences_install_and_clear_as_one_set() { + let activity = Arc::new(MasterKeyActivityTable::default()); + let items = vec![item("rank0", 1), item("rank1", 2)]; + + try_install_cohort_master_fences(&activity, &items).unwrap(); + assert!(activity.has_reclaim("rank0")); + assert!(activity.has_reclaim("rank1")); + for item in &items { + assert!(activity.clear_reclaim(item)); + } + } + + #[test] + fn master_capacity_origin_rejects_committed_slot_backing() { + let backing = KvReplicaBacking::CommittedSlot(CommittedSlotReplica { + owner_node_id: "gpu0".to_string().into(), + grant_id: 1, + slot_index: 2, + slot_size: 4096, + addr: 0, + len: 4096, + base_addr: 0, + }); + assert_eq!( + master_allocation_capacity_weight(&backing), + Err(MasterCapacityPlanError::CommittedSlot), + ); + } + + fn source_member( + key: &str, + put_id: (u64, u32), + grant_id: u64, + slot_index: u32, + ) -> OwnerSourceEvictionMember { + OwnerSourceEvictionMember { + key: key.to_string(), + put_id, + backing: OwnerReclaimBacking::CommittedSlot { + grant_id, + slot_index, + slot_size: 4096, + }, + } + } + + fn source_route( + owner: &NodeID, + member: &OwnerSourceEvictionMember, + atomic_group: Option>, + include_cpu_replica: bool, + ) -> Arc { + let OwnerReclaimBacking::CommittedSlot { + grant_id, + slot_index, + slot_size, + } = &member.backing + else { + unreachable!() + }; + let owner_replica = KvRouteInfo { + node_id: owner.clone(), + backing: KvReplicaBacking::CommittedSlot(CommittedSlotReplica { + owner_node_id: owner.clone(), + grant_id: *grant_id, + slot_index: *slot_index, + slot_size: *slot_size, + addr: 0, + len: *slot_size, + base_addr: 0, + }), + owner_local_indexed: true, + get_durable_reservation: None, + capacity_reservation: None, + tomb_tag: NodeTombTag::new(), + }; + let mut replicas = HashMap::from([(owner.clone(), owner_replica)]); + if include_cpu_replica { + let cpu: NodeID = "cpu0".to_string().into(); + replicas.insert( + cpu.clone(), + KvRouteInfo { + node_id: cpu.clone(), + backing: KvReplicaBacking::CommittedSlot(CommittedSlotReplica { + owner_node_id: cpu, + grant_id: 900 + *grant_id, + slot_index: *slot_index, + slot_size: *slot_size, + addr: 0, + len: *slot_size, + base_addr: 0, + }), + owner_local_indexed: false, + get_durable_reservation: None, + capacity_reservation: None, + tomb_tag: NodeTombTag::new(), + }, + ); + } + Arc::new(OneKvNodesRoutes { + put_id: member.put_id, + lease_id: None, + atomic_group, + nodes_replicas: RwLock::new(replicas), + get_durable_slots_used: AtomicU32::new(0), + }) + } + + fn source_reclaim_item(member: &OwnerSourceEvictionMember) -> OwnerReclaimItem { + OwnerReclaimItem { + key: member.key.clone(), + put_id: member.put_id, + epoch: 1, + backing: member.backing.clone(), + reason: OwnerReclaimReason::OwnerCapacityEviction, + } + } + + #[test] + fn exact_source_plan_accepts_with_or_without_a_cpu_replica() { + let owner: NodeID = "gpu0".to_string().into(); + let member = source_member("single", (10, 1), 7, 3); + let cohort = OwnerSourceEvictionCohort { + members: vec![member.clone()], + }; + + for include_cpu_replica in [false, true] { + let route = source_route(&owner, &member, None, include_cpu_replica); + let plan = plan_exact_owner_source_cohort_with(&owner, &cohort, &|key| { + (key == "single").then(|| route.clone()) + }); + match plan { + OwnerSourceCohortPlan::Ready { + members, + all_sources_present, + } => { + assert!(all_sources_present); + assert_eq!(members.len(), 1); + assert_eq!(members[0].key, "single"); + assert_eq!(members[0].expected_backing, Some(member.backing.clone())); + } + _ => panic!("exact current owner source must be accepted"), + } + } + } + + #[test] + fn exact_source_removal_deletes_only_gpu_when_cpu_exists_and_last_route_otherwise() { + let owner: NodeID = "gpu0".to_string().into(); + let member = source_member("with-cpu", (10, 2), 7, 4); + let routes = dashmap::DashMap::new(); + routes.insert( + member.key.clone(), + source_route(&owner, &member, None, true), + ); + let removed = + remove_exact_owner_source_route(&routes, &owner, &source_reclaim_item(&member)) + .expect("exact GPU source must be removed"); + assert!(!removed.removed_last_route); + let remaining = routes.get(&member.key).expect("CPU route must remain"); + assert!(!remaining.nodes_replicas.read().contains_key(&owner)); + assert!(remaining.nodes_replicas.read().contains_key("cpu0")); + + let last = source_member("last", (10, 3), 7, 5); + routes.insert(last.key.clone(), source_route(&owner, &last, None, false)); + let removed = remove_exact_owner_source_route(&routes, &owner, &source_reclaim_item(&last)) + .expect("last exact GPU source must be removed"); + assert!(removed.removed_last_route); + assert!(!routes.contains_key(&last.key)); + + let stale = source_member("stale", (10, 4), 8, 6); + routes.insert(stale.key.clone(), source_route(&owner, &stale, None, false)); + let wrong_identity = source_member("stale", stale.put_id, 999, 6); + assert!( + remove_exact_owner_source_route( + &routes, + &owner, + &source_reclaim_item(&wrong_identity), + ) + .is_none() + ); + assert!(routes.contains_key(&stale.key)); + } + + #[test] + fn partial_source_absence_is_replay_only_and_all_absent_is_completed() { + let owner: NodeID = "gpu0".to_string().into(); + let a = source_member("a", (11, 0), 8, 0); + let b = source_member("b", (11, 1), 8, 1); + let cohort = OwnerSourceEvictionCohort { + members: vec![a.clone(), b.clone()], + }; + let group = Arc::new(PutAtomicGroup { + members: vec![ + PutAtomicGroupMember { + key: a.key.clone(), + put_id: a.put_id, + }, + PutAtomicGroupMember { + key: b.key.clone(), + put_id: b.put_id, + }, + ], + }); + let route_a = source_route(&owner, &a, Some(group), false); + + match plan_exact_owner_source_cohort_with(&owner, &cohort, &|key| { + (key == "a").then(|| route_a.clone()) + }) { + OwnerSourceCohortPlan::Ready { + all_sources_present, + .. + } => assert!(!all_sources_present), + _ => panic!("a partially removed accepted cohort must be recognized as replay-only"), + } + assert!(matches!( + plan_exact_owner_source_cohort_with(&owner, &cohort, &|_| None), + OwnerSourceCohortPlan::Completed(_) + )); + } + + #[test] + fn one_stale_or_inconsistent_member_rejects_the_whole_source_cohort() { + let owner: NodeID = "gpu0".to_string().into(); + let a = source_member("a", (12, 0), 9, 0); + let b = source_member("b", (12, 1), 9, 1); + let cohort = OwnerSourceEvictionCohort { + members: vec![a.clone(), b.clone()], + }; + let group = Arc::new(PutAtomicGroup { + members: vec![ + PutAtomicGroupMember { + key: a.key.clone(), + put_id: a.put_id, + }, + PutAtomicGroupMember { + key: b.key.clone(), + put_id: b.put_id, + }, + ], + }); + let route_a = source_route(&owner, &a, Some(group.clone()), false); + let changed_b = source_member("b", b.put_id, 99, 1); + let route_b_with_changed_backing = + source_route(&owner, &changed_b, Some(group.clone()), false); + let stale_backing_plan = + plan_exact_owner_source_cohort_with(&owner, &cohort, &|key| match key { + "a" => Some(route_a.clone()), + "b" => Some(route_b_with_changed_backing.clone()), + _ => None, + }); + assert!(matches!( + stale_backing_plan, + OwnerSourceCohortPlan::Stale(_) + )); + + let route_b_without_group = source_route(&owner, &b, None, false); + let inconsistent_group_plan = + plan_exact_owner_source_cohort_with(&owner, &cohort, &|key| match key { + "a" => Some(route_a.clone()), + "b" => Some(route_b_without_group.clone()), + _ => None, + }); + assert!(matches!( + inconsistent_group_plan, + OwnerSourceCohortPlan::Rejected(_) + )); + } +} + +/// Why an entry entered the shared safe-reclaim pipeline. +/// +/// Only `MasterAllocationCapacity` may originate from the master resident +/// cache's Size listener. `OwnerCapacityEviction` is an exact source-deletion +/// request selected by the owner and may resolve to a CommittedSlot. +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub(crate) enum EvictionReclaimOrigin { + MasterAllocationCapacity, + OwnerCapacityEviction, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(crate) enum EnqueueEvictionReclaimResult { + Accepted, + AlreadyInProgress, + PartialOverlap, + NotInProgress, + Closed, +} + +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub(crate) struct EvictionReclaimIdentity { + owner_node_id: NodeIDString, + owner_node_start_time: Option, + key: String, + put_id: (u64, u32), + weight_bytes: u32, + expected_backing: Option, +} + #[derive(Clone, Debug)] -pub(crate) struct EvictionReclaimRequest { - pub owner_node_id: NodeIDString, +pub(crate) struct EvictionReclaimMember { pub key: String, pub desc: NodeValueReplicaDesc, + pub expected_backing: Option, +} + +#[derive(Clone, Debug)] +pub(crate) struct EvictionReclaimRequest { + pub owner_node_id: NodeIDString, + pub owner_node_start_time: Option, + pub members: Vec, + pub origin: EvictionReclaimOrigin, pub retry_count: u32, } +impl EvictionReclaimRequest { + pub(crate) fn identities(&self) -> Vec { + self.members + .iter() + .map(|member| EvictionReclaimIdentity { + owner_node_id: self.owner_node_id.clone(), + owner_node_start_time: self.owner_node_start_time, + key: member.key.clone(), + put_id: member.desc.put_id, + weight_bytes: member.desc.weight_bytes, + expected_backing: member.expected_backing.clone(), + }) + .collect() + } + + pub(crate) fn weight_bytes(&self) -> u64 { + self.members + .iter() + .map(|member| u64::from(member.desc.weight_bytes)) + .fold(0u64, u64::saturating_add) + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum MasterCapacityPlanError { + RouteChanged, + InvalidCohort, + WrongRole, + CommittedSlot, +} + +fn master_allocation_capacity_weight( + backing: &KvReplicaBacking, +) -> Result { + match backing { + KvReplicaBacking::Allocation(allocation) => { + Ok(u32::try_from(allocation.capcity()).unwrap_or(u32::MAX)) + } + KvReplicaBacking::CommittedSlot(_) => Err(MasterCapacityPlanError::CommittedSlot), + } +} + +fn allocation_member_from_route( + view: &MasterKvRouterView, + owner: &NodeID, + key: &str, +) -> Result< + ( + EvictionReclaimMember, + std::sync::Arc, + ), + MasterCapacityPlanError, +> { + let route = view + .master_kv_router() + .inner() + .kv_routes + .get(key) + .map(|entry| entry.clone()) + .ok_or(MasterCapacityPlanError::RouteChanged)?; + if route.lease_id.is_some() { + return Err(MasterCapacityPlanError::RouteChanged); + } + let replicas = route.nodes_replicas.read(); + let replica = replicas + .get(owner) + .filter(|replica| !replica.tomb_tag.is_tomb()) + .ok_or(MasterCapacityPlanError::RouteChanged)?; + if replica.owner_local_indexed { + return Err(MasterCapacityPlanError::WrongRole); + } + let weight_bytes = master_allocation_capacity_weight(&replica.backing)?; + drop(replicas); + Ok(( + EvictionReclaimMember { + key: key.to_string(), + desc: NodeValueReplicaDesc { + weight_bytes, + put_id: route.put_id, + }, + expected_backing: None, + }, + route, + )) +} + +/// Expand one master Size event by point-looking up its atomic/TP cohort. +/// This function never iterates the resident cache or global route table. +fn plan_master_allocation_capacity_cohort( + view: &MasterKvRouterView, + request: &EvictionReclaimRequest, +) -> Result, MasterCapacityPlanError> { + if request.origin != EvictionReclaimOrigin::MasterAllocationCapacity + || request.members.is_empty() + { + return Err(MasterCapacityPlanError::WrongRole); + } + let owner: NodeID = request.owner_node_id.clone().into(); + let anchor = &request.members[0]; + let (current_anchor, anchor_route) = allocation_member_from_route(view, &owner, &anchor.key)?; + if current_anchor.desc.put_id != anchor.desc.put_id + || current_anchor.desc.weight_bytes != anchor.desc.weight_bytes + { + return Err(MasterCapacityPlanError::RouteChanged); + } + let mut cohort_keys = + super::current_tp_cohort_keys(&anchor.key, &anchor_route, ¤t_anchor.desc) + .map_err(|_| MasterCapacityPlanError::InvalidCohort)?; + cohort_keys.sort_unstable(); + cohort_keys.dedup(); + if cohort_keys.is_empty() { + return Err(MasterCapacityPlanError::InvalidCohort); + } + + let mut members = Vec::with_capacity(cohort_keys.len()); + for key in &cohort_keys { + let (member, route) = allocation_member_from_route(view, &owner, key)?; + let mut peer_keys = super::current_tp_cohort_keys(key, &route, &member.desc) + .map_err(|_| MasterCapacityPlanError::InvalidCohort)?; + peer_keys.sort_unstable(); + peer_keys.dedup(); + if peer_keys != cohort_keys { + return Err(MasterCapacityPlanError::InvalidCohort); + } + members.push(member); + } + Ok(members) +} + +fn detach_present_capacity_cohort_siblings( + view: &MasterKvRouterView, + owner_node_id: &str, + members: &[EvictionReclaimMember], +) -> Result, MasterCapacityPlanError> { + let cache = view + .master_kv_router() + .get_node_cache_controller(owner_node_id) + .ok_or(MasterCapacityPlanError::RouteChanged)?; + let mut expected = HashMap::new(); + for member in members { + if let Some(cached) = cache.get(&member.key) { + if cached.put_id != member.desc.put_id + || cached.weight_bytes != member.desc.weight_bytes + { + return Err(MasterCapacityPlanError::RouteChanged); + } + expected.insert(member.key.clone(), member.desc.clone()); + } + } + if expected.is_empty() { + return Ok(Vec::new()); + } + super::take_exact_cache_entries(&cache, &expected) + .map(|removed| { + removed + .into_iter() + .map(|(key, desc)| EvictionReclaimMember { + key, + desc, + expected_backing: None, + }) + .collect() + }) + .ok_or(MasterCapacityPlanError::RouteChanged) +} + fn route_item( view: &MasterKvRouterView, owner_node_id: &NodeID, @@ -111,32 +630,7 @@ fn route_item( } KvReplicaBacking::CommittedSlot(_) => return None, }; - let has_other_live_replica = replicas - .iter() - .any(|(node_id, replica)| node_id != owner_node_id && !replica.tomb_tag.is_tomb()); drop(replicas); - if reason == OwnerReclaimReason::Reserve { - let normally_recoverable = has_other_live_replica - && (view - .master_kv_router() - .owner_cache_allows_unrecoverable_eviction(owner_node_id.as_ref()) - || { - let desc = NodeValueReplicaDesc { - weight_bytes: 0, - put_id: route.put_id, - }; - view.master_kv_router() - .eviction_cache_entry_recoverable_status(owner_node_id.as_ref(), key, &desc) - == super::RecoverableReplicaStatus::Recoverable - }); - if !normally_recoverable - && !view - .master_kv_router() - .owner_cache_allows_unrecoverable_reserve_pressure_eviction(owner_node_id.as_ref()) - { - return None; - } - } Some(OwnerReclaimItem { key: key.to_string(), put_id: route.put_id, @@ -146,15 +640,6 @@ fn route_item( }) } -fn master_has_holder(view: &MasterKvRouterView, key: &str) -> bool { - view.master_kv_router() - .inner() - .get_holding - .inner() - .iter() - .any(|entry| entry.value().key == key) -} - fn item_still_valid(view: &MasterKvRouterView, owner: &NodeID, item: &OwnerReclaimItem) -> bool { if !view .master_kv_router() @@ -250,6 +735,7 @@ fn clear_master_fence(view: &MasterKvRouterView, item: &OwnerReclaimItem) { } } +#[cfg(test)] async fn abort_prepared( view: &MasterKvRouterView, owner: &NodeID, @@ -291,6 +777,7 @@ async fn abort_prepared( } } +#[cfg(test)] fn spawn_abort_retry(view: MasterKvRouterView, owner: NodeID, items: Vec) { if items.is_empty() { return; @@ -365,55 +852,351 @@ fn reclaim_backing_matches(replica: &super::KvRouteInfo, expected: &OwnerReclaim } } -fn remove_reclaimed_replica( +fn owner_source_member_weight(backing: &OwnerReclaimBacking) -> Option { + match backing { + OwnerReclaimBacking::CommittedSlot { slot_size, .. } => u32::try_from(*slot_size).ok(), + // Allocation does not carry an address/generation identity in the + // current wire contract, so accepting it would not be an exact delete. + OwnerReclaimBacking::Allocation | OwnerReclaimBacking::UnindexedAllocation => None, + } +} + +enum OwnerSourceCohortPlan { + Ready { + members: Vec, + all_sources_present: bool, + }, + Completed(&'static str), + Stale(String), + Rejected(String), +} + +fn plan_exact_owner_source_cohort( view: &MasterKvRouterView, owner: &NodeID, - item: &OwnerReclaimItem, -) -> bool { - if !view - .master_kv_router() - .inner() - .key_activity - .reclaim_matches(item) - { - return false; + cohort: &OwnerSourceEvictionCohort, +) -> OwnerSourceCohortPlan { + plan_exact_owner_source_cohort_with(owner, cohort, &|key| { + view.master_kv_router() + .inner() + .kv_routes + .get(key) + .map(|entry| entry.clone()) + }) +} + +fn plan_exact_owner_source_cohort_with( + owner: &NodeID, + cohort: &OwnerSourceEvictionCohort, + route_lookup: &dyn Fn(&str) -> Option>, +) -> OwnerSourceCohortPlan { + if cohort.members.is_empty() { + return OwnerSourceCohortPlan::Rejected("empty source-eviction cohort".to_string()); + } + + let mut expected_keys = cohort + .members + .iter() + .map(|member| member.key.clone()) + .collect::>(); + expected_keys.sort_unstable(); + expected_keys.dedup(); + if expected_keys.len() != cohort.members.len() { + return OwnerSourceCohortPlan::Rejected( + "source-eviction cohort contains duplicate keys".to_string(), + ); + } + + let mut planned = Vec::with_capacity(cohort.members.len()); + let mut absent_sources = 0usize; + for member in &cohort.members { + let Some(weight_bytes) = owner_source_member_weight(&member.backing) else { + return OwnerSourceCohortPlan::Rejected(format!( + "source backing is not an exact committed slot: key={}", + member.key + )); + }; + let desc = NodeValueReplicaDesc { + weight_bytes, + put_id: member.put_id, + }; + planned.push(EvictionReclaimMember { + key: member.key.clone(), + desc: desc.clone(), + expected_backing: Some(member.backing.clone()), + }); + + let Some(route) = route_lookup(&member.key) else { + absent_sources += 1; + continue; + }; + if route.put_id != member.put_id { + return OwnerSourceCohortPlan::Stale(format!( + "route version changed: key={} expected=({},{}) current=({},{})", + member.key, member.put_id.0, member.put_id.1, route.put_id.0, route.put_id.1, + )); + } + if route.lease_id.is_some() { + return OwnerSourceCohortPlan::Rejected(format!( + "leased route is not cache-evictable: key={}", + member.key + )); + } + let replica_matches = { + let replicas = route.nodes_replicas.read(); + match replicas.get(owner) { + Some(replica) if !replica.tomb_tag.is_tomb() => { + if !replica.owner_local_indexed { + return OwnerSourceCohortPlan::Rejected(format!( + "source route is not owner-local indexed: key={}", + member.key + )); + } + reclaim_backing_matches(replica, &member.backing) + } + _ => { + absent_sources += 1; + continue; + } + } + }; + if !replica_matches { + return OwnerSourceCohortPlan::Stale(format!( + "source backing changed: key={} put_id=({},{})", + member.key, member.put_id.0, member.put_id.1 + )); + } + + let mut route_cohort = match super::current_tp_cohort_keys(&member.key, &route, &desc) { + Ok(keys) => keys, + Err(_) => { + return OwnerSourceCohortPlan::Rejected(format!( + "master route has an invalid TP/atomic cohort: key={}", + member.key + )); + } + }; + route_cohort.sort_unstable(); + route_cohort.dedup(); + if route_cohort != expected_keys { + return OwnerSourceCohortPlan::Rejected(format!( + "owner did not submit the complete TP/atomic cohort: key={} expected_members={} route_members={}", + member.key, + expected_keys.len(), + route_cohort.len(), + )); + } + } + + if absent_sources == cohort.members.len() { + OwnerSourceCohortPlan::Completed("all exact source replicas are already absent") + } else if absent_sources != 0 { + // This can be observed while an accepted cohort is between individual + // route removals. The exact inflight registration below distinguishes + // that case from a malformed new request. + OwnerSourceCohortPlan::Ready { + members: planned, + all_sources_present: false, + } + } else { + OwnerSourceCohortPlan::Ready { + members: planned, + all_sources_present: true, + } } - let _route_guard = view.master_kv_router().inner().route_lifetime_lock.lock(); - let Some(route) = view +} + +pub(crate) async fn handle_batch_evict_owner_source( + view: &MasterKvRouterView, + req: MsgPack, + owner: NodeID, +) -> MsgPack { + let operation_id = req.serialize_part.operation_id; + let counters = view .master_kv_router() - .inner() - .kv_routes - .get(&item.key) - .map(|route| route.clone()) - else { - return true; - }; + .eviction_reclaim_counters(owner.as_ref()); + counters + .source_evict_rpc_requests + .fetch_add(1, Ordering::Relaxed); + counters.source_evict_cohorts.fetch_add( + u64::try_from(req.serialize_part.cohorts.len()).unwrap_or(u64::MAX), + Ordering::Relaxed, + ); + let requested_bytes = req + .serialize_part + .cohorts + .iter() + .flat_map(|cohort| cohort.members.iter()) + .filter_map(|member| owner_source_member_weight(&member.backing)) + .map(u64::from) + .fold(0u64, u64::saturating_add); + counters + .source_evict_requested_bytes + .fetch_add(requested_bytes, Ordering::Relaxed); + let current_generation = view + .cluster_manager() + .get_member_info_cached(owner.as_ref()) + .map(|member| member.node_start_time); + if current_generation != Some(req.serialize_part.owner_node_start_time) { + counters.source_evict_rejected.fetch_add( + u64::try_from(req.serialize_part.cohorts.len()).unwrap_or(u64::MAX), + Ordering::Relaxed, + ); + let err = KvError::Api(ApiError::InvalidArgument { + detail: format!( + "owner source-eviction generation mismatch: owner={} requested={} current={:?}", + owner, req.serialize_part.owner_node_start_time, current_generation + ), + }); + return MsgPack { + serialize_part: BatchEvictOwnerSourceResp { + operation_id, + cohorts: Vec::new(), + error_code: err.code(), + error_json: err.to_json(), + }, + raw_bytes: Vec::new(), + }; + } + + let mut responses = Vec::with_capacity(req.serialize_part.cohorts.len()); + for (index, cohort) in req.serialize_part.cohorts.iter().enumerate() { + let (outcome, detail) = match plan_exact_owner_source_cohort(view, &owner, cohort) { + OwnerSourceCohortPlan::Completed(detail) => { + (OwnerSourceEvictionOutcome::Completed, detail.to_string()) + } + OwnerSourceCohortPlan::Stale(detail) => (OwnerSourceEvictionOutcome::Stale, detail), + OwnerSourceCohortPlan::Rejected(detail) => { + (OwnerSourceEvictionOutcome::RejectedNotEvictable, detail) + } + OwnerSourceCohortPlan::Ready { + members, + all_sources_present, + } => { + match view + .master_kv_router() + .enqueue_owner_capacity_eviction_cohort( + owner.as_ref().to_string(), + req.serialize_part.owner_node_start_time, + members, + all_sources_present, + ) { + EnqueueEvictionReclaimResult::Accepted => ( + OwnerSourceEvictionOutcome::Accepted, + "exact source cohort accepted by reclaim pipeline".to_string(), + ), + EnqueueEvictionReclaimResult::AlreadyInProgress => ( + OwnerSourceEvictionOutcome::AlreadyInProgress, + "same exact source cohort is already in progress".to_string(), + ), + EnqueueEvictionReclaimResult::PartialOverlap => ( + OwnerSourceEvictionOutcome::RetryableBusy, + "source cohort partially overlaps another reclaim transaction".to_string(), + ), + EnqueueEvictionReclaimResult::NotInProgress => ( + OwnerSourceEvictionOutcome::Stale, + "partially absent source cohort is not an in-progress replay".to_string(), + ), + EnqueueEvictionReclaimResult::Closed => ( + OwnerSourceEvictionOutcome::RetryableBusy, + "source reclaim actor is unavailable".to_string(), + ), + } + } + }; + let outcome_counter = match outcome { + OwnerSourceEvictionOutcome::Accepted => &counters.source_evict_accepted, + OwnerSourceEvictionOutcome::AlreadyInProgress => &counters.source_evict_in_progress, + OwnerSourceEvictionOutcome::Completed => &counters.source_evict_completed, + OwnerSourceEvictionOutcome::RetryableBusy | OwnerSourceEvictionOutcome::Unspecified => { + &counters.source_evict_retryable_busy + } + OwnerSourceEvictionOutcome::Stale => &counters.source_evict_stale, + OwnerSourceEvictionOutcome::RejectedNotEvictable => &counters.source_evict_rejected, + }; + outcome_counter.fetch_add(1, Ordering::Relaxed); + responses.push(OwnerSourceEvictionCohortResp { + cohort_index: u32::try_from(index).unwrap_or(u32::MAX), + outcome, + detail, + }); + } + + MsgPack { + serialize_part: BatchEvictOwnerSourceResp { + operation_id, + cohorts: responses, + error_code: OK, + error_json: String::new(), + }, + raw_bytes: Vec::new(), + } +} + +struct RemovedOwnerSource { + desc: NodeValueReplicaDesc, + removed_last_route: bool, +} + +fn remove_exact_owner_source_route( + routes: &dashmap::DashMap>, + owner: &NodeID, + item: &OwnerReclaimItem, +) -> Option { + let route = routes.get(&item.key).map(|route| route.clone())?; if route.put_id != item.put_id { - return true; + return None; } - let removed = { + let removed_desc = { let mut replicas = route.nodes_replicas.write(); let Some(replica) = replicas.get(owner) else { - return true; + return None; }; if !reclaim_backing_matches(replica, &item.backing) { - // This backing is no longer advertised by the fenced route version. - return true; + return None; } - replicas.remove(owner).is_some() + let desc = NodeValueReplicaDesc { + weight_bytes: u32::try_from(replica.backing.capacity_bytes()).unwrap_or(u32::MAX), + put_id: route.put_id, + }; + replicas.remove(owner).map(|_| desc) }; - if !removed { - return true; - } + let removed_desc = removed_desc?; - if route.nodes_replicas.read().is_empty() { - let route_removed = view - .master_kv_router() - .inner() - .kv_routes - .remove_if(&item.key, |_, current| current.put_id == item.put_id) - .is_some(); - if route_removed && view.master_kv_router().prefix_index_enabled() { + let removed_last_route = if route.nodes_replicas.read().is_empty() { + routes + .remove_if(&item.key, |_, current| { + Arc::ptr_eq(current, &route) + && current.put_id == item.put_id + && current.nodes_replicas.read().is_empty() + }) + .is_some() + } else { + false + }; + Some(RemovedOwnerSource { + desc: removed_desc, + removed_last_route, + }) +} + +fn remove_reclaimed_replica( + view: &MasterKvRouterView, + owner: &NodeID, + item: &OwnerReclaimItem, +) -> bool { + if !view + .master_kv_router() + .inner() + .key_activity + .reclaim_matches(item) + { + return false; + } + let removed = + remove_exact_owner_source_route(&view.master_kv_router().inner().kv_routes, owner, item); + if let Some(removed) = removed { + if removed.removed_last_route && view.master_kv_router().prefix_index_enabled() { let view_task = view.clone(); let key = item.key.clone(); let put_id = item.put_id; @@ -428,15 +1211,23 @@ fn remove_reclaimed_replica( tree.remove(&key, put_id); }); } + if let Some(cache) = view + .master_kv_router() + .inner() + .node_kv_cache_controller + .get(owner.as_ref()) + { + let _ = super::remove_exact_cache_entry(cache.value(), &item.key, &removed.desc); + } + if let Some(cache) = view + .master_kv_router() + .inner() + .node_writeback_tier1_controller + .get(owner.as_ref()) + { + let _ = super::remove_exact_cache_entry(cache.value(), &item.key, &removed.desc); + } } - if let Some(cache) = view - .master_kv_router() - .get_node_cache_controller(owner.as_ref()) - { - let _ = cache.remove(&item.key); - } - view.master_kv_router() - .remove_node_writeback_tier1_entry(owner.as_ref(), &item.key); true } @@ -572,6 +1363,7 @@ fn spawn_finalize_retry(view: MasterKvRouterView, owner: NodeID, items: Vec Result<(), (usize, super::MasterKeyActivitySnapshot)> { + let mut installed = Vec::with_capacity(items.len()); + for (index, item) in items.iter().enumerate() { + match activity.try_install_reclaim(item) { + Ok(()) => installed.push(item), + Err(snapshot) => { + for installed_item in installed { + assert!(activity.clear_reclaim(installed_item)); + } + return Err((index, snapshot)); + } + } + } + Ok(()) +} + +/// Reclaim one TP/atomic cohort as a transaction. +/// +/// Before the first owner Commit, any failed fence/validation/Prepare rolls +/// the entire cohort back. Once a response (including an Abort response) +/// proves that any member was committed, rollback is impossible; the same +/// transaction retains every master fence and keeps driving the remaining +/// members until all are committed, then removes/finalizes the whole cohort. +async fn reclaim_cohort_items( view: &MasterKvRouterView, owner: &NodeID, - slot_size: u64, - limit: usize, -) -> Vec { - let mut candidates = Vec::new(); - // Moka iteration may synchronously drain cache maintenance and eviction listeners. Under - // pressure that made a 256-item candidate lookup take seconds. Route metadata is the - // reclaim authority, so snapshot its keys and validate candidates directly instead. - let route_keys = view + items: Vec, +) -> u32 { + if items.is_empty() { + return 0; + } + let counters = view .master_kv_router() - .inner() - .kv_routes + .eviction_reclaim_counters(owner.as_ref()); + if let Err((failed_index, activity)) = + try_install_cohort_master_fences(&view.master_kv_router().inner().key_activity, &items) + { + counters + .master_activity_deferred + .fetch_add(1, Ordering::Relaxed); + tracing::trace!( + "cohort reclaim deferred by master activity: owner={} key={} puts={} gets={} replicas={} reclaim_installed={}", + owner, + items[failed_index].key, + activity.puts, + activity.gets, + activity.replicas, + activity.reclaim_installed, + ); + return 0; + } + let fenced = items; + if fenced .iter() - .map(|route| route.key().clone()) - .collect::>(); - for key in route_keys { - if candidates.len() >= limit { - break; - } - if !view - .master_kv_router() - .inner() - .key_activity - .is_quiescent(&key) + .any(|item| !item_still_valid(view, owner, item)) + { + clear_master_fences(view, &fenced); + return 0; + } + + let (master_only, owner_coordinated) = partition_reclaim_coordination(fenced.clone()); + if owner_coordinated.is_empty() { + // All master-owned allocations are fenced and revalidated before the + // first route mutation, so no member can be admitted independently. + if master_only.len() != fenced.len() + || master_only + .iter() + .any(|item| !item_still_valid(view, owner, item)) { - continue; + clear_master_fences(view, &fenced); + return 0; } - if let Some(item) = route_item( - view, + let reclaimed = finish_unindexed_allocations(view, owner, master_only); + counters + .completed + .fetch_add(u64::from(reclaimed), Ordering::Relaxed); + return reclaimed; + } + if !master_only.is_empty() || owner_coordinated.len() != fenced.len() { + tracing::error!( + "BUG: one reclaim cohort mixed master-only and owner-coordinated backings: owner={} cohort={} master_only={} owner_coordinated={}", owner, - &key, - None, - Some(slot_size), - OwnerReclaimReason::Reserve, - view.master_kv_router().next_owner_reclaim_epoch(), - ) { - candidates.push(item); - } + fenced.len(), + master_only.len(), + owner_coordinated.len(), + ); + clear_master_fences(view, &fenced); + return 0; } - candidates -} -async fn reclaim_reserve_candidate_batches( - candidates: Vec, - required_free_slots: u32, - mut reclaim_batch: F, -) -> (u32, usize) -where - F: FnMut(Vec) -> Fut, - Fut: Future, -{ - let mut reclaimed = 0u32; - let mut scanned_candidates = 0usize; - while reclaimed < required_free_slots && scanned_candidates < candidates.len() { - let remaining_slots = required_free_slots.saturating_sub(reclaimed); - let batch_len = usize::try_from(remaining_slots) - .unwrap_or(usize::MAX) - .min(candidates.len() - scanned_candidates); - let batch_end = scanned_candidates + batch_len; - let batch = candidates[scanned_candidates..batch_end].to_vec(); - scanned_candidates = batch_end; - - let batch_size = u32::try_from(batch.len()).unwrap_or(u32::MAX); - let batch_reclaimed = reclaim_batch(batch).await; - debug_assert!(batch_reclaimed <= batch_size); - reclaimed = reclaimed.saturating_add(batch_reclaimed.min(batch_size)); - } - (reclaimed, scanned_candidates) + let all_by_key = owner_coordinated + .iter() + .cloned() + .map(|item| (item.key.clone(), item)) + .collect::>(); + let mut committed_keys = HashSet::new(); + let mut delay = Duration::from_millis(25); + let mut rounds = 0u32; + loop { + let pending = all_by_key + .iter() + .filter(|(key, _)| !committed_keys.contains(*key)) + .map(|(_, item)| item.clone()) + .collect::>(); + if pending.is_empty() { + let reclaimed = finish_committed(view, owner, owner_coordinated).await; + counters + .completed + .fetch_add(u64::from(reclaimed), Ordering::Relaxed); + return reclaimed; + } + + rounds = rounds.saturating_add(1); + let prepare = + call_owner_phase(view, owner, OwnerReclaimPhase::Prepare, pending.clone()).await; + let Ok(prepare_responses) = prepare else { + // No member is known committed yet. Abort is both rollback and + // response-loss resolution: a Committed response moves us onto + // the mandatory roll-forward branch. + if committed_keys.is_empty() { + if let Ok(abort_responses) = + call_owner_phase(view, owner, OwnerReclaimPhase::Abort, pending.clone()).await + { + for (item, response) in pending.iter().zip(abort_responses) { + if response.state == OwnerReclaimItemState::Committed { + committed_keys.insert(item.key.clone()); + } + } + if committed_keys.is_empty() { + clear_master_fences(view, &fenced); + return 0; + } + } + } + tokio::time::sleep(delay).await; + delay = (delay * 2).min(Duration::from_secs(1)); + continue; + }; + + let mut prepared = Vec::new(); + let mut blocked = false; + for (item, response) in pending.iter().cloned().zip(prepare_responses) { + match response.state { + OwnerReclaimItemState::Prepared => prepared.push(item), + OwnerReclaimItemState::Committed => { + committed_keys.insert(item.key); + } + _ => blocked = true, + } + } + + if blocked && committed_keys.is_empty() { + // Nothing irreversible happened. Abort every possibly-prepared + // member, and only roll back after the response proves that none + // had crossed Commit during a lost response. + match call_owner_phase(view, owner, OwnerReclaimPhase::Abort, pending.clone()).await { + Ok(responses) => { + for (item, response) in pending.iter().zip(responses) { + if response.state == OwnerReclaimItemState::Committed { + committed_keys.insert(item.key.clone()); + } + } + if committed_keys.is_empty() { + clear_master_fences(view, &fenced); + return 0; + } + } + Err(_) => { + tokio::time::sleep(delay).await; + delay = (delay * 2).min(Duration::from_secs(1)); + continue; + } + } + } + + // With no blocked member this is the first atomic Commit attempt. If + // another member was already observed Committed, this is mandatory + // roll-forward for the rest of the transaction. + if !prepared.is_empty() && (!blocked || !committed_keys.is_empty()) { + if let Ok(commit_responses) = + call_owner_phase(view, owner, OwnerReclaimPhase::Commit, prepared.clone()).await + { + for (item, response) in prepared.iter().zip(commit_responses) { + if response.state == OwnerReclaimItemState::Committed { + committed_keys.insert(item.key.clone()); + } + } + } + } + + if rounds == 8 && !committed_keys.is_empty() { + tracing::warn!( + "owner cohort reclaim is rolling forward after partial/uncertain commit: owner={} cohort={} committed={}", + owner, + owner_coordinated.len(), + committed_keys.len(), + ); + } + tokio::time::sleep(delay).await; + delay = (delay * 2).min(Duration::from_secs(1)); + } } #[cfg(test)] -mod reserve_scan_tests { +mod reclaim_partition_tests { use super::{ OwnerReclaimBacking, OwnerReclaimItem, OwnerReclaimReason, partition_reclaim_coordination, - reclaim_reserve_candidate_batches, }; - use std::future::ready; fn candidate(index: u32) -> OwnerReclaimItem { OwnerReclaimItem { @@ -823,7 +1740,7 @@ mod reserve_scan_tests { slot_index: index, slot_size: 8 * 1024 * 1024, }, - reason: OwnerReclaimReason::Reserve, + reason: OwnerReclaimReason::OwnerCapacityEviction, } } @@ -831,10 +1748,10 @@ mod reserve_scan_tests { fn only_unindexed_allocations_skip_owner_coordination() { let mut indexed_allocation = candidate(1); indexed_allocation.backing = OwnerReclaimBacking::Allocation; - indexed_allocation.reason = OwnerReclaimReason::CapacityEviction; + indexed_allocation.reason = OwnerReclaimReason::OwnerCapacityEviction; let mut unindexed_allocation = candidate(2); unindexed_allocation.backing = OwnerReclaimBacking::UnindexedAllocation; - unindexed_allocation.reason = OwnerReclaimReason::CapacityEviction; + unindexed_allocation.reason = OwnerReclaimReason::MasterAllocationCapacity; let committed_slot = candidate(3); let (master_only, owner_coordinated) = partition_reclaim_coordination(vec![ @@ -851,57 +1768,6 @@ mod reserve_scan_tests { .all(|item| item.backing != OwnerReclaimBacking::UnindexedAllocation) ); } - - #[limit_thirdparty::tokio::test] - async fn reserve_scan_continues_after_busy_first_batch() { - let candidates = (0..12).map(candidate).collect::>(); - let mut batches = Vec::new(); - let mut call_count = 0usize; - - let (reclaimed, scanned_candidates) = - reclaim_reserve_candidate_batches(candidates, 5, |batch: Vec| { - call_count += 1; - batches.push( - batch - .iter() - .map(|item| item.key.clone()) - .collect::>(), - ); - ready(if call_count == 1 { - 0 - } else { - u32::try_from(batch.len()).unwrap() - }) - }) - .await; - - assert_eq!(reclaimed, 5); - assert_eq!(scanned_candidates, 10); - assert_eq!(batches.len(), 2); - assert_eq!(batches[0][0], "candidate-0"); - assert_eq!(batches[0][4], "candidate-4"); - assert_eq!(batches[1][0], "candidate-5"); - assert_eq!(batches[1][4], "candidate-9"); - } - - #[limit_thirdparty::tokio::test] - async fn reserve_scan_shrinks_next_batch_after_partial_reclaim() { - let candidates = (0..10).map(candidate).collect::>(); - let mut batch_lengths = Vec::new(); - let mut call_count = 0usize; - - let (reclaimed, scanned_candidates) = - reclaim_reserve_candidate_batches(candidates, 5, |batch| { - call_count += 1; - batch_lengths.push(batch.len()); - ready(if call_count == 1 { 2 } else { 3 }) - }) - .await; - - assert_eq!(reclaimed, 5); - assert_eq!(scanned_candidates, 8); - assert_eq!(batch_lengths, vec![5, 3]); - } } #[cfg(test)] @@ -967,7 +1833,7 @@ mod owner_get_holding_reclaim_tests { key, None, None, - OwnerReclaimReason::CapacityEviction, + OwnerReclaimReason::OwnerCapacityEviction, master_view.master_kv_router().next_owner_reclaim_epoch(), ) .expect("active-holder owner route should be reclaimable after the reader exits"); @@ -995,7 +1861,7 @@ mod owner_get_holding_reclaim_tests { key, None, None, - OwnerReclaimReason::CapacityEviction, + OwnerReclaimReason::OwnerCapacityEviction, master_view.master_kv_router().next_owner_reclaim_epoch(), ) .expect("current owner route should be reclaimable"); @@ -1036,36 +1902,69 @@ mod owner_get_holding_reclaim_tests { } } -pub(crate) async fn reclaim_owner_slots_for_reserve( - view: &MasterKvRouterView, - owner_node_id: &NodeID, - slot_size: u64, - required_free_slots: u32, -) -> u32 { - if slot_size == 0 || required_free_slots == 0 { - return 0; +fn request_is_current(view: &MasterKvRouterView, request: &EvictionReclaimRequest) -> bool { + if let Some(expected_generation) = request.owner_node_start_time + && view + .cluster_manager() + .get_member_info_cached(&request.owner_node_id) + .map(|member| member.node_start_time) + != Some(expected_generation) + { + return false; + } + match request.origin { + EvictionReclaimOrigin::MasterAllocationCapacity => request.members.iter().all(|member| { + view.master_kv_router().eviction_cache_entry_is_current( + &request.owner_node_id, + &member.key, + &member.desc, + ) + }), + EvictionReclaimOrigin::OwnerCapacityEviction => { + let owner: NodeID = request.owner_node_id.clone().into(); + request.members.iter().all(|member| { + let Some(expected_backing) = member.expected_backing.as_ref() else { + return false; + }; + let Some(route) = view + .master_kv_router() + .inner() + .kv_routes + .get(&member.key) + .map(|entry| entry.clone()) + else { + return false; + }; + if route.put_id != member.desc.put_id || route.lease_id.is_some() { + return false; + } + route + .nodes_replicas + .read() + .get(&owner) + .is_some_and(|replica| { + !replica.tomb_tag.is_tomb() + && replica.owner_local_indexed + && reclaim_backing_matches(replica, expected_backing) + }) + }) + } } - let scan_started = Instant::now(); - let candidates = - collect_reserve_candidates(view, owner_node_id, slot_size, OWNER_RECLAIM_MAX_BATCH); - let candidate_scan_us = scan_started.elapsed().as_micros(); - let candidate_count = candidates.len(); - let (reclaimed, scanned_candidate_count) = - reclaim_reserve_candidate_batches(candidates, required_free_slots, |batch| { - reclaim_items(view, owner_node_id, batch) +} + +fn restore_request_entries(view: &MasterKvRouterView, request: &EvictionReclaimRequest) -> usize { + request + .members + .iter() + .filter(|member| { + view.master_kv_router() + .restore_eviction_cache_entry_if_current( + &request.owner_node_id, + member.key.clone(), + member.desc.clone(), + ) }) - .await; - tracing::info!( - "owner reserve reclaim completed: owner={} slot_size={} requested_slots={} candidates={} scanned_candidates={} reclaimed={} candidate_scan_us={}", - owner_node_id, - slot_size, - required_free_slots, - candidate_count, - scanned_candidate_count, - reclaimed, - candidate_scan_us - ); - reclaimed + .count() } fn spawn_eviction_reclaim_retry(view: MasterKvRouterView, requests: Vec) { @@ -1080,46 +1979,31 @@ fn spawn_eviction_reclaim_retry(view: MasterKvRouterView, requests: Vec, + mut rx: limit_thirdparty::tokio::sync::ampsc::UnboundedReceiver, ) { let view_task = view.clone(); let _ = view.spawn("eviction_reclaim_actor", async move { @@ -1226,64 +2093,192 @@ pub(crate) fn spawn_eviction_reclaim_actor( let counters = view_task .master_kv_router() .eviction_reclaim_counters(&owner_node_id); - let mut seen = HashSet::new(); - let mut items = Vec::new(); - let mut unique_requests = Vec::new(); - let mut completed_weight = 0u64; - for request in requests { - if !seen.insert((request.key.clone(), request.desc.put_id)) { - completed_weight = completed_weight - .saturating_add(u64::from(request.desc.weight_bytes)); - continue; - } - if let Some(item) = route_item( - &view_task, - &owner, - &request.key, - Some(request.desc.put_id), - None, - OwnerReclaimReason::CapacityEviction, - view_task.master_kv_router().next_owner_reclaim_epoch(), - ) { - items.push(item); - } - unique_requests.push(request); - } - let candidate_count = items.len(); - let reclaimed = reclaim_items(&view_task, &owner, items).await; + let mut pending = std::collections::VecDeque::from(requests); let mut retry_requests = Vec::new(); - for request in unique_requests { - if view_task - .master_kv_router() - .eviction_cache_entry_is_current( - &owner_node_id, - &request.key, - &request.desc, - ) - { - retry_requests.push(request); - } else { - completed_weight = completed_weight - .saturating_add(u64::from(request.desc.weight_bytes)); - counters.route_changed.fetch_add(1, Ordering::Relaxed); - if request.retry_count != 0 { - counters.retry_completed.fetch_add(1, Ordering::Relaxed); + while let Some(request) = pending.pop_front() { + let (members, mut accounting_requests, reason) = match request.origin { + EvictionReclaimOrigin::OwnerCapacityEviction => ( + request.members.clone(), + vec![request], + OwnerReclaimReason::OwnerCapacityEviction, + ), + EvictionReclaimOrigin::MasterAllocationCapacity => { + let members = match plan_master_allocation_capacity_cohort( + &view_task, + &request, + ) { + Ok(members) => members, + Err(MasterCapacityPlanError::CommittedSlot) => { + counters + .capacity_eviction_non_ring_b_entry_total + .fetch_add(1, Ordering::Relaxed); + counters + .capacity_eviction_hit_committed_slot + .fetch_add(1, Ordering::Relaxed); + view_task + .master_kv_router() + .complete_eviction_reclaim(&request); + let restored = restore_request_entries(&view_task, &request); + tracing::error!( + "BUG: master Allocation capacity event resolved to CommittedSlot; restored metadata: owner={} members={} restored={}", + owner_node_id, + request.members.len(), + restored, + ); + continue; + } + Err(MasterCapacityPlanError::RouteChanged) => { + view_task + .master_kv_router() + .complete_eviction_reclaim(&request); + counters.route_changed.fetch_add(1, Ordering::Relaxed); + continue; + } + Err(MasterCapacityPlanError::InvalidCohort) => { + retry_requests.push(request); + continue; + } + Err(MasterCapacityPlanError::WrongRole) => { + counters + .capacity_eviction_non_ring_b_entry_total + .fetch_add(1, Ordering::Relaxed); + view_task + .master_kv_router() + .complete_eviction_reclaim(&request); + let restored = restore_request_entries(&view_task, &request); + tracing::error!( + "BUG: master Allocation Size event resolved to a non-ring-B route; restored metadata: owner={} members={} restored={}", + owner_node_id, + request.members.len(), + restored, + ); + continue; + } + }; + let owner_cache_lock = view_task + .master_kv_router() + .inner() + .owner_cache_operation_locks + .get_lock(owner_node_id.clone()); + let owner_cache_guard = owner_cache_lock.lock().await; + let detach_result = detach_present_capacity_cohort_siblings( + &view_task, + &owner_node_id, + &members, + ); + drop(owner_cache_guard); + if detach_result.is_err() { + retry_requests.push(request); + continue; + } + + let planned = members + .iter() + .map(|member| { + ( + member.key.clone(), + member.desc.put_id, + member.desc.weight_bytes, + ) + }) + .collect::>(); + let mut accounting_requests = vec![request]; + let mut retained = std::collections::VecDeque::new(); + while let Some(other) = pending.pop_front() { + let belongs = other.origin + == EvictionReclaimOrigin::MasterAllocationCapacity + && other.members.iter().all(|member| { + planned.contains(&( + member.key.clone(), + member.desc.put_id, + member.desc.weight_bytes, + )) + }); + if belongs { + accounting_requests.push(other); + } else { + retained.push_back(other); + } + } + pending = retained; + + let mut accounted = accounting_requests + .iter() + .flat_map(EvictionReclaimRequest::identities) + .collect::>(); + for member in &members { + let synthetic = EvictionReclaimRequest { + owner_node_id: owner_node_id.clone(), + owner_node_start_time: None, + members: vec![member.clone()], + origin: EvictionReclaimOrigin::MasterAllocationCapacity, + retry_count: 0, + }; + let identity = synthetic.identities().pop().unwrap(); + if accounted.contains(&identity) { + continue; + } + if view_task + .master_kv_router() + .register_eviction_reclaim(&synthetic) + { + accounted.insert(identity); + accounting_requests.push(synthetic); + } + } + ( + members, + accounting_requests, + OwnerReclaimReason::MasterAllocationCapacity, + ) + } + }; + + let items = members + .iter() + .map(|member| { + let item = route_item( + &view_task, + &owner, + &member.key, + Some(member.desc.put_id), + None, + reason, + view_task.master_kv_router().next_owner_reclaim_epoch(), + )?; + if member + .expected_backing + .as_ref() + .is_some_and(|expected| expected != &item.backing) + { + return None; + } + Some(item) + }) + .collect::>>(); + if let Some(items) = items { + let _ = reclaim_cohort_items(&view_task, &owner, items).await; + } + for accounting_request in accounting_requests.drain(..) { + if request_is_current(&view_task, &accounting_request) { + retry_requests.push(accounting_request); + } else { + view_task + .master_kv_router() + .complete_eviction_reclaim(&accounting_request); + counters.route_changed.fetch_add(1, Ordering::Relaxed); + if accounting_request.retry_count != 0 { + counters.retry_completed.fetch_add(1, Ordering::Relaxed); + } } } } - view_task.master_kv_router().complete_eviction_reclaim_weight( - &owner_node_id, - completed_weight, - ); let retry_count = retry_requests.len(); spawn_eviction_reclaim_retry(view_task.clone(), retry_requests); tracing::trace!( - "batched safe eviction reclaim completed: owner={} candidates={} reclaimed={} retry_deferred={} completed_weight={}", + "safe cohort eviction reclaim batch completed: owner={} retry_deferred={}", owner_node_id, - candidate_count, - reclaimed, retry_count, - completed_weight ); } } diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/route_maintenance.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/route_maintenance.rs index b1c0932..6ebd982 100644 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/route_maintenance.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/route_maintenance.rs @@ -1,7 +1,7 @@ use super::{MasterKvRouterView, NodeValueReplicaDesc, put::PutIDForAKey}; use crate::cluster_manager::NodeID; use limit_thirdparty::tokio; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::time::Duration; const POST_ROUTE_MAINTENANCE_MAX_BATCH: usize = 512; @@ -73,12 +73,6 @@ fn saturating_moka_weight_bytes(key: &str, put_id: PutIDForAKey, capacity_bytes: } } -fn projected_batch_weight(current_weight: u64, replaced_weight: u64, incoming_weight: u64) -> u64 { - current_weight - .saturating_sub(replaced_weight) - .saturating_add(incoming_weight) -} - fn deduplicate_owner_events( events: Vec<(usize, String, NodeValueReplicaDesc)>, ) -> Vec<(String, NodeValueReplicaDesc)> { @@ -95,7 +89,7 @@ fn deduplicate_owner_events( } /// Applies index and cache work after route guards have been released. -async fn apply_post_route_maintenance_batch( +pub(super) async fn apply_post_route_maintenance_batch( view: &MasterKvRouterView, events: Vec, ) { @@ -126,7 +120,10 @@ async fn apply_post_route_maintenance_batch( if !view.master_kv_router().replica_cache_enabled() { return; } - let mut events_by_owner = HashMap::>::new(); + let mut ring_b_events_by_owner = + HashMap::>::new(); + let mut tier1_events_by_owner = + HashMap::>::new(); for (sequence, event) in events.into_iter().enumerate() { if event.lease_id.is_some() { continue; @@ -137,21 +134,39 @@ async fn apply_post_route_maintenance_batch( weight_bytes, put_id: event.put_id, }; - if !view.master_kv_router().eviction_cache_entry_is_current( + if view.master_kv_router().eviction_cache_entry_is_current( event.node_id.as_ref(), &event.key, &desc, ) { - continue; + ring_b_events_by_owner + .entry(event.node_id.as_ref().to_string()) + .or_default() + .push((sequence, event.key.clone(), desc.clone())); + } + if view.master_kv_router().tier1_writeback_entry_is_current( + event.node_id.as_ref(), + &event.key, + &desc, + ) { + tier1_events_by_owner + .entry(event.node_id.as_ref().to_string()) + .or_default() + .push((sequence, event.key, desc)); } - events_by_owner - .entry(event.node_id.as_ref().to_string()) - .or_default() - .push((sequence, event.key, desc)); } - for (owner_node_id, owner_events) in events_by_owner { + for (owner_node_id, owner_events) in ring_b_events_by_owner { let entries = deduplicate_owner_events(owner_events); + // Moka's sync housekeeper uses a blocking mutex. Serialize before + // entering it with an async owner-level gate so waiting route-publish + // tasks yield instead of occupying every Tokio worker thread. + let owner_cache_lock = view + .master_kv_router() + .inner() + .owner_cache_operation_locks + .get_lock(owner_node_id.clone()); + let _owner_cache_guard = owner_cache_lock.lock().await; let Some(cache) = view .master_kv_router() .get_node_cache_controller(&owner_node_id) @@ -163,85 +178,58 @@ async fn apply_post_route_maintenance_batch( continue; }; - // Drain prior writes once, then admit this owner batch as one unit. This exposes the - // aggregate incoming weight to the explicit resident-capacity policy. + // Drain prior writes once, then admit this owner batch as one unit. + // Every node's controller is the bounded authority for that node's + // unindexed Allocation domain; placement role is irrelevant. cache.run_pending_tasks(); - let weighted_size_before = cache.weighted_size(); - let replaced_weight = entries - .iter() - .filter_map(|(key, _)| cache.get(key)) - .map(|existing| u64::from(existing.weight_bytes)) - .fold(0u64, u64::saturating_add); - let incoming_weight = entries - .iter() - .map(|(_, desc)| u64::from(desc.weight_bytes)) - .fold(0u64, u64::saturating_add); - let projected_weight = - projected_batch_weight(weighted_size_before, replaced_weight, incoming_weight); - let node_space_size = view - .master_seg_manager() - .get_node_space_size(&owner_node_id); - let capacity = view - .master_kv_router() - .replica_cache_effective_capacity(&owner_node_id, node_space_size); - let requested_weight = projected_weight.saturating_sub(capacity); - let incoming_keys = entries - .iter() - .map(|(key, _)| key.clone()) - .collect::>(); - - let recoverable_selected_weight = view - .master_kv_router() - .evict_recoverable_cache_weight_excluding( - &owner_node_id, - requested_weight, - &incoming_keys, - ); - let fallback_requested_weight = - requested_weight.saturating_sub(recoverable_selected_weight); - let fallback_selected_weight = if view - .master_kv_router() - .owner_cache_allows_unrecoverable_eviction(&owner_node_id) - { - cache.evict_some_if(fallback_requested_weight, |key, _desc| { - !incoming_keys.contains(key) - }) - } else { - 0 - }; - if requested_weight != 0 { - tracing::debug!( - "recoverable-first batch admission: owner={} entries={} weighted_size_before={} replaced_weight={} incoming_weight={} projected_weight={} capacity={} requested_weight={} recoverable_selected_weight={} fallback_requested_weight={} fallback_selected_weight={} shortfall_weight={}", - owner_node_id, - entries.len(), - weighted_size_before, - replaced_weight, - incoming_weight, - projected_weight, - capacity, - requested_weight, - recoverable_selected_weight, - fallback_requested_weight, - fallback_selected_weight, - fallback_requested_weight.saturating_sub(fallback_selected_weight), - ); - } - - let tier1_cache = view - .master_kv_router() - .get_node_writeback_tier1_controller(&owner_node_id); for (key, desc) in entries { + if !view + .master_kv_router() + .eviction_cache_entry_is_current(&owner_node_id, &key, &desc) + { + continue; + } tracing::debug!("Inserting key: {:?} into cache", key); cache.insert(key.clone(), desc.clone()); - if let Some(tier1_cache) = tier1_cache.as_ref() { - tier1_cache.insert(key.clone(), desc); - } tracing::debug!( "Inserted key: {:?} into cache, current cache size: {}", key, cache.weighted_size() ); } + // Do not search Moka for a recoverable victim here. CPU append Done + // already carries the exact source key/cohort and performs a validated + // point demotion. Local-reserve Free/Prepared/Pending/Committed state is + // the physical capacity authority while that writeback is in flight. + } + + // Tier1 is a separate pre-writeback policy. Its admission rules remain + // owner-route based and must not be coupled to ring-B backing admission. + for (owner_node_id, owner_events) in tier1_events_by_owner { + let entries = deduplicate_owner_events(owner_events); + let owner_cache_lock = view + .master_kv_router() + .inner() + .owner_cache_operation_locks + .get_lock(owner_node_id.clone()); + let _owner_cache_guard = owner_cache_lock.lock().await; + let Some(tier1_cache) = view + .master_kv_router() + .get_node_writeback_tier1_controller(&owner_node_id) + else { + continue; + }; + tier1_cache.run_pending_tasks(); + for (key, desc) in entries { + if !view.master_kv_router().tier1_writeback_entry_is_current( + &owner_node_id, + &key, + &desc, + ) { + continue; + } + tier1_cache.insert(key, desc); + } } } @@ -306,7 +294,7 @@ pub(super) async fn enqueue_post_route_maintenance( #[cfg(test)] mod tests { - use super::{deduplicate_owner_events, projected_batch_weight, saturating_moka_weight_bytes}; + use super::{deduplicate_owner_events, saturating_moka_weight_bytes}; use crate::master_kv_router::NodeValueReplicaDesc; #[test] @@ -321,12 +309,6 @@ mod tests { ); } - #[test] - fn projected_weight_accounts_for_batch_replacements_once() { - assert_eq!(projected_batch_weight(90, 30, 50), 110); - assert_eq!(projected_batch_weight(10, 20, 5), 5); - } - #[test] fn owner_batch_keeps_only_the_last_event_for_each_key() { let desc = |weight_bytes, put_id| NodeValueReplicaDesc { diff --git a/fluxon_rs/fluxon_kv/src/master_lease_manager/lease.rs b/fluxon_rs/fluxon_kv/src/master_lease_manager/lease.rs index 1df23e3..eeb24e6 100755 --- a/fluxon_rs/fluxon_kv/src/master_lease_manager/lease.rs +++ b/fluxon_rs/fluxon_kv/src/master_lease_manager/lease.rs @@ -146,6 +146,15 @@ impl Lease { Ok(()) } + /// Remove only the exact version installed by a failed route publication. + /// A newer Put may already have rebound the same key, so key-only removal + /// would be an ABA bug. + pub fn detach_key_if_version(&self, key: &str, put_id: PutIDForAKey) -> bool { + self.keys + .remove_if(key, |_, current_put_id| *current_put_id == put_id) + .is_some() + } + // Note: no detach_all_keys semantics; deletion paths iterate keys directly. /// Get all keys with their put_id information diff --git a/fluxon_rs/fluxon_kv/src/master_lease_manager/lease_manager_test.rs b/fluxon_rs/fluxon_kv/src/master_lease_manager/lease_manager_test.rs index 5d344c9..ed7f6be 100755 --- a/fluxon_rs/fluxon_kv/src/master_lease_manager/lease_manager_test.rs +++ b/fluxon_rs/fluxon_kv/src/master_lease_manager/lease_manager_test.rs @@ -350,6 +350,36 @@ async fn test5_eviction_when_lease_consumes_space() { leased_success_keys.len() ); + // Rounded allocations and the three reclaimable normal keys mean that a + // fixed 19 * 5MiB loop does not itself prove the physical segment is full. + // Establish the precondition explicitly before asserting later NoSpace + // behavior; otherwise the first post-check lease put can legitimately use + // the final free 5MiB slot. + let mut reached_lease_full = false; + for i in 0..32u32 { + let k = format!("t5_lease_topoff_{}", i); + match client_view + .client_kv_api() + .put(&k, &leased_value, Some(lease_id)) + .await + { + Ok(()) => leased_success_keys.push(k), + Err(e) => { + assert!( + e.to_string().contains("NoSpace"), + "expected top-off to end in NoSpace, got: {}", + e + ); + reached_lease_full = true; + break; + } + } + } + assert!( + reached_lease_full, + "lease top-off did not establish a full physical segment" + ); + // Canvas assertion: assert 放成功的所有 lease key 都存在(TTL 尚未到期) tracing::info!( "[test5-assert-all-leased-keys-exist] verifying all successfully stored leased keys still exist before TTL expiry" diff --git a/fluxon_rs/fluxon_kv/src/master_lease_manager/master_lease_manager.rs b/fluxon_rs/fluxon_kv/src/master_lease_manager/master_lease_manager.rs index 86d6736..5eb2120 100644 --- a/fluxon_rs/fluxon_kv/src/master_lease_manager/master_lease_manager.rs +++ b/fluxon_rs/fluxon_kv/src/master_lease_manager/master_lease_manager.rs @@ -503,6 +503,21 @@ impl MasterLeaseManager { } } + /// Roll back one exact lease binding when its route publication did not + /// linearize. This is synchronous because it only touches the lease's + /// DashMap and is used from completion rollback paths. + pub fn detach_key_if_version( + &self, + lease_id: LeaseID, + key: &str, + put_id: PutIDForAKey, + ) -> bool { + self.inner() + .leases + .get(&lease_id) + .is_some_and(|lease| lease.detach_key_if_version(key, put_id)) + } + /// Get lease information /// pub fn get_lease(&self, lease_id: LeaseID) -> Option> { /// let leases_guard = self.leases.read(); diff --git a/fluxon_rs/fluxon_kv/src/master_seg_manager/mod.rs b/fluxon_rs/fluxon_kv/src/master_seg_manager/mod.rs index 8a50032..627d361 100644 --- a/fluxon_rs/fluxon_kv/src/master_seg_manager/mod.rs +++ b/fluxon_rs/fluxon_kv/src/master_seg_manager/mod.rs @@ -2,7 +2,7 @@ pub mod msg_pack; pub mod one_seg_allocator; use self::msg_pack::RequestSegmentRegistrationReq; use self::msg_pack::SegmentDeviceDescription; -use self::one_seg_allocator::OneSegAllocator; +use self::one_seg_allocator::{Allocation, OneSegAllocator}; use crate::cluster_manager::NodeID; use crate::p2p::p2p_module::P2pModuleAccessTrait; use crate::rpcresp_kvresult_convert::msg_and_error::OK; @@ -27,6 +27,7 @@ use std::time::Duration; fn register_node_segments( view: &MasterSegManagerView, node_id: NodeID, + node_start_time: i64, seg_map: std::collections::HashMap< SegmentDeviceID, (SegmentDeviceDescription, msg_pack::SegmentDeviceMemInfo), @@ -72,13 +73,29 @@ fn register_node_segments( device_id_2_allocator.insert(device_id, Arc::new(allocator)); } - v.insert(NodeSegmentsManager::new(total_size, device_id_2_allocator)); + v.insert(NodeSegmentsManager::new( + node_start_time, + total_size, + device_id_2_allocator, + )); } dashmap::mapref::entry::Entry::Occupied(mut occ) => { let node_segments_manager = occ.get_mut(); // Tomb means the previous instance has left/restarted; replace the full segment set. if node_segments_manager.tomb_tag.is_tomb() { + // An RPC response already in flight at MemberLeft must not resurrect the + // departed generation. Only a genuinely newer epoch may replace a tomb. + if node_segments_manager.node_start_time == node_start_time { + return Err(KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::RegisterSegmentFailed { + detail: format!( + "stale segment registration for tombed node generation: node={} node_start_time={}", + node_id, node_start_time + ), + }, + )); + } let mut total_size: u64 = 0; let mut device_id_2_allocator: HashMap> = HashMap::new(); @@ -100,12 +117,24 @@ fn register_node_segments( } *node_segments_manager = - NodeSegmentsManager::new(total_size, device_id_2_allocator); + NodeSegmentsManager::new(node_start_time, total_size, device_id_2_allocator); tracing::info!("RegisterSegment replaced tombed node: {}", node_id); return Ok(()); } - // Non-tomb: allow re-entrant registration (idempotent) to tolerate transient retries. + if node_segments_manager.node_start_time != node_start_time { + return Err(KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::RegisterSegmentFailed { + detail: format!( + "new segment generation attempted to replace a live generation: node={} live_node_start_time={} requested_node_start_time={}", + node_id, node_segments_manager.node_start_time, node_start_time + ), + }, + )); + } + + // Non-tomb, same generation: allow re-entrant registration (idempotent) to + // tolerate transient retries. for (device_id, (seg_device_desc, seg_mem_info)) in seg_map { if let Some(existing) = node_segments_manager.device_id_2_allocator.get(&device_id) { @@ -181,9 +210,15 @@ impl NodeTombTag { pub fn set_tomb(&self) { self.0.store(true, Ordering::Release); } + + /// True only when both tags belong to the same node registration generation. + pub fn same_generation(&self, other: &Self) -> bool { + Arc::ptr_eq(&self.0, &other.0) + } } pub struct NodeSegmentsManager { + node_start_time: i64, total_size: u64, device_id_2_allocator: HashMap>, tomb_tag: NodeTombTag, @@ -191,10 +226,12 @@ pub struct NodeSegmentsManager { impl NodeSegmentsManager { pub fn new( + node_start_time: i64, total_size: u64, device_id_2_allocator: HashMap>, ) -> Self { Self { + node_start_time, total_size, device_id_2_allocator, tomb_tag: NodeTombTag::new(), @@ -298,11 +335,30 @@ impl MasterSegManager { // allocator.clone().allocate(size) // } - pub fn mark_node_tomb(&self, node_id: &NodeID) { + pub fn mark_node_tomb(&self, node_id: &NodeID) -> Option { + self.mark_node_tomb_generation(node_id, None) + } + + /// Mark one exact membership generation as departed and return its shared tomb tag. + /// A delayed leave for an older epoch must not tomb a newly registered generation that + /// happens to reuse the same node id. + pub fn mark_node_tomb_generation( + &self, + node_id: &NodeID, + expected_node_start_time: Option, + ) -> Option { if let Some(allocators_and_tomb_tag) = self.inner().node_allocators_and_tomb_tag.get(node_id) { + if expected_node_start_time + .is_some_and(|expected| allocators_and_tomb_tag.node_start_time != expected) + { + return None; + } allocators_and_tomb_tag.tomb_tag.set_tomb(); + Some(allocators_and_tomb_tag.tomb_tag.clone()) + } else { + None } } @@ -316,6 +372,28 @@ impl MasterSegManager { } } + /// Resolve the registration generation that owns an already-created allocation. + /// + /// A plain `get_node_tomb_tag(node_id)` is insufficient: the node may have left and + /// re-registered between allocation and completion. In that case the current tag belongs + /// to a different allocator set and must never be attached to the old allocation. + pub fn get_allocation_tomb_tag( + &self, + node_id: &NodeID, + allocation: &Allocation, + ) -> Option { + let node = self.inner().node_allocators_and_tomb_tag.get(node_id)?; + if node.tomb_tag.is_tomb() + || !node + .device_id_2_allocator + .values() + .any(|allocator| allocation.belongs_to_allocator(allocator)) + { + return None; + } + Some(node.tomb_tag.clone()) + } + pub fn get_node_allocators(&self, node_id: &NodeID) -> Vec> { let mut ret = Vec::new(); if let Some(node_allocators) = self.inner().node_allocators_and_tomb_tag.get(node_id) { @@ -417,7 +495,12 @@ impl MasterSegManager { ); // Now, register these segments in the master. - match register_node_segments(inner.view(), node_id.clone(), resp.serialize_part.seg_map) { + match register_node_segments( + inner.view(), + node_id.clone(), + expected_node_start_time, + resp.serialize_part.seg_map, + ) { Ok(()) => { tracing::info!("Successfully registered segments for node {}", node_id); } @@ -434,6 +517,7 @@ impl MasterSegManager { self.inner() .node_allocators_and_tomb_tag .get(node_id) + .filter(|node_segments_manager| !node_segments_manager.tomb_tag.is_tomb()) .map(|node_segments_manager| node_segments_manager.total_size) .unwrap_or(0) } diff --git a/fluxon_rs/fluxon_kv/src/master_seg_manager/one_seg_allocator.rs b/fluxon_rs/fluxon_kv/src/master_seg_manager/one_seg_allocator.rs index 6dcd136..18eaf66 100755 --- a/fluxon_rs/fluxon_kv/src/master_seg_manager/one_seg_allocator.rs +++ b/fluxon_rs/fluxon_kv/src/master_seg_manager/one_seg_allocator.rs @@ -72,6 +72,15 @@ impl Allocation { self.allocator.base_addr } + /// Returns whether this allocation was created by the exact allocator instance. + /// + /// Segment names and node ids are reusable after a node reconnects. Pointer identity is + /// therefore the only safe way for master-side completion paths to bind an allocation back + /// to the registration generation that created it. + pub(crate) fn belongs_to_allocator(&self, allocator: &Arc) -> bool { + Arc::ptr_eq(&self.allocator, allocator) + } + /// Attach an on-drop callback. It will be executed exactly once /// when this allocation is dropped. pub fn set_on_drop(&mut self, f: F) diff --git a/fluxon_rs/fluxon_kv/src/memholder/lifetime.rs b/fluxon_rs/fluxon_kv/src/memholder/lifetime.rs index 1ea35eb..e070b1d 100755 --- a/fluxon_rs/fluxon_kv/src/memholder/lifetime.rs +++ b/fluxon_rs/fluxon_kv/src/memholder/lifetime.rs @@ -721,6 +721,86 @@ pub struct OwnerExternalMemMgr { inner: MemholderManagerInner, } +impl OwnerExternalMemMgr { + /// Remove only holdings owned by the departed membership generation. + /// Node ids are reusable, so node-only cleanup can release memory still in + /// use by a reconnected external requester. + pub fn cleanup_node_generation(&self, node_id: &str, node_start_time: i64) -> usize { + let keys = self + .inner + .as_map() + .iter() + .filter_map(|entry| { + owner_external_holding_matches_generation( + &entry.value().req_node_id, + entry.value().requester_node_start_time, + node_id, + node_start_time, + ) + .then(|| entry.key().clone()) + }) + .collect::>(); + + keys.into_iter() + .filter(|key| { + self.inner + .as_map() + .remove_if(key, |_, holding| { + owner_external_holding_matches_generation( + &holding.req_node_id, + holding.requester_node_start_time, + node_id, + node_start_time, + ) + }) + .is_some() + }) + .count() + } +} + +fn owner_external_holding_matches_generation( + holding_node_id: &str, + holding_node_start_time: Option, + departed_node_id: &str, + departed_node_start_time: i64, +) -> bool { + holding_node_id == departed_node_id && holding_node_start_time == Some(departed_node_start_time) +} + +#[cfg(test)] +mod owner_external_generation_tests { + use super::owner_external_holding_matches_generation; + + #[test] + fn holding_cleanup_never_matches_reconnected_or_unknown_generation() { + assert!(owner_external_holding_matches_generation( + "external-a", + Some(11), + "external-a", + 11, + )); + assert!(!owner_external_holding_matches_generation( + "external-a", + Some(12), + "external-a", + 11, + )); + assert!(!owner_external_holding_matches_generation( + "external-a", + None, + "external-a", + 11, + )); + assert!(!owner_external_holding_matches_generation( + "external-b", + Some(11), + "external-a", + 11, + )); + } +} + impl Default for OwnerExternalMemMgr { fn default() -> Self { Self { @@ -762,15 +842,21 @@ impl MemholderManagerTrait for OwnerExternalMemMgr { if holding.key != task.key { continue; } + let Some(holding_epoch) = holding.requester_node_start_time else { + continue; + }; let Some(member) = ctx .cluster_manager() .get_member_info_cached(&holding.req_node_id) else { continue; }; + if member.node_start_time != holding_epoch { + continue; + } targets.insert(DeleteTargetMember::new( holding.req_node_id.clone(), - member.node_start_time, + holding_epoch, )); } targets.into_iter().collect() diff --git a/fluxon_rs/fluxon_kv/src/memholder/mod.rs b/fluxon_rs/fluxon_kv/src/memholder/mod.rs index 0cd6a6f..7221f2d 100755 --- a/fluxon_rs/fluxon_kv/src/memholder/mod.rs +++ b/fluxon_rs/fluxon_kv/src/memholder/mod.rs @@ -194,6 +194,30 @@ impl MemoryInfo { .expect("segment cpu mem must be available when creating resident MemoryInfo"); base_guard.allocated_addr }; + Self::new_local_reserve_resident_with_base( + addr, + base_addr, + len, + key, + master_node_id, + view, + slot_size, + grant_id, + slot_index, + ) + } + + pub fn new_local_reserve_resident_with_base( + addr: u64, + base_addr: u64, + len: u32, + key: String, + master_node_id: NodeID, + view: ClientKvApiView, + slot_size: u64, + grant_id: u64, + slot_index: u32, + ) -> Self { assert!( addr >= base_addr, "resident local reserve addr must be within client segment: addr={:#x} base_addr={:#x}", diff --git a/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/msg_and_error.rs b/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/msg_and_error.rs index d771141..5f6e8ca 100644 --- a/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/msg_and_error.rs +++ b/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/msg_and_error.rs @@ -77,6 +77,12 @@ pub enum MsgId { BatchEnqueueReplicaTaskResp = 3062, GroupedBatchPutDoneReq = 3063, GroupedBatchPutDoneResp = 3064, + BatchPutAppendStartReq = 3065, + BatchPutAppendStartResp = 3066, + BatchPutAppendDoneReq = 3067, + BatchPutAppendDoneResp = 3068, + BatchEvictOwnerSourceReq = 3069, + BatchEvictOwnerSourceResp = 3070, ExternalGetReq = 4001, ExternalGetResp = 4002, ExternalPutStartReq = 4003, diff --git a/fluxon_rs/fluxon_pyo3/src/lib.rs b/fluxon_rs/fluxon_pyo3/src/lib.rs index 693e873..412ec5f 100644 --- a/fluxon_rs/fluxon_pyo3/src/lib.rs +++ b/fluxon_rs/fluxon_pyo3/src/lib.rs @@ -3481,7 +3481,7 @@ impl KvClient { .client_kv_api_view() .client_kv_api() .inner() - .reserve_local_grant(0, 0, false) + .reserve_local_grant() .await }) }) { @@ -3501,12 +3501,6 @@ impl KvClient { base_addr, len, }) => ApiResult::new_success((grant_id, addr, base_addr, len).into_py(py)), - Ok(ReserveLocalGrantOutcome::Reclaimed { .. }) => { - ApiResult::new_error(new_general_error( - py, - "raw reserve_local_grant request unexpectedly reclaimed class slots", - )) - } Ok(ReserveLocalGrantOutcome::None) => { unreachable!("reserve_local_grant filters empty successful outcomes") } @@ -4202,55 +4196,38 @@ impl KvClient { slot_ref.slot_index, ) .await; - inner.install_precommit_local_visible_memory_info( - key, - memory_info.clone(), - ); + inner.install_precommit_local_visible_memory_info(key, memory_info); let put_id = put_ids[idx]; - let promote = inner - .promote_precommit_local_reserve_resident_slot_if_same( - key, - put_id, - memory_info.clone(), - atomic_groups[idx].as_ref(), - ); - match promote { - Ok(()) => { - inner.record_put_locality(false, owner_data.value_len, 0); - publish_items.push(OwnerLocalPublishItem { - key: key.clone(), - put_id, - value_len: owner_data.value_len, - lease_id: None, - committed_slot: PutDoneCommittedSlot { - grant_id: slot_ref.grant_id, - slot_index: slot_ref.slot_index, - slot_size, - addr: slot_ref.ptr, - base_addr: slot_ref.base_addr, - len: owner_data.value_len, - }, - make_replica_task: *make_replica_task, - preferred_sub_cluster: None, - atomic_group: atomic_groups[idx].clone(), - }); - ret_codes.push(0); - } - Err(err) => { - let _ = inner - .remove_precommit_local_reserve_resident_slot_if_same( - key, - &memory_info, - ); - ret_codes.push(kv_error_to_ret_code(&err)); - } - } + inner.record_put_locality(false, owner_data.value_len, 0); + publish_items.push(OwnerLocalPublishItem { + key: key.clone(), + put_id, + value_len: owner_data.value_len, + lease_id: None, + committed_slot: PutDoneCommittedSlot { + grant_id: slot_ref.grant_id, + slot_index: slot_ref.slot_index, + slot_size, + addr: slot_ref.ptr, + base_addr: slot_ref.base_addr, + len: owner_data.value_len, + }, + make_replica_task: *make_replica_task, + preferred_sub_cluster: None, + atomic_group: atomic_groups[idx].clone(), + }); + ret_codes.push(0); } if !publish_items.is_empty() { + let publish_keys = publish_items + .iter() + .map(|item| item.key.clone()) + .collect::>(); if let Err(err) = inner .enqueue_owner_local_publish(OwnerLocalPublishJob { items: publish_items, key_reservation_ids: owner_data.key_reservation_ids.clone(), + external_pending_contexts: Vec::new(), }) .await { @@ -4258,6 +4235,17 @@ impl KvClient { "local_fast_put_commit owner local publish enqueue failed after local commit: {}", err ); + for key in publish_keys { + if let Some(memory_info) = + inner.precommit_local_visible_memory_info(&key) + { + let _ = inner + .remove_precommit_local_reserve_resident_slot_if_same( + &key, + &memory_info, + ); + } + } if let Err(cleanup_err) = release_put_key_reservations_only( inner, owner_data.key_reservation_ids, diff --git a/pegaflow b/pegaflow new file mode 160000 index 0000000..939363f --- /dev/null +++ b/pegaflow @@ -0,0 +1 @@ +Subproject commit 939363f198a0ffded9e3f30d8af9cdd74439f16c diff --git a/scripts/preview_doc_html.py b/scripts/preview_doc_html.py new file mode 100755 index 0000000..18f5093 --- /dev/null +++ b/scripts/preview_doc_html.py @@ -0,0 +1,547 @@ +#!/usr/bin/env python3 +"""Generate a standalone HTML preview for a Markdown document.""" + +from __future__ import annotations + +import argparse +import hashlib +import json +import os +import re +import subprocess +import sys +from pathlib import Path + + +REPO_ROOT = Path(__file__).resolve().parents[1] +DEFAULT_OUTPUT_ROOT = REPO_ROOT / ".dever/html_preview" + + +HTML_TEMPLATE = """ + + + + + {title} + + + + + + +

+
{title}
+
+ Waiting + + +
+
+ +
+
+
+ + + + + + + + + + + +""" + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Generate a standalone HTML preview for a Markdown document with Mermaid fullscreen zoom/pan support." + ) + parser.add_argument( + "markdown_path", + type=Path, + help="Markdown input path.", + ) + parser.add_argument( + "--output", + type=Path, + default=None, + help=f"HTML output path. Default: {DEFAULT_OUTPUT_ROOT.relative_to(REPO_ROOT)}/.html", + ) + parser.add_argument( + "--open", + action="store_true", + help="Open the generated HTML file with the system browser.", + ) + return parser.parse_args() + + +def default_output_path(input_path: Path) -> Path: + try: + relative_input = input_path.relative_to(REPO_ROOT) + except ValueError: + digest = hashlib.sha256(str(input_path).encode("utf-8")).hexdigest()[:12] + relative_input = Path("external") / f"{input_path.stem}-{digest}{input_path.suffix}" + return (DEFAULT_OUTPUT_ROOT / relative_input).with_suffix(".html") + + +def infer_html_lang(input_path: Path, markdown: str) -> str: + parts = set(input_path.parts) + if "fluxon_doc_cn" in parts or input_path.name == "README_CN.md": + return "zh-CN" + if "fluxon_doc_en" in parts or input_path.name == "README.md": + return "en" + return "zh-CN" if re.search(r"[\u4e00-\u9fff]", markdown) else "en" + + +def first_markdown_heading(markdown: str, fallback: str) -> str: + for line in markdown.splitlines(): + stripped = line.strip() + if stripped.startswith("# "): + return stripped[2:].strip() or fallback + return fallback + + +def open_in_browser(path: Path) -> None: + if sys.platform == "darwin": + subprocess.run(["open", str(path)], check=False) + elif os.name == "nt": + os.startfile(str(path)) # type: ignore[attr-defined] + else: + subprocess.run(["xdg-open", str(path)], check=False) + + +def main() -> int: + args = parse_args() + input_path = args.markdown_path.resolve() + + if not input_path.exists(): + print(f"Input markdown does not exist: {input_path}", file=sys.stderr) + return 1 + if not input_path.is_file(): + print(f"Input path is not a file: {input_path}", file=sys.stderr) + return 1 + + output_path = args.output.resolve() if args.output else default_output_path(input_path) + + markdown = input_path.read_text(encoding="utf-8") + title = first_markdown_heading(markdown, input_path.stem) + html = HTML_TEMPLATE.format( + title=title, + html_lang=infer_html_lang(input_path, markdown), + markdown_json=json.dumps(markdown, ensure_ascii=False), + ) + + output_path.parent.mkdir(parents=True, exist_ok=True) + output_path.write_text(html, encoding="utf-8") + + print(f"Generated HTML preview: {output_path}") + print("Open it in a browser. Mermaid fullscreen zoom/pan uses CDN assets, so internet access is required.") + + if args.open: + open_in_browser(output_path) + + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From 568ef15fc6b7ed33adf850819e10e5cc5d7fcd5d Mon Sep 17 00:00:00 2001 From: zTz01 <1773266173@qq.com> Date: Sat, 18 Jul 2026 22:02:46 +0800 Subject: [PATCH 05/10] bak --- .../fluxon_kv/src/client_kv_api/delete.rs | 2 +- .../src/client_kv_api/external_api.rs | 6 +- fluxon_rs/fluxon_kv/src/client_kv_api/get.rs | 4 +- .../client_kv_api/local_reserve_rebalance.rs | 122 ++- fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs | 726 +++++++++++++++--- fluxon_rs/fluxon_kv/src/client_kv_api/put.rs | 207 +++-- .../fluxon_kv/src/client_kv_api/reclaim.rs | 75 ++ .../fluxon_kv/src/master_kv_router/mod.rs | 378 ++++++--- .../src/master_kv_router/msg_pack.rs | 10 +- .../fluxon_kv/src/master_kv_router/put.rs | 7 + .../fluxon_kv/src/master_kv_router/reclaim.rs | 351 +++++---- .../src/master_kv_router/route_maintenance.rs | 6 +- fluxon_rs/fluxon_kv/src/memholder/mod.rs | 11 + fluxon_rs/fluxon_util/src/lib.rs | 1 + fluxon_rs/fluxon_util/src/pin_aware_moka.rs | 671 ++++++++++++++++ 15 files changed, 2104 insertions(+), 473 deletions(-) create mode 100644 fluxon_rs/fluxon_util/src/pin_aware_moka.rs diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/delete.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/delete.rs index 973a453..809ca0e 100755 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/delete.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/delete.rs @@ -93,7 +93,7 @@ async fn apply_delete_client_kv_meta_cache_item( let controls = client_inner.owner_key_control.lock_key(&delete_item.key); if controls .get(&delete_item.key) - .is_some_and(|state| state.reclaim.is_some()) + .is_some_and(|state| state.local_access_fenced()) { tracing::debug!( "skip legacy local-index delete while owner reclaim fence is active: key={}", diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs index 42fe4e7..015d41c 100755 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs @@ -1132,6 +1132,7 @@ mod external_get_start_batch_tests { OwnerKeyControlState { local_puts: 0, external_pending_puts: 0, + source_eviction_selection: None, reclaim: None, external_get: Some(old.clone()), }, @@ -1159,6 +1160,7 @@ mod external_get_start_batch_tests { OwnerKeyControlState { local_puts: 0, external_pending_puts: 0, + source_eviction_selection: None, reclaim: None, external_get: Some(op.clone()), }, @@ -1422,7 +1424,7 @@ async fn plan_external_get_key_items( } else { let fenced = controls .get(key) - .is_some_and(|state| state.reclaim.is_some()); + .is_some_and(|state| state.local_access_fenced()); if !fenced { if let Some(memory_info) = inner.local_visible_mem_holder_unfenced(key) { let hot_touch = inner.get_cached_info.get(key).and_then(|cached| { @@ -2000,7 +2002,7 @@ async fn finish_external_get_key_leaders( match finish_result { Ok(results) if results.len() == batch.len() => { // Publish each confirmed sub-batch immediately. A different - // uncertain Done cohort therefore cannot retain these flights + // uncertain Done atomic_batch therefore cannot retain these flights // or their pending-visible slots. for ((op, _), result) in batch.into_iter().zip(results) { let phase = match result { diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs index 874107a..8cfbf99 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs @@ -621,7 +621,7 @@ impl ClientKvApiInner { } // All members are in get_cached_info before any hot admission can evict one of them. - // This keeps atomic/TP cohort write-back decisions complete. + // This keeps atomic/TP atomic_batch write-back decisions complete. for (key, put_id, memory_info, atomic_group) in local_hot_admissions { self.owner_hot_track_committed(&key, put_id, &memory_info, atomic_group.as_ref()); } @@ -1495,7 +1495,7 @@ impl ClientKvApiInner { // committed-slot Done. Bound the number of callers entering that path // so a capacity scan cannot park every master Tokio worker on Moka's // blocking housekeeper lock. The permit covers one RPC attempt only; - // idempotent retry backoff releases it and lets other cohorts converge. + // idempotent retry backoff releases it and lets other atomic_batches converge. let _done_rpc_permit = batch_get_done_rpc_limiter() .acquire() .await diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/local_reserve_rebalance.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/local_reserve_rebalance.rs index 08ad95e..a9db5e5 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/local_reserve_rebalance.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/local_reserve_rebalance.rs @@ -10,7 +10,7 @@ const OWNER_LOCAL_RESERVE_REBALANCE_INTERVAL: Duration = Duration::from_millis(2 const OWNER_LOCAL_RESERVE_SHRINK_IDLE_COOLDOWN: Duration = Duration::from_secs(5); const OWNER_LOCAL_RESERVE_SHRINK_GROW_COOLDOWN: Duration = Duration::from_secs(1); const OWNER_LOCAL_RESERVE_DEFAULT_SOFT_WAIT_TIMEOUT: Duration = Duration::from_millis(10); -// Cohort-safe master route deletion plus owner slot release is asynchronous. +// AtomicBatch-safe master route deletion plus owner slot release is asynchronous. // Thirty seconds turns a recoverable pressure burst into a storage exception that // can wedge SGLang's detokenizer. This remains well below the external request // timeout while allowing bounded backpressure to finish reclaiming slots. @@ -19,8 +19,17 @@ const OWNER_LOCAL_RESERVE_MIN_GRANTS_PER_CLASS: usize = 0; const OWNER_LOCAL_RESERVE_REPORT_INTERVAL: Duration = Duration::from_secs(30); const OWNER_LOCAL_RESERVE_FREE_SLOT_HEADROOM_GRANTS: usize = 4; const OWNER_SLOT_PRESSURE_INTERVAL: Duration = Duration::from_millis(10); -const OWNER_SLOT_PRESSURE_MIN_KICK_INTERVAL: Duration = Duration::from_millis(200); -const OWNER_SLOT_PRESSURE_MAX_EVICT_BYTES: u64 = 256 * 1024 * 1024; +// Source deletion now has an exact, idempotent owner -> master transaction and +// selection debt accounts for candidates until their slots are physically Free. +// Keep pressure retries responsive: a 200 ms gate used to surface directly as +// local_fast_put_start tail latency whenever one bounded kick was insufficient. +const OWNER_SLOT_PRESSURE_MIN_KICK_INTERVAL: Duration = Duration::from_millis(25); +// One 512 MiB grant contains 113 production KV slots. The old 256 MiB cap was +// smaller than a single grant and could never refill the configured four-grant +// high watermark in one pass. Bound a kick at eight grants so it covers the +// four-grant retained headroom plus a normal large claimant, while selection +// debt still prevents repeated over-selection before physical reclaim lands. +const OWNER_SLOT_PRESSURE_MAX_EVICT_BYTES: u64 = OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES * 8; #[derive(Debug, Clone, Copy)] struct ExpectedCapacityLayout { @@ -72,7 +81,7 @@ fn owner_local_reserve_target_grant_count( fn owner_slot_pressure_request_bytes( snapshot: RebalanceClassSnapshot, - outstanding_selection_debt_bytes: u64, + source_eviction_selected_bytes: u64, ) -> u64 { let low_watermark = (snapshot.slots_per_grant as usize) .saturating_mul(2) @@ -80,7 +89,7 @@ fn owner_slot_pressure_request_bytes( let high_watermark = (snapshot.slots_per_grant as usize) .saturating_mul(OWNER_LOCAL_RESERVE_FREE_SLOT_HEADROOM_GRANTS); let projected_eviction_slots = - usize::try_from(outstanding_selection_debt_bytes / snapshot.slot_size.max(1)) + usize::try_from(source_eviction_selected_bytes / snapshot.slot_size.max(1)) .unwrap_or(usize::MAX); let projected_free_slots = snapshot.free_slots.saturating_add(projected_eviction_slots); let pressure_active = @@ -96,6 +105,17 @@ fn owner_slot_pressure_request_bytes( .min(OWNER_SLOT_PRESSURE_MAX_EVICT_BYTES) } +fn owner_slot_pressure_projected_reclaim_bytes(inner: &ClientKvApiInner) -> u64 { + // Candidate debt starts in Moka's synchronous eviction listener. A + // candidate that is incomplete, pinned, or waiting in the retry queue has + // no installed owner fence and cannot release a slot. Only exact selected + // source debt is valid projected reclaim credit. + inner + .owner_hot_counters + .source_eviction_selected_bytes + .load(std::sync::atomic::Ordering::Acquire) +} + fn owner_local_reserve_desired_free_slots(snapshot: RebalanceClassSnapshot) -> usize { let configured_headroom = if snapshot.expected_grant_count == 0 { 0 @@ -359,6 +379,8 @@ async fn try_shrink_once(inner: &ClientKvApiInner, snapshot: RebalanceClassSnaps #[cfg(test)] mod tests { use super::*; + use crate::client_kv_api::OwnerHotCacheCounters; + use std::sync::atomic::Ordering; const SLOT_SIZE: u64 = 8 * 1024 * 1024; @@ -500,8 +522,8 @@ mod tests { used_slots: 64, free_slots: 1, grant_count: 1, - pending_slot_demand: 100, - max_observed_claim_slots: 100, + pending_slot_demand: 1_000, + max_observed_claim_slots: 1_000, expected_grant_count: 1, }; assert_eq!( @@ -509,6 +531,84 @@ mod tests { OWNER_SLOT_PRESSURE_MAX_EVICT_BYTES ); } + + #[test] + fn retry_candidate_debt_is_not_projected_reclaim_credit() { + let snapshot = RebalanceClassSnapshot { + slot_size: 1024 * 1024, + slots_per_grant: 4, + used_slots: 4, + free_slots: 1, + grant_count: 1, + pending_slot_demand: 3, + max_observed_claim_slots: 3, + expected_grant_count: 1, + }; + let counters = OwnerHotCacheCounters::default(); + counters + .selection_debt_bytes + .store(10 * 1024 * 1024, Ordering::Release); + + assert_eq!( + counters + .source_eviction_selected_bytes + .load(Ordering::Acquire), + 0 + ); + assert_eq!( + owner_slot_pressure_request_bytes( + snapshot, + counters + .source_eviction_selected_bytes + .load(Ordering::Acquire), + ), + 18 * 1024 * 1024, + "retry-only candidate debt must not suppress physical victim selection" + ); + + counters.add_source_eviction_selected_bytes(10 * 1024 * 1024); + assert_eq!( + owner_slot_pressure_request_bytes( + snapshot, + counters + .source_eviction_selected_bytes + .load(Ordering::Acquire), + ), + 8 * 1024 * 1024, + "only installed source-selection debt is valid projected reclaim credit" + ); + counters.remove_source_eviction_selected_bytes(10 * 1024 * 1024); + assert_eq!( + counters + .source_eviction_selected_bytes + .load(Ordering::Acquire), + 0 + ); + } + + #[test] + fn production_pressure_fills_high_watermark_in_one_kick() { + const VALUE_LEN: u64 = 4_718_592; + let slots_per_grant = crate::owner_local_reserve_slots_per_grant(VALUE_LEN).unwrap(); + assert_eq!(slots_per_grant, 113); + let snapshot = RebalanceClassSnapshot { + slot_size: VALUE_LEN, + slots_per_grant, + used_slots: 113 * 174 - 8, + free_slots: 8, + grant_count: 174, + pending_slot_demand: 128, + max_observed_claim_slots: 128, + expected_grant_count: 174, + }; + let requested = owner_slot_pressure_request_bytes(snapshot, 0); + assert_eq!( + requested, + u64::from(128_u32 + slots_per_grant * 4 - 8) * VALUE_LEN, + "one pressure kick must cover the claimant and retained four-grant headroom" + ); + assert!(requested < OWNER_SLOT_PRESSURE_MAX_EVICT_BYTES); + } } async fn owner_local_reserve_rebalance_once(view: &ClientKvApiView) { @@ -639,10 +739,8 @@ pub fn spawn_owner_slot_pressure_actor(view: ClientKvApiView) { { continue; } - let outstanding_selection_debt_bytes = inner - .owner_hot_counters - .selection_debt_bytes - .load(std::sync::atomic::Ordering::Acquire); + let source_eviction_selected_bytes = + owner_slot_pressure_projected_reclaim_bytes(inner); let requested_bytes = { let pool = inner.owner_local_reserve_pool.lock(); let snapshots = snapshot_rebalance_classes(&pool); @@ -652,7 +750,7 @@ pub fn spawn_owner_slot_pressure_actor(view: ClientKvApiView) { [] => 0, [snapshot] => owner_slot_pressure_request_bytes( *snapshot, - outstanding_selection_debt_bytes, + source_eviction_selected_bytes, ), _ => { // Selection is intentionally disabled until the victim diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs index d5843c4..efb4dde 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs @@ -50,12 +50,12 @@ use crate::{ rpcresp_kvresult_convert::msg_and_error::{ApiError, ErrorCode, KvError, KvResult}, }; use async_trait::async_trait; -use dashmap::DashMap; +use dashmap::{DashMap, mapref::entry::Entry as DashMapEntry}; use fluxon_framework::{LogicalModule, define_module}; use fluxon_util::map_lock::AMapLock; +use fluxon_util::pin_aware_moka::{PinAwareMoka, PinGuard}; use limit_thirdparty::tokio; use moka::notification::RemovalCause; -use moka::ops::compute::Op as MokaComputeOp; use parking_lot::Mutex; use std::collections::BTreeSet; use std::collections::HashMap; @@ -83,6 +83,7 @@ pub struct ExternalHoldingGetInfo { /// MemberLeft cleanup. pub requester_node_start_time: Option, pub memory_info: Arc, // The actual memholder being held + _owner_hot_pin: Option, } #[derive(Clone, Debug, Default)] @@ -115,8 +116,10 @@ pub struct OwnerRuntimeObserveSnapshot { pub hot_source_evict_retry_scheduled: u64, pub hot_source_evict_retry_emitted: u64, pub hot_selection_debt_bytes: u64, + pub hot_source_eviction_selected_bytes: u64, pub hot_eviction_skipped_stale: u64, pub hot_eviction_skipped_reclaim: u64, + pub hot_eviction_skipped_active_holders: u64, pub hot_group_registry_entries: u64, pub hot_group_trigger_duplicates: u64, pub hot_group_trigger_incomplete: u64, @@ -145,7 +148,7 @@ pub enum ExternalGetStartOwnerItem { /// /// A pending prefix decision is owned by this guard, not by control flow. If /// the request future is cancelled at any await point, Drop retires the -/// undecided count so the cohort task can still choose Finish or Revoke. +/// undecided count so the atomic_batch task can still choose Finish or Revoke. pub struct ExternalGetKeyInterest { op: Arc, decision_pending: bool, @@ -210,7 +213,7 @@ pub enum ExternalGetKeySharedPhase { Started { item: BatchGetStartItemResp, }, - /// At least one request plan's prefix retained this key. The leader cohort is + /// At least one request plan's prefix retained this key. The leader atomic_batch is /// transferring/completing it and later publishes one canonical result. Finishing { item: BatchGetStartItemResp, @@ -1233,6 +1236,23 @@ struct OwnerHotCacheEntry { weight_bytes: u32, } +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +pub(crate) struct OwnerHotPinAlias { + key: String, + memory_info_ptr: usize, +} + +impl OwnerHotPinAlias { + fn new(memory_info: &Arc) -> Self { + Self { + key: memory_info.key.clone(), + memory_info_ptr: Arc::as_ptr(memory_info) as usize, + } + } +} + +type OwnerHotCache = PinAwareMoka; + #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] pub(crate) struct OwnerHotReplicaIdentity { key: String, @@ -1261,8 +1281,12 @@ struct OwnerHotCacheCounters { source_evict_retry_scheduled: AtomicU64, source_evict_retry_emitted: AtomicU64, selection_debt_bytes: Arc, + /// Bytes behind an installed source-selection fence. Unlike candidate + /// debt, every byte here can become a physical Free slot after reclaim. + source_eviction_selected_bytes: AtomicU64, skipped_stale: AtomicU64, skipped_reclaim: AtomicU64, + skipped_active_holders: AtomicU64, group_trigger_duplicates: AtomicU64, group_trigger_incomplete: AtomicU64, grouped_put_done_batches: AtomicU64, @@ -1302,18 +1326,37 @@ impl OwnerHotSelectionDebt { } } +impl OwnerHotCacheCounters { + fn add_source_eviction_selected_bytes(&self, bytes: u64) { + self.source_eviction_selected_bytes + .fetch_update(Ordering::AcqRel, Ordering::Acquire, |current| { + current.checked_add(bytes) + }) + .expect("owner source-selection byte credit overflowed"); + } + + fn remove_source_eviction_selected_bytes(&self, bytes: u64) { + self.source_eviction_selected_bytes + .fetch_update(Ordering::AcqRel, Ordering::Acquire, |current| { + current.checked_sub(bytes) + }) + .expect("owner source-selection byte credit underflowed"); + } +} + #[derive(Clone)] pub(crate) struct OwnerHotEvictionEvent { key: String, put_id: crate::master_kv_router::put::PutIDForAKey, memory_info: Weak, selection_debt: Arc, - /// Retry events already own one exact source-delete cohort. + /// The event was dispatched from the bounded retry queue. It may be a + /// pre-selection retry (no atomic_batch yet) or an exact installed-atomic_batch retry. retry: bool, - /// Exact owner source-delete cohort retained across RPC retries. Once set, - /// retries never re-expand or re-pin the local cohort. - source_eviction_cohort: - Option>, + /// Exact owner source-delete atomic_batch retained across RPC retries. Once set, + /// retries never re-expand or re-pin the local atomic_batch. + source_eviction_atomic_batch: + Option>, /// Failure count follows the event while it is dispatched, preserving /// exponential backoff across queue take/reinsert cycles. retry_failures: u32, @@ -1325,7 +1368,17 @@ pub(crate) enum OwnerHotEvictionPreparation { sources: Vec<(OwnerHotReplicaIdentity, Arc)>, }, RetryableReclaimFence, - RetryableIncompleteCohort, + RetryableIncompleteAtomicBatch, + TemporarilyPinned { + active_members: usize, + }, + Obsolete, +} + +pub(crate) enum OwnerHotSelectionFenceOutcome { + Fenced, + Retryable, + TemporarilyPinned { active_members: usize }, Obsolete, } @@ -1398,8 +1451,8 @@ impl OwnerHotRetryQueue { if !Arc::ptr_eq(&entry.event.selection_debt, &event.selection_debt) { entry.event.selection_debt.release(); } - if event.source_eviction_cohort.is_none() { - event.source_eviction_cohort = entry.event.source_eviction_cohort.clone(); + if event.source_eviction_atomic_batch.is_none() { + event.source_eviction_atomic_batch = entry.event.source_eviction_atomic_batch.clone(); } entry.failures = entry.failures.max(event.retry_failures).saturating_add(1); event.retry = true; @@ -1497,6 +1550,11 @@ pub(crate) struct OwnerPreparedReclaim { local_snapshot: Option, } +pub(crate) struct OwnerSourceEvictionSelection { + put_id: crate::master_kv_router::put::PutIDForAKey, + cached_info: GetCachedInfo, +} + pub(crate) enum OwnerReclaimRecord { Prepared(OwnerPreparedReclaim), /// The local index is fenced and the Commit handler owns the detached @@ -1515,6 +1573,11 @@ pub(crate) struct OwnerKeyControlState { /// guard stored in every context, so cache invalidation cannot clear the /// reclaim fence while a cloned context is still in use. external_pending_puts: u32, + /// Owner-local pre-Prepare fence installed by the Moka source-eviction + /// dispatcher. The matching committed index is moved into this record, + /// so a new local Get cannot acquire the source between victim selection + /// and the master's reclaim Prepare RPC. + source_eviction_selection: Option, reclaim: Option, /// Per-key owner-side Get singleflight marker. It deliberately lives in /// the same fence as local visibility and reclaim so `R ∩ local`, @@ -1523,9 +1586,14 @@ pub(crate) struct OwnerKeyControlState { } impl OwnerKeyControlState { + fn local_access_fenced(&self) -> bool { + self.source_eviction_selection.is_some() || self.reclaim.is_some() + } + fn is_idle(&self) -> bool { self.local_puts == 0 && self.external_pending_puts == 0 + && self.source_eviction_selection.is_none() && self.reclaim.is_none() && self.external_get.is_none() } @@ -1671,7 +1739,7 @@ fn acquire_external_pending_put_fence_for_key( let mut controls = owner_key_control.lock_key(key); if controls .get(key) - .is_some_and(|state| state.reclaim.is_some()) + .is_some_and(|state| state.local_access_fenced()) { return Err(KvError::Api(ApiError::KeyBeingWritten { key: key.to_string(), @@ -1758,6 +1826,15 @@ fn clone_if_owner_hot_entry_matches( .then(|| current.clone()) } +fn owner_hot_source_has_active_holders(selected_source: &Arc) -> bool { + // A reclaimable committed source has exactly two strong references here: + // one in get_cached_info and one temporary selection pin. Any additional + // reference belongs to an active local reader/transfer. Sending such a + // source to the master would only make Prepare return Busy while its + // selection debt suppresses choosing a different, reclaimable victim. + Arc::strong_count(selected_source) > 2 +} + enum OwnerHotPinResult { Pinned(Arc), ReclaimBusy, @@ -1905,7 +1982,7 @@ fn pin_current_owner_hot_group_sources( Some(sources) } -fn owner_hot_tp_cohort_key_rows( +fn owner_hot_tp_atomic_batch_key_rows( identity: &OwnerHotReplicaIdentity, group: Option<&crate::master_kv_router::msg_pack::PutAtomicGroup>, ) -> Result>>, ()> { @@ -1954,8 +2031,8 @@ fn owner_hot_tp_cohort_key_rows( )) } -fn pin_current_owner_hot_tp_cohort_sources( - cohort_key_rows: &[Vec], +fn pin_current_owner_hot_tp_atomic_batch_sources( + atomic_batch_key_rows: &[Vec], expect_atomic_group: bool, get_cached_info: &DashMap, atomic_groups: &DashMap< @@ -1964,8 +2041,8 @@ fn pin_current_owner_hot_tp_cohort_sources( >, counters: &OwnerHotCacheCounters, ) -> Option)>> { - let mut cohort_sources = Vec::new(); - for rank_keys in cohort_key_rows { + let mut atomic_batch_sources = Vec::new(); + for rank_keys in atomic_batch_key_rows { if rank_keys.is_empty() { return None; } @@ -2013,9 +2090,9 @@ fn pin_current_owner_hot_tp_cohort_sources( } else if rank_sources.len() != 1 || atomic_groups.contains_key(&rank_sources[0].0) { return None; } - cohort_sources.extend(rank_sources); + atomic_batch_sources.extend(rank_sources); } - Some(cohort_sources) + Some(atomic_batch_sources) } fn build_owner_hot_cache( @@ -2023,13 +2100,12 @@ fn build_owner_hot_cache( counters: Arc, retry_queue: Arc, eviction_tx: tokio::sync::ampsc::UnboundedSender, -) -> moka::sync::Cache { +) -> OwnerHotCache { assert!( capacity_bytes > 0, "owner hot-cache capacity must be positive" ); - moka::sync::Cache::builder() - .max_capacity(capacity_bytes) + OwnerHotCache::builder(capacity_bytes) .weigher(|_key: &String, entry: &OwnerHotCacheEntry| entry.weight_bytes) .eviction_listener(move |key, entry, cause| { if cause != RemovalCause::Size { @@ -2051,7 +2127,7 @@ fn build_owner_hot_cache( memory_info: entry.memory_info.clone(), selection_debt, retry: false, - source_eviction_cohort: None, + source_eviction_atomic_batch: None, retry_failures: 0, }; if let Err(err) = eviction_tx.send(event) { @@ -2140,7 +2216,7 @@ pub struct ClientKvApiInner { owner_key_control: Arc, /// A weak-value admission/recency tier. It never owns resident memory and /// therefore cannot become a second physical-reclaim authority. - owner_hot_cache: Option>, + owner_hot_cache: Option, /// Exact selected identities remain here until their backing is physically /// Free or the source is restored to owner-hot. owner_source_eviction_selected: @@ -2300,56 +2376,206 @@ impl ClientKvApiInner { OwnerHotPinResult::Stale => return OwnerHotEvictionPreparation::Obsolete, }; - // A retry is authoritative for exactly one previously selected key. - // Re-expanding it would pin every cohort member again while the safe - // reclaim pipeline is waiting for those very pins to disappear. - if event.retry { - return OwnerHotEvictionPreparation::Ready { - trigger: trigger.clone(), - sources: vec![(trigger, memory_info)], - }; - } - - // Cohort lookup and pinning deliberately happen here, after the - // synchronous Moka listener has returned. Each source Arc is cloned - // directly from its current DashMap entry. A concurrent reclaim must - // wait for that shard read guard and then observes the extra strong - // reference, so no global owner-control lock is needed. + // A retry reaches this function only when no source-selection atomic_batch + // has been installed yet. Installed retries are handled from the + // event's exact `source_eviction_atomic_batch` before this method is called. + // Therefore a pre-selection retry must resolve the complete current + // TP/atomic atomic_batch again; degrading it to the trigger key would make + // the master reject a valid victim as an incomplete atomic_batch forever. + // AtomicBatch lookup and pinning deliberately happen after the synchronous + // Moka listener has returned. Each source Arc is cloned directly from + // its current DashMap entry. A concurrent reclaim must wait for that + // shard read guard and then observes the extra strong reference, so no + // global owner-control lock is needed. let group = self .owner_hot_atomic_groups .get(&trigger) .map(|entry| entry.value().clone()); - let cohort_sources = match owner_hot_tp_cohort_key_rows(&trigger, group.as_deref()) { - Ok(Some(cohort_key_rows)) => pin_current_owner_hot_tp_cohort_sources( - &cohort_key_rows, - group.is_some(), - self.get_cached_info.as_ref(), - self.owner_hot_atomic_groups.as_ref(), - self.owner_hot_counters.as_ref(), - ), - Ok(None) => match group.as_deref() { - Some(group) => pin_current_owner_hot_group_sources( - group, - self.get_cached_info.as_ref(), - self.owner_hot_counters.as_ref(), - ), - None => Some(vec![(trigger.clone(), memory_info)]), - }, - Err(()) => None, - }; - match cohort_sources { + let atomic_batch_sources = + match owner_hot_tp_atomic_batch_key_rows(&trigger, group.as_deref()) { + Ok(Some(atomic_batch_key_rows)) => { + // pin_current_owner_hot_tp_atomic_batch_sources clones the trigger + // again. Drop the probe pin first so the active-holder test + // below has the exact index + selection baseline of two Arcs. + drop(memory_info); + pin_current_owner_hot_tp_atomic_batch_sources( + &atomic_batch_key_rows, + group.is_some(), + self.get_cached_info.as_ref(), + self.owner_hot_atomic_groups.as_ref(), + self.owner_hot_counters.as_ref(), + ) + } + Ok(None) => match group.as_deref() { + Some(group) => { + drop(memory_info); + pin_current_owner_hot_group_sources( + group, + self.get_cached_info.as_ref(), + self.owner_hot_counters.as_ref(), + ) + } + None => Some(vec![(trigger.clone(), memory_info)]), + }, + Err(()) => None, + }; + match atomic_batch_sources { Some(sources) if !sources.is_empty() => { - OwnerHotEvictionPreparation::Ready { trigger, sources } + let active_members = sources + .iter() + .filter(|(_, source)| owner_hot_source_has_active_holders(source)) + .count(); + if active_members == 0 { + OwnerHotEvictionPreparation::Ready { trigger, sources } + } else { + OwnerHotEvictionPreparation::TemporarilyPinned { active_members } + } } _ => { self.owner_hot_counters .group_trigger_incomplete .fetch_add(1, Ordering::Relaxed); - OwnerHotEvictionPreparation::RetryableIncompleteCohort + OwnerHotEvictionPreparation::RetryableIncompleteAtomicBatch } } } + pub(crate) fn owner_hot_restore_source_selection( + &self, + identity: &OwnerHotReplicaIdentity, + ) -> bool { + let mut controls = self.owner_key_control.lock_key(&identity.key); + let Some(state) = controls.get_mut(&identity.key) else { + return false; + }; + let matches = state + .source_eviction_selection + .as_ref() + .is_some_and(|selection| { + selection.put_id == (identity.put_time_ms, identity.put_version) + }); + if !matches { + return false; + } + let selection = state + .source_eviction_selection + .take() + .expect("matching owner source selection must exist"); + let replaced = self + .get_cached_info + .insert(identity.key.clone(), selection.cached_info); + assert!( + replaced.is_none(), + "rolling back an owner source selection must restore an empty local index" + ); + if state.is_idle() { + controls.remove(&identity.key); + } + true + } + + fn owner_hot_install_source_selection_debt( + &self, + identity: OwnerHotReplicaIdentity, + debt: Arc, + ) -> bool { + match self.owner_source_eviction_selected.entry(identity) { + DashMapEntry::Vacant(entry) => { + entry.insert(debt.clone()); + self.owner_hot_counters + .add_source_eviction_selected_bytes(debt.weight_bytes); + true + } + DashMapEntry::Occupied(_) => false, + } + } + + fn owner_hot_remove_source_selection_debt( + &self, + identity: &OwnerHotReplicaIdentity, + ) -> Option> { + let debt = self + .owner_source_eviction_selected + .remove(identity) + .map(|(_, debt)| debt)?; + self.owner_hot_counters + .remove_source_eviction_selected_bytes(debt.weight_bytes); + Some(debt) + } + + pub(crate) fn owner_hot_install_source_selection_fences( + &self, + sources: &[(OwnerHotReplicaIdentity, Arc)], + ) -> OwnerHotSelectionFenceOutcome { + let mut installed = Vec::with_capacity(sources.len()); + let mut outcome = OwnerHotSelectionFenceOutcome::Fenced; + + for (identity, source) in sources { + let mut controls = self.owner_key_control.lock_key(&identity.key); + let control_busy = controls.get(&identity.key).is_some_and(|state| { + state.local_puts != 0 + || state.external_pending_puts != 0 + || state.external_get.is_some() + || state.local_access_fenced() + }); + if control_busy + || self + .precommit_local_visible_info + .contains_key(&identity.key) + || self.pending_local_get_info.contains_key(&identity.key) + { + outcome = OwnerHotSelectionFenceOutcome::Retryable; + break; + } + + let cached_info = self + .get_cached_info + .remove_if(&identity.key, |_, cached| { + (cached.put_time_ms, cached.put_version) + == (identity.put_time_ms, identity.put_version) + && Arc::ptr_eq(&cached.mem_holder, source) + }) + .map(|(_, cached)| cached); + let Some(cached_info) = cached_info else { + outcome = OwnerHotSelectionFenceOutcome::Obsolete; + break; + }; + + let state = controls.entry(identity.key.clone()).or_default(); + assert!(state.source_eviction_selection.is_none()); + state.source_eviction_selection = Some(OwnerSourceEvictionSelection { + put_id: (identity.put_time_ms, identity.put_version), + cached_info, + }); + installed.push(identity.clone()); + } + + if matches!(outcome, OwnerHotSelectionFenceOutcome::Fenced) { + // Every matching local index is now hidden under its per-key fence. + // Each source has exactly two expected Arcs: the selection record + // and this temporary atomic_batch pin. No new local reader can enter, + // so an extra reference is an already-active holder and the whole + // atomic_batch must be rolled back before choosing another victim. + let active_members = sources + .iter() + .filter(|(_, source)| owner_hot_source_has_active_holders(source)) + .count(); + if active_members != 0 { + outcome = OwnerHotSelectionFenceOutcome::TemporarilyPinned { active_members }; + } + } + + if !matches!(outcome, OwnerHotSelectionFenceOutcome::Fenced) { + for identity in installed.iter().rev() { + assert!( + self.owner_hot_restore_source_selection(identity), + "partial owner source selection rollback must find every installed fence" + ); + } + } + outcome + } + fn owner_hot_track_committed( &self, key: &str, @@ -2368,6 +2594,7 @@ impl ClientKvApiInner { } cache.insert( key.to_string(), + [OwnerHotPinAlias::new(memory_info)], OwnerHotCacheEntry { put_id, memory_info: Arc::downgrade(memory_info), @@ -2404,7 +2631,7 @@ impl ClientKvApiInner { let Some(cache) = self.owner_hot_cache.as_ref() else { return; }; - if cache.get(key).is_some_and(|entry| { + if cache.get(&key.to_string()).is_some_and(|entry| { entry.put_id == put_id && Weak::ptr_eq(&entry.memory_info, &Arc::downgrade(memory_info)) }) { return; @@ -2421,7 +2648,7 @@ impl ClientKvApiInner { let controls = self.owner_key_control.lock_key(key); if controls .get(key) - .is_some_and(|state| state.reclaim.is_some()) + .is_some_and(|state| state.local_access_fenced()) { return false; } @@ -2443,18 +2670,9 @@ impl ClientKvApiInner { put_version: put_id.1, }; if let Some(cache) = self.owner_hot_cache.as_ref() { - let _ = cache.entry(key.to_string()).and_compute_with(|entry| { - if entry - .as_ref() - .is_some_and(|entry| entry.value().put_id == put_id) - { - MokaComputeOp::Remove - } else { - MokaComputeOp::Nop - } - }); + cache.invalidate_if(&key.to_string(), |entry| entry.put_id == put_id); } - if let Some((_identity, debt)) = self.owner_source_eviction_selected.remove(&identity) { + if let Some(debt) = self.owner_hot_remove_source_selection_debt(&identity) { debt.release(); self.owner_hot_counters .source_evict_committed_members @@ -2483,6 +2701,15 @@ impl ClientKvApiInner { } } + pub(crate) fn owner_hot_pin_memory_info( + &self, + memory_info: &Arc, + ) -> Option { + self.owner_hot_cache + .as_ref()? + .try_pin_alias(OwnerHotPinAlias::new(memory_info)) + } + pub(crate) fn short_circuit_put_payload_path_enabled(&self) -> bool { self.test_spec_config.short_circuit_put_payload_path } @@ -2532,7 +2759,7 @@ impl ClientKvApiInner { let mut controls = self.owner_key_control.lock_key(key); if controls .get(key) - .is_some_and(|state| state.reclaim.is_some()) + .is_some_and(|state| state.local_access_fenced()) { return Err(KvError::Api(ApiError::KeyBeingWritten { key: key.to_string(), @@ -2587,7 +2814,7 @@ impl ClientKvApiInner { let controls = self.owner_key_control.lock_key(key); if controls .get(key) - .is_some_and(|state| state.reclaim.is_some()) + .is_some_and(|state| state.local_access_fenced()) { tracing::debug!( "skip local snapshot publication behind owner reclaim fence: key={} put_id=({},{})", @@ -2610,7 +2837,7 @@ impl ClientKvApiInner { let controls = self.owner_key_control.lock_key(key); if controls .get(key) - .is_some_and(|state| state.reclaim.is_some()) + .is_some_and(|state| state.local_access_fenced()) { return false; } @@ -2624,7 +2851,7 @@ impl ClientKvApiInner { let controls = self.owner_key_control.lock_key(key); if controls .get(key) - .is_some_and(|state| state.reclaim.is_some()) + .is_some_and(|state| state.local_access_fenced()) { return None; } @@ -2657,7 +2884,7 @@ impl ClientKvApiInner { let controls = self.owner_key_control.lock_key(key); if controls .get(key) - .is_some_and(|state| state.reclaim.is_some()) + .is_some_and(|state| state.local_access_fenced()) { return None; } @@ -2689,7 +2916,7 @@ impl ClientKvApiInner { let controls = self.owner_key_control.lock_key(key); if controls .get(key) - .is_some_and(|state| state.reclaim.is_some()) + .is_some_and(|state| state.local_access_fenced()) { return None; } @@ -2727,6 +2954,7 @@ impl ClientKvApiInner { len: memory_info.len, holder_id: external_holder_id, }; + let owner_hot_pin = self.owner_hot_pin_memory_info(&memory_info); let previous = self.external_get_holding.inner().insert( key, ExternalHoldingGetInfo { @@ -2738,6 +2966,7 @@ impl ClientKvApiInner { .get_member_info_cached(req_node_id) .map(|member| member.node_start_time), memory_info, + _owner_hot_pin: owner_hot_pin, }, ); assert!( @@ -2787,7 +3016,7 @@ impl ClientKvApiInner { let controls = self.owner_key_control.lock_key(key); if controls .get(key) - .is_some_and(|state| state.reclaim.is_some()) + .is_some_and(|state| state.local_access_fenced()) || self.pending_local_get_info.contains_key(key) { return Err(KvError::Api(ApiError::KeyBeingWritten { @@ -2841,7 +3070,7 @@ impl ClientKvApiInner { let controls = self.owner_key_control.lock_key(key); if controls .get(key) - .is_some_and(|state| state.reclaim.is_some()) + .is_some_and(|state| state.local_access_fenced()) { return Err(KvError::Api(ApiError::KeyBeingWritten { key: key.to_string(), @@ -2930,7 +3159,7 @@ impl ClientKvApiInner { let controls = self.owner_key_control.lock_key(key); if controls .get(key) - .is_some_and(|state| state.reclaim.is_some()) + .is_some_and(|state| state.local_access_fenced()) { return Err(KvError::Api(ApiError::KeyBeingWritten { key: key.to_string(), @@ -2969,7 +3198,7 @@ impl ClientKvApiInner { let controls = self.owner_key_control.lock_key(key); if controls .get(key) - .is_some_and(|state| state.reclaim.is_some()) + .is_some_and(|state| state.local_access_fenced()) { tracing::debug!( "skip get cache publication behind owner reclaim fence: key={} put_id=({},{})", @@ -3011,7 +3240,7 @@ impl ClientKvApiInner { assert!( !controls .get(key) - .is_some_and(|state| state.reclaim.is_some()), + .is_some_and(|state| state.local_access_fenced()), "precommit local index publication must not cross an owner reclaim fence" ); let (slot_size, grant_id, slot_index) = memory_info @@ -3076,7 +3305,7 @@ impl ClientKvApiInner { let controls = self.owner_key_control.lock_key(key); if controls .get(key) - .is_some_and(|state| state.reclaim.is_some()) + .is_some_and(|state| state.local_access_fenced()) { return Err(KvError::Api(ApiError::KeyBeingWritten { key: key.to_string(), @@ -3792,17 +4021,21 @@ impl OwnerLocalReserveClassState { mod owner_reclaim_slot_tests { use super::{ ExternalPendingPutCtx, ExternalPendingPutFenceGuard, OwnerHotCacheCounters, - OwnerHotCacheEntry, OwnerHotEvictionEvent, OwnerHotReplicaIdentity, OwnerHotRetryQueue, - OwnerHotSelectionDebt, OwnerKeyControlState, OwnerKeyControlTable, - OwnerLocalReserveGrantState, OwnerLocalReserveSlotLease, OwnerLocalReserveSlotRef, - OwnerLocalReserveSlotState, OwnerReclaimRecord, acquire_external_pending_put_fence_for_key, + OwnerHotCacheEntry, OwnerHotEvictionEvent, OwnerHotPinAlias, OwnerHotReplicaIdentity, + OwnerHotRetryQueue, OwnerHotSelectionDebt, OwnerHotSelectionFenceOutcome, + OwnerKeyControlState, OwnerKeyControlTable, OwnerLocalReserveGrantState, + OwnerLocalReserveSlotLease, OwnerLocalReserveSlotRef, OwnerLocalReserveSlotState, + OwnerReclaimRecord, acquire_external_pending_put_fence_for_key, allocate_external_holding_id, build_owner_hot_cache, clone_if_owner_hot_entry_matches, - forget_owner_hot_atomic_group, owner_hot_tp_cohort_key_rows, - pin_current_owner_hot_source_from_index, register_owner_hot_atomic_group, + forget_owner_hot_atomic_group, owner_hot_source_has_active_holders, + owner_hot_tp_atomic_batch_key_rows, pin_current_owner_hot_source_from_index, + register_owner_hot_atomic_group, }; use crate::master_kv_router::msg_pack::{ - OwnerReclaimItem, PutAtomicGroup, PutAtomicGroupMember, + BatchOwnerReclaimReq, OwnerReclaimBacking, OwnerReclaimItem, OwnerReclaimItemState, + OwnerReclaimPhase, OwnerReclaimReason, PutAtomicGroup, PutAtomicGroupMember, }; + use crate::p2p::msg_pack::MsgPack; use dashmap::DashMap; use parking_lot::Mutex; use std::sync::atomic::{AtomicU64, Ordering}; @@ -3858,6 +4091,7 @@ mod owner_reclaim_slot_tests { OwnerKeyControlState { local_puts: 1, external_pending_puts: 1, + source_eviction_selection: None, reclaim: None, external_get: None, }, @@ -3882,6 +4116,7 @@ mod owner_reclaim_slot_tests { OwnerKeyControlState { local_puts: 1, external_pending_puts: 1, + source_eviction_selection: None, reclaim: None, external_get: None, }, @@ -3908,6 +4143,7 @@ mod owner_reclaim_slot_tests { OwnerKeyControlState { local_puts: 1, external_pending_puts: 1, + source_eviction_selection: None, reclaim: None, external_get: None, }, @@ -4005,6 +4241,264 @@ mod owner_reclaim_slot_tests { ); } + #[test] + fn pressure_victim_rejects_an_extra_active_holder() { + let indexed = Arc::new(7u64); + let selected = indexed.clone(); + assert_eq!(Arc::strong_count(&selected), 2); + assert!( + !owner_hot_source_has_active_holders(&selected), + "index plus the temporary selection pin is reclaimable" + ); + + let active_reader = indexed.clone(); + assert_eq!(Arc::strong_count(&selected), 3); + assert!(owner_hot_source_has_active_holders(&selected)); + + drop(active_reader); + assert!(!owner_hot_source_has_active_holders(&selected)); + } + + #[limit_thirdparty::tokio::test(flavor = "multi_thread", worker_threads = 8)] + async fn source_selection_fence_closes_late_get_and_rolls_back_whole_atomic_batch() { + use crate::client_kv_api::PutOptionalArgs; + use crate::kvcore_test_lib::{ + integration_test_lock, start_master_and_client, stop_master_and_client, + }; + + let _test_guard = integration_test_lock().await; + let (master, client) = start_master_and_client( + "source_selection_fence_master", + "source_selection_fence_owner", + ) + .await; + let owner_view = client.client_kv_api_view(); + let inner = owner_view.client_kv_api().inner(); + let keys = ["selection-rank0", "selection-rank1"]; + for key in keys { + inner + .put(key, &[7u8; 4096], PutOptionalArgs::default()) + .await + .expect("owner put must publish a committed route"); + let (holder, _remote) = inner + .get(key) + .await + .expect("owner get must succeed") + .expect("committed route must be readable"); + drop(holder); + } + + let sources = keys + .iter() + .map(|key| { + let cached = inner + .get_cached_info + .get(*key) + .expect("committed owner source must be indexed"); + ( + OwnerHotReplicaIdentity { + key: (*key).to_string(), + put_time_ms: cached.put_time_ms, + put_version: cached.put_version, + }, + cached.mem_holder.clone(), + ) + }) + .collect::>(); + assert!( + sources + .iter() + .all(|(_, source)| !owner_hot_source_has_active_holders(source)), + "the initial victim check must see only index plus selection pins" + ); + + // Reproduce the r11 TOCTOU exactly: a local Get acquires one atomic_batch + // member after the dispatcher's first holder check but before the + // source-selection fence is installed. + let late_reader = inner + .local_visible_mem_holder(keys[1]) + .expect("late local Get must acquire the source before fencing"); + assert!(matches!( + inner.owner_hot_install_source_selection_fences(&sources), + OwnerHotSelectionFenceOutcome::TemporarilyPinned { active_members: 1 } + )); + for key in keys { + assert!(inner.get_cached_info.contains_key(key)); + assert!( + inner + .owner_key_control + .lock_key(key) + .get(key) + .is_none_or(|state| state.source_eviction_selection.is_none()), + "a pinned member must roll back every partial atomic_batch fence" + ); + } + + drop(late_reader); + assert!(matches!( + inner.owner_hot_install_source_selection_fences(&sources), + OwnerHotSelectionFenceOutcome::Fenced + )); + for key in keys { + assert!(!inner.get_cached_info.contains_key(key)); + assert!(inner.local_visible_mem_holder(key).is_none()); + assert!( + acquire_external_pending_put_fence_for_key(&inner.owner_key_control, key).is_err(), + "a new local Put must not cross a source-selection fence" + ); + } + + let identities = sources + .iter() + .map(|(identity, _)| identity.clone()) + .collect::>(); + drop(sources); + let master_id = master + .cluster_manager_view() + .cluster_manager() + .get_self_info() + .id; + + let mismatched = OwnerReclaimItem { + key: identities[0].key.clone(), + put_id: ( + identities[0].put_time_ms, + identities[0].put_version.wrapping_add(1), + ), + epoch: 90, + backing: OwnerReclaimBacking::Allocation, + reason: OwnerReclaimReason::OwnerCapacityEviction, + }; + let mismatch_resp = super::reclaim::handle_batch_owner_reclaim( + &owner_view, + MsgPack { + serialize_part: BatchOwnerReclaimReq { + phase: OwnerReclaimPhase::Prepare, + items: vec![mismatched], + }, + raw_bytes: Vec::new(), + }, + master_id.clone().into(), + ) + .await; + assert_eq!( + mismatch_resp.serialize_part.items[0].state, + OwnerReclaimItemState::Busy + ); + assert!( + inner + .owner_key_control + .lock_key(&identities[0].key) + .get(&identities[0].key) + .is_some_and(|state| state.source_eviction_selection.is_some()), + "a mismatched Prepare must not consume the owner selection" + ); + + let matching = identities + .iter() + .enumerate() + .map(|(index, identity)| OwnerReclaimItem { + key: identity.key.clone(), + put_id: (identity.put_time_ms, identity.put_version), + epoch: 100 + index as u64, + backing: OwnerReclaimBacking::Allocation, + reason: OwnerReclaimReason::OwnerCapacityEviction, + }) + .collect::>(); + let prepare_resp = super::reclaim::handle_batch_owner_reclaim( + &owner_view, + MsgPack { + serialize_part: BatchOwnerReclaimReq { + phase: OwnerReclaimPhase::Prepare, + items: matching.clone(), + }, + raw_bytes: Vec::new(), + }, + master_id.clone().into(), + ) + .await; + assert!( + prepare_resp + .serialize_part + .items + .iter() + .all(|item| item.state == OwnerReclaimItemState::Prepared), + "matching Prepare must atomically promote each selection into reclaim" + ); + for key in keys { + assert!(inner.local_visible_mem_holder(key).is_none()); + } + + let abort_resp = super::reclaim::handle_batch_owner_reclaim( + &owner_view, + MsgPack { + serialize_part: BatchOwnerReclaimReq { + phase: OwnerReclaimPhase::Abort, + items: matching, + }, + raw_bytes: Vec::new(), + }, + master_id.into(), + ) + .await; + assert!( + abort_resp + .serialize_part + .items + .iter() + .all(|item| item.state == OwnerReclaimItemState::Aborted) + ); + for key in keys { + assert!( + inner.local_visible_mem_holder(key).is_some(), + "Abort must restore the exact committed local index" + ); + } + + let group = PutAtomicGroup { + members: identities + .iter() + .map(|identity| PutAtomicGroupMember { + key: identity.key.clone(), + put_id: (identity.put_time_ms, identity.put_version), + }) + .collect(), + }; + inner.owner_hot_register_atomic_group(&group); + let trigger_weak = { + let cached = inner + .get_cached_info + .get(&identities[0].key) + .expect("Abort-restored trigger must be indexed"); + Arc::downgrade(&cached.mem_holder) + }; + let retry_event = OwnerHotEvictionEvent { + key: identities[0].key.clone(), + put_id: (identities[0].put_time_ms, identities[0].put_version), + memory_info: trigger_weak, + selection_debt: OwnerHotSelectionDebt::new( + 4096, + inner.owner_hot_counters.selection_debt_bytes.clone(), + ), + retry: true, + source_eviction_atomic_batch: None, + retry_failures: 1, + }; + match inner.owner_hot_prepare_eviction(&retry_event) { + super::OwnerHotEvictionPreparation::Ready { sources, .. } => { + assert_eq!( + sources.len(), + identities.len(), + "a pre-selection retry must resolve the complete atomic atomic_batch" + ); + } + _ => panic!("a pre-selection retry with a complete atomic_batch must be ready"), + } + retry_event.selection_debt.release(); + + stop_master_and_client(master, client).await; + } + #[test] fn dispatcher_pin_and_reclaim_prepare_are_serialized_by_the_current_index() { let current = Mutex::new(Some(((10, 2), Arc::new(7u64)))); @@ -4065,7 +4559,7 @@ mod owner_reclaim_slot_tests { memory_info: Weak::new(), selection_debt: debt, retry: true, - source_eviction_cohort: None, + source_eviction_atomic_batch: None, retry_failures: 0, }; retry_queue.schedule(event.clone(), "first failure"); @@ -4109,7 +4603,7 @@ mod owner_reclaim_slot_tests { memory_info: Weak::new(), selection_debt: debt, retry: true, - source_eviction_cohort: None, + source_eviction_atomic_batch: None, retry_failures: 0, }; @@ -4150,7 +4644,7 @@ mod owner_reclaim_slot_tests { memory_info: Weak::new(), selection_debt: remove_debt, retry: true, - source_eviction_cohort: None, + source_eviction_atomic_batch: None, retry_failures: 0, }; for _ in 0..CHURN { @@ -4194,7 +4688,7 @@ mod owner_reclaim_slot_tests { } #[test] - fn owner_hot_tp_cohort_expands_the_same_group_boundary_across_ranks() { + fn owner_hot_tp_atomic_batch_expands_the_same_group_boundary_across_ranks() { let identity = OwnerHotReplicaIdentity { key: "page0_model_0_2".to_string(), put_time_ms: 10, @@ -4213,7 +4707,7 @@ mod owner_reclaim_slot_tests { ], }; assert_eq!( - owner_hot_tp_cohort_key_rows(&identity, Some(&rank0_group)), + owner_hot_tp_atomic_batch_key_rows(&identity, Some(&rank0_group)), Ok(Some(vec![ vec!["page0_model_0_2".to_string(), "page1_model_0_2".to_string(),], vec!["page0_model_1_2".to_string(), "page1_model_1_2".to_string(),], @@ -4230,7 +4724,7 @@ mod owner_reclaim_slot_tests { ], }; assert_eq!( - owner_hot_tp_cohort_key_rows(&identity, Some(&mixed_rank_group)), + owner_hot_tp_atomic_batch_key_rows(&identity, Some(&mixed_rank_group)), Err(()) ); } @@ -4246,18 +4740,22 @@ mod owner_reclaim_slot_tests { memory_info: Weak::new(), weight_bytes: 6, }; + let alias = |key: &str, put_version: usize| OwnerHotPinAlias { + key: key.to_string(), + memory_info_ptr: put_version, + }; - cache.insert("explicit".to_string(), entry(0)); + cache.insert("explicit".to_string(), [alias("explicit", 0)], entry(0)); cache.run_pending_tasks(); - cache.invalidate("explicit"); + cache.invalidate(&"explicit".to_string()); cache.run_pending_tasks(); assert_eq!(counters.size_evictions.load(Ordering::Relaxed), 0); - cache.insert("size-a".to_string(), entry(1)); - cache.insert("size-b".to_string(), entry(2)); + cache.insert("size-a".to_string(), [alias("size-a", 1)], entry(1)); + cache.insert("size-b".to_string(), [alias("size-b", 2)], entry(2)); cache.run_pending_tasks(); assert!(counters.size_evictions.load(Ordering::Relaxed) >= 1); - assert_eq!(cache.policy().max_capacity(), Some(10)); + assert_eq!(cache.max_capacity(), Some(10)); let event = rx .try_recv() .expect("the Moka listener must emit lightweight metadata without pinning"); @@ -4277,6 +4775,7 @@ mod owner_reclaim_slot_tests { OwnerKeyControlState { local_puts: 0, external_pending_puts: 0, + source_eviction_selection: None, reclaim: Some(OwnerReclaimRecord::Committed(OwnerReclaimItem { key: "fenced".to_string(), ..OwnerReclaimItem::default() @@ -4289,7 +4788,10 @@ mod owner_reclaim_slot_tests { .iter() .map(|key| { let shard = controls.lock_key(key); - if shard.get(key).is_some_and(|state| state.reclaim.is_some()) { + if shard + .get(key) + .is_some_and(|state| state.local_access_fenced()) + { None } else { resolved_keys.push(key.to_string()); @@ -4599,7 +5101,7 @@ impl ClientKvApiInner { .as_ref() .map(|cache| { ( - cache.policy().max_capacity().unwrap_or(0), + cache.max_capacity().unwrap_or(0), cache.entry_count(), cache.weighted_size(), ) @@ -4723,6 +5225,10 @@ impl ClientKvApiInner { .owner_hot_counters .selection_debt_bytes .load(Ordering::Relaxed), + hot_source_eviction_selected_bytes: self + .owner_hot_counters + .source_eviction_selected_bytes + .load(Ordering::Relaxed), hot_eviction_skipped_stale: self .owner_hot_counters .skipped_stale @@ -4731,6 +5237,10 @@ impl ClientKvApiInner { .owner_hot_counters .skipped_reclaim .load(Ordering::Relaxed), + hot_eviction_skipped_active_holders: self + .owner_hot_counters + .skipped_active_holders + .load(Ordering::Relaxed), hot_group_registry_entries: self.owner_hot_atomic_groups.len() as u64, hot_group_trigger_duplicates: self .owner_hot_counters @@ -5296,8 +5806,10 @@ impl ClientKvApi { source_evict_retry_scheduled = snapshot.hot_source_evict_retry_scheduled, source_evict_retry_emitted = snapshot.hot_source_evict_retry_emitted, selection_debt_bytes = snapshot.hot_selection_debt_bytes, + source_eviction_selected_bytes = snapshot.hot_source_eviction_selected_bytes, skipped_stale = snapshot.hot_eviction_skipped_stale, skipped_reclaim = snapshot.hot_eviction_skipped_reclaim, + skipped_active_holders = snapshot.hot_eviction_skipped_active_holders, group_registry_entries = snapshot.hot_group_registry_entries, group_trigger_duplicates = snapshot.hot_group_trigger_duplicates, group_trigger_incomplete = snapshot.hot_group_trigger_incomplete, @@ -5331,7 +5843,7 @@ impl ClientKvApi { // The Moka eviction listener is synchronous and must never block while // holding Moka's housekeeper lock. Events contain only weak payload // references and are deduplicated by exact selected identities, so use - // a lossless metadata channel instead of dropping cohorts when the old + // a lossless metadata channel instead of dropping atomic_batches when the old // bounded queue briefly filled under cache pressure. let (owner_hot_eviction_tx, owner_hot_eviction_rx) = tokio::sync::ampsc::unbounded_channel(); diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs index 8bfa822..862adab 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs @@ -1,7 +1,8 @@ use super::{ ClientKvApiInner, OwnerHotEvictionEvent, OwnerHotEvictionPreparation, OwnerHotSelectionDebt, - OwnerLocalReserveClassState, OwnerLocalReserveGrantState, OwnerLocalReservePoolState, - OwnerLocalReserveSlotLease, OwnerLocalReserveSlotRef, ReplicaTaskJob, ReplicaTaskTarget, + OwnerHotSelectionFenceOutcome, OwnerLocalReserveClassState, OwnerLocalReserveGrantState, + OwnerLocalReservePoolState, OwnerLocalReserveSlotLease, OwnerLocalReserveSlotRef, + ReplicaTaskJob, ReplicaTaskTarget, local_reserve_rebalance::{owner_local_reserve_timeout_config, wait_owner_local_reserve_ready}, owner_hot_weight_bytes, }; @@ -26,7 +27,7 @@ use crate::{ BatchPutStartItemReq, BatchPutStartReq, BatchPutStartResp, BatchReleasePutKeyReservationsReq, BatchReleasePutKeyReservationsResp, EnqueueReplicaTaskItemResp, GroupedBatchPutDoneItemReq, GroupedBatchPutDoneReq, - GroupedBatchPutDoneResp, OwnerReclaimBacking, OwnerSourceEvictionCohort, + GroupedBatchPutDoneResp, OwnerReclaimBacking, OwnerSourceEvictionAtomicBatch, OwnerSourceEvictionMember, OwnerSourceEvictionOutcome, PutAppendDoneReq, PutAppendDoneResp, PutAppendRevokeReq, PutAppendStartOutcome, PutAppendStartReq, PutAppendStartResp, PutAtomicGroup, PutDoneCommittedSlot, PutDoneReq, PutRevokeReq, PutStartReq, PutStartResp, @@ -2224,12 +2225,12 @@ impl ClientKvApiInner { pub async fn batch_evict_owner_source( &self, - cohorts: Vec, + atomic_batches: Vec, ) -> KvResult { - if cohorts.is_empty() { + if atomic_batches.is_empty() { return Ok(BatchEvictOwnerSourceResp { operation_id: 0, - cohorts: Vec::new(), + atomic_batches: Vec::new(), error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, error_json: String::new(), }); @@ -2247,7 +2248,7 @@ impl ClientKvApiInner { serialize_part: BatchEvictOwnerSourceReq { operation_id, owner_node_start_time: self_info.node_start_time, - cohorts, + atomic_batches, }, raw_bytes: Vec::new(), }; @@ -2847,7 +2848,7 @@ const OWNER_LOCAL_PUBLISH_RETRY_MAX: Duration = Duration::from_secs(1); mod owner_hot_replica_policy_tests { use super::{ OwnerLocalPublishItem, complete_owner_local_publish_group_lens, - owner_local_publish_cohort_complete, + owner_local_publish_atomic_batch_complete, }; use crate::master_kv_router::msg_pack::{ PutAtomicGroup, PutAtomicGroupMember, PutDoneCommittedSlot, @@ -2926,11 +2927,19 @@ mod owner_hot_replica_policy_tests { publish_item("single", (2, 0), None), ]; let partial = vec![&items[0]]; - assert!(!owner_local_publish_cohort_complete(&items[0], &partial)); + assert!(!owner_local_publish_atomic_batch_complete( + &items[0], &partial + )); let complete = vec![&items[0], &items[1]]; - assert!(owner_local_publish_cohort_complete(&items[0], &complete)); - assert!(owner_local_publish_cohort_complete(&items[1], &complete)); - assert!(owner_local_publish_cohort_complete(&items[2], &partial)); + assert!(owner_local_publish_atomic_batch_complete( + &items[0], &complete + )); + assert!(owner_local_publish_atomic_batch_complete( + &items[1], &complete + )); + assert!(owner_local_publish_atomic_batch_complete( + &items[2], &partial + )); } } @@ -2978,13 +2987,13 @@ fn owner_source_eviction_member( fn finish_owner_source_selection( inner: &ClientKvApiInner, - cohort: &OwnerSourceEvictionCohort, + atomic_batch: &OwnerSourceEvictionAtomicBatch, restore_current: bool, reason: &str, ) { - for member in &cohort.members { + for member in &atomic_batch.members { let identity = owner_source_eviction_identity(member); - if let Some((_identity, debt)) = inner.owner_source_eviction_selected.remove(&identity) { + if let Some(debt) = inner.owner_hot_remove_source_selection_debt(&identity) { debt.release(); inner .owner_hot_counters @@ -2995,6 +3004,7 @@ fn finish_owner_source_selection( if !restore_current { continue; } + inner.owner_hot_restore_source_selection(&identity); let group = inner .owner_hot_atomic_groups .get(&identity) @@ -3014,18 +3024,18 @@ fn finish_owner_source_selection( fn schedule_owner_source_eviction_retry( inner: &ClientKvApiInner, mut event: OwnerHotEvictionEvent, - cohort: Arc, + atomic_batch: Arc, reason: &'static str, ) { event.retry = true; - event.source_eviction_cohort = Some(cohort); + event.source_eviction_atomic_batch = Some(atomic_batch); inner.owner_hot_retry_queue.schedule(event, reason); } fn prepare_owner_source_eviction_event( inner: &ClientKvApiInner, mut event: OwnerHotEvictionEvent, -) -> Option<(OwnerHotEvictionEvent, Arc)> { +) -> Option<(OwnerHotEvictionEvent, Arc)> { let trigger = super::OwnerHotReplicaIdentity { key: event.key.clone(), put_time_ms: event.put_id.0, @@ -3035,17 +3045,22 @@ fn prepare_owner_source_eviction_event( if event.retry { let _ = inner.owner_hot_retry_queue.take_for_inflight(&trigger); } - if let Some(cohort) = event.source_eviction_cohort.clone() { - if cohort.members.iter().all(|member| { + if let Some(atomic_batch) = event.source_eviction_atomic_batch.clone() { + if atomic_batch.members.iter().all(|member| { inner .owner_source_eviction_selected .contains_key(&owner_source_eviction_identity(member)) }) { - return Some((event, cohort)); + return Some((event, atomic_batch)); } // Commit/invalidation may win the race with a due retry. Any remaining // selected members are restored rather than leaving false projected credit. - finish_owner_source_selection(inner, &cohort, true, "retry cohort lost selected identity"); + finish_owner_source_selection( + inner, + &atomic_batch, + true, + "retry atomic_batch lost selected identity", + ); event.selection_debt.release(); return None; } @@ -3068,10 +3083,40 @@ fn prepare_owner_source_eviction_event( ); return None; } - OwnerHotEvictionPreparation::RetryableIncompleteCohort => { + OwnerHotEvictionPreparation::RetryableIncompleteAtomicBatch => { inner .owner_hot_retry_queue - .schedule(event, "owner source cohort is temporarily incomplete"); + .schedule(event, "owner source atomic_batch is temporarily incomplete"); + return None; + } + OwnerHotEvictionPreparation::TemporarilyPinned { active_members } => { + // This event was removed from Moka, but its source atomic_batch is still + // serving a local reader. Do not hand it to the master's reclaim + // loop and do not retain projected selection credit. Re-admission + // refreshes the trigger's recency so the next pressure kick can + // choose a different, currently reclaimable victim. + event.selection_debt.release(); + inner.owner_hot_counters.skipped_active_holders.fetch_add( + u64::try_from(active_members).unwrap_or(u64::MAX), + Ordering::Relaxed, + ); + let group = inner + .owner_hot_atomic_groups + .get(&trigger) + .map(|entry| entry.value().clone()); + let restored = inner.owner_hot_admit_published_committed( + &event.key, + event.put_id, + group.as_deref(), + ); + tracing::debug!( + key = event.key, + put_time_ms = event.put_id.0, + put_version = event.put_id.1, + active_members, + restored, + "owner pressure eviction skipped an actively held source atomic_batch" + ); return None; } OwnerHotEvictionPreparation::Obsolete => { @@ -3103,13 +3148,47 @@ fn prepare_owner_source_eviction_event( ); return None; }; - let cohort = Arc::new(OwnerSourceEvictionCohort { members }); + let atomic_batch = Arc::new(OwnerSourceEvictionAtomicBatch { members }); + + match inner.owner_hot_install_source_selection_fences(&sources) { + OwnerHotSelectionFenceOutcome::Fenced => {} + OwnerHotSelectionFenceOutcome::Retryable => { + inner + .owner_hot_retry_queue + .schedule(event, "owner source selection fence is temporarily busy"); + return None; + } + OwnerHotSelectionFenceOutcome::TemporarilyPinned { active_members } => { + event.selection_debt.release(); + inner.owner_hot_counters.skipped_active_holders.fetch_add( + u64::try_from(active_members).unwrap_or(u64::MAX), + Ordering::Relaxed, + ); + let group = inner + .owner_hot_atomic_groups + .get(&trigger) + .map(|entry| entry.value().clone()); + inner.owner_hot_admit_published_committed(&event.key, event.put_id, group.as_deref()); + return None; + } + OwnerHotSelectionFenceOutcome::Obsolete => { + event.selection_debt.release(); + inner + .owner_hot_counters + .source_evict_obsolete + .fetch_add(1, Ordering::Relaxed); + return None; + } + } - if cohort.members.iter().any(|member| { + if atomic_batch.members.iter().any(|member| { inner .owner_source_eviction_selected .contains_key(&owner_source_eviction_identity(member)) }) { + for member in &atomic_batch.members { + inner.owner_hot_restore_source_selection(&owner_source_eviction_identity(member)); + } event.selection_debt.release(); inner .owner_hot_counters @@ -3118,8 +3197,8 @@ fn prepare_owner_source_eviction_event( return None; } - let mut installed = Vec::with_capacity(cohort.members.len()); - for ((identity, memory_info), member) in sources.iter().zip(cohort.members.iter()) { + let mut installed = Vec::with_capacity(atomic_batch.members.len()); + for ((identity, memory_info), member) in sources.iter().zip(atomic_batch.members.iter()) { debug_assert_eq!(identity, &owner_source_eviction_identity(member)); let debt = if identity == &trigger { event.selection_debt.clone() @@ -3129,27 +3208,25 @@ fn prepare_owner_source_eviction_event( inner.owner_hot_counters.selection_debt_bytes.clone(), ) }; - if inner - .owner_source_eviction_selected - .insert(identity.clone(), debt.clone()) - .is_some() - { + if !inner.owner_hot_install_source_selection_debt(identity.clone(), debt.clone()) { debt.release(); for installed_identity in installed { - if let Some((_identity, installed_debt)) = inner - .owner_source_eviction_selected - .remove(&installed_identity) + if let Some(installed_debt) = + inner.owner_hot_remove_source_selection_debt(&installed_identity) { installed_debt.release(); } } + for member in &atomic_batch.members { + inner.owner_hot_restore_source_selection(&owner_source_eviction_identity(member)); + } event.selection_debt.release(); return None; } installed.push(identity.clone()); } - event.source_eviction_cohort = Some(cohort.clone()); - Some((event, cohort)) + event.source_eviction_atomic_batch = Some(atomic_batch.clone()); + Some((event, atomic_batch)) } async fn process_owner_source_eviction_events( @@ -3164,44 +3241,44 @@ async fn process_owner_source_eviction_events( if prepared.is_empty() { return; } - let cohorts = prepared + let atomic_batches = prepared .iter() - .map(|(_, cohort)| cohort.as_ref().clone()) + .map(|(_, atomic_batch)| atomic_batch.as_ref().clone()) .collect::>(); - let response = inner.batch_evict_owner_source(cohorts).await; + let response = inner.batch_evict_owner_source(atomic_batches).await; let Ok(response) = response else { - for (event, cohort) in prepared { + for (event, atomic_batch) in prepared { schedule_owner_source_eviction_retry( inner, event, - cohort, + atomic_batch, "owner source-eviction RPC failed", ); } return; }; - if response.cohorts.len() != prepared.len() { - for (event, cohort) in prepared { + if response.atomic_batches.len() != prepared.len() { + for (event, atomic_batch) in prepared { schedule_owner_source_eviction_retry( inner, event, - cohort, + atomic_batch, "owner source-eviction response length mismatch", ); } return; } - for (index, ((event, cohort), result)) in prepared + for (index, ((event, atomic_batch), result)) in prepared .into_iter() - .zip(response.cohorts.into_iter()) + .zip(response.atomic_batches.into_iter()) .enumerate() { - if result.cohort_index != u32::try_from(index).unwrap_or(u32::MAX) { + if result.atomic_batch_index != u32::try_from(index).unwrap_or(u32::MAX) { schedule_owner_source_eviction_retry( inner, event, - cohort, + atomic_batch, "owner source-eviction response identity mismatch", ); continue; @@ -3212,14 +3289,14 @@ async fn process_owner_source_eviction_events( inner .owner_hot_counters .source_evict_handoff_members - .fetch_add(cohort.members.len() as u64, Ordering::Relaxed); + .fetch_add(atomic_batch.members.len() as u64, Ordering::Relaxed); // Selected debt stays live until owner reclaim Commit calls // owner_hot_invalidate_version for every exact member. } OwnerSourceEvictionOutcome::Completed => { finish_owner_source_selection( inner, - &cohort, + &atomic_batch, true, "master reported source deletion already completed", ); @@ -3228,29 +3305,29 @@ async fn process_owner_source_eviction_events( schedule_owner_source_eviction_retry( inner, event, - cohort, + atomic_batch, "master source reclaim is temporarily busy", ); } OwnerSourceEvictionOutcome::Stale => { finish_owner_source_selection( inner, - &cohort, + &atomic_batch, true, "master rejected stale source identity", ); } OwnerSourceEvictionOutcome::RejectedNotEvictable => { tracing::error!( - cohort_members = cohort.members.len(), + atomic_batch_members = atomic_batch.members.len(), detail = result.detail, - "owner selected a source cohort that master declared non-evictable" + "owner selected a source atomic_batch that master declared non-evictable" ); finish_owner_source_selection( inner, - &cohort, + &atomic_batch, true, - "master rejected non-evictable source cohort", + "master rejected non-evictable source atomic_batch", ); } } @@ -3261,7 +3338,7 @@ pub fn spawn_owner_source_eviction_dispatcher( view: ClientKvApiView, mut rx: tokio::sync::ampsc::UnboundedReceiver, ) { - const MAX_COHORTS_PER_RPC: usize = 128; + const MAX_ATOMIC_BATCHES_PER_RPC: usize = 128; const MERGE_WINDOW: Duration = Duration::from_millis(2); let view_task = view.clone(); @@ -3278,11 +3355,11 @@ pub fn spawn_owner_source_eviction_dispatcher( event } }; - let mut events = Vec::with_capacity(MAX_COHORTS_PER_RPC); + let mut events = Vec::with_capacity(MAX_ATOMIC_BATCHES_PER_RPC); events.push(first); let merge_window = tokio::time::sleep(MERGE_WINDOW); tokio::pin!(merge_window); - while events.len() < MAX_COHORTS_PER_RPC { + while events.len() < MAX_ATOMIC_BATCHES_PER_RPC { tokio::select! { _ = &mut merge_window => break, event = rx.recv() => { @@ -3963,7 +4040,7 @@ fn complete_owner_local_publish_group_lens(items: &[OwnerLocalPublishItem]) -> O Some(group_lens) } -fn owner_local_publish_cohort_complete( +fn owner_local_publish_atomic_batch_complete( item: &OwnerLocalPublishItem, promoted_items: &[&OwnerLocalPublishItem], ) -> bool { @@ -4083,7 +4160,7 @@ pub(crate) async fn publish_owner_local_job(view: ClientKvApiView, job: OwnerLoc })?; } - // Do not expose only part of an atomic/TP cohort to owner-hot. + // Do not expose only part of an atomic/TP atomic_batch to owner-hot. // First prove every master route terminal, then roll all local // precommit slots forward. Replayed attempts accept members that // were already promoted before a cancellation or partial local @@ -4129,7 +4206,7 @@ pub(crate) async fn publish_owner_local_job(view: ClientKvApiView, job: OwnerLoc } Err(reason) => { tracing::warn!( - "owner local publish retained full cohort for retry: key_count={} external_fences={} retry_ms={} reason={}", + "owner local publish retained full atomic_batch for retry: key_count={} external_fences={} retry_ms={} reason={}", job.items.len(), job.external_pending_contexts.len(), retry_delay.as_millis(), @@ -4150,7 +4227,7 @@ pub(crate) async fn publish_owner_local_job(view: ClientKvApiView, job: OwnerLoc if published { let promoted_items = job.items.iter().collect::>(); for item in &promoted_items { - if !owner_local_publish_cohort_complete(item, &promoted_items) { + if !owner_local_publish_atomic_batch_complete(item, &promoted_items) { tracing::warn!( "owner local publish skipped hot admission for incomplete atomic group: key={} put_id=({},{})", item.key, diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs index f3ea172..0071968 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs @@ -55,6 +55,8 @@ fn reclaim_key_control_busy_detail(state: &super::OwnerKeyControlState) -> Optio Some("owner local put is inflight") } else if state.external_pending_puts != 0 { Some("owner external put context is still pending") + } else if state.source_eviction_selection.is_some() { + Some("owner source eviction selection fence is active") } else if state.external_get.is_some() { Some("owner external Get is inflight") } else { @@ -64,6 +66,76 @@ fn reclaim_key_control_busy_detail(state: &super::OwnerKeyControlState) -> Optio fn prepare_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclaimItemResp { let mut controls = inner.owner_key_control.lock_key(&item.key); + if controls + .get(&item.key) + .is_some_and(|state| state.source_eviction_selection.is_some()) + { + let state = controls + .get_mut(&item.key) + .expect("owner source selection control state disappeared"); + let selection_matches = state + .source_eviction_selection + .as_ref() + .is_some_and(|selection| { + selection.put_id == item.put_id + && memory_matches_reclaim_backing( + selection.cached_info.mem_holder.as_ref(), + &item.backing, + ) + }); + if !selection_matches { + return item_resp( + item, + OwnerReclaimItemState::Busy, + "another owner source selection owns the key fence", + ); + } + if state.local_puts != 0 || state.external_pending_puts != 0 { + return item_resp( + item, + OwnerReclaimItemState::Busy, + "owner put crossed the source selection fence", + ); + } + if inner.precommit_local_visible_info.contains_key(&item.key) + || inner.pending_local_get_info.contains_key(&item.key) + { + return item_resp( + item, + OwnerReclaimItemState::Busy, + "owner local publication crossed the source selection fence", + ); + } + let selection = state + .source_eviction_selection + .take() + .expect("matching owner source selection must exist"); + if Arc::strong_count(&selection.cached_info.mem_holder) != 1 { + state.source_eviction_selection = Some(selection); + return item_resp( + item, + OwnerReclaimItemState::Busy, + "owner local memory still has active holders", + ); + } + let local_snapshot = inner + .local_snapshot_info + .remove_if(&item.key, |_, snapshot| { + snapshot.put_time_ms == item.put_id.0 && snapshot.put_version == item.put_id.1 + }) + .map(|(_, snapshot)| snapshot); + assert!(state.reclaim.is_none()); + state.reclaim = Some(OwnerReclaimRecord::Prepared(OwnerPreparedReclaim { + item: item.clone(), + cached_info: selection.cached_info, + local_snapshot, + })); + return item_resp( + item, + OwnerReclaimItemState::Prepared, + "owner source selection promoted to reclaim fence", + ); + } if let Some(state) = controls.get(&item.key) { if let Some(detail) = reclaim_key_control_busy_detail(state) { return item_resp(item, OwnerReclaimItemState::Busy, detail); @@ -206,6 +278,7 @@ fn reclaim_release_fence_is_intact( Some(OwnerReclaimRecord::Releasing(releasing)) if releasing == item ) && state.local_puts == 0 && state.external_pending_puts == 0 + && state.source_eviction_selection.is_none() } fn commit_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclaimItemResp { @@ -318,6 +391,7 @@ mod tests { let state = OwnerKeyControlState { local_puts: 0, external_pending_puts: 0, + source_eviction_selection: None, reclaim: Some(OwnerReclaimRecord::Releasing(item.clone())), external_get: Some(Arc::new(ExternalGetKeySharedOp::new( "remote-during-reclaim".to_string(), @@ -328,6 +402,7 @@ mod tests { let local_put_state = OwnerKeyControlState { local_puts: 1, external_pending_puts: 0, + source_eviction_selection: None, reclaim: Some(OwnerReclaimRecord::Releasing(item.clone())), external_get: state.external_get, }; diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs index ccba45e..2bc3846 100644 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs @@ -62,6 +62,7 @@ use crate::p2p::p2p_module::{P2pModule, P2pModuleAccessTrait}; use crate::rpcresp_kvresult_convert::msg_and_error::{KvError, OK}; use fluxon_framework::{LogicalModule, define_module}; use fluxon_util::map_lock::AMapLock; +use fluxon_util::pin_aware_moka::{PinAwareMoka, PinGuard}; use async_trait::async_trait; use chrono::Utc; @@ -298,7 +299,7 @@ pub struct ReplicaCacheNodeObserveSnapshot { pub reclaim_retry_restored: u64, pub reclaim_completed: u64, pub source_evict_rpc_requests: u64, - pub source_evict_cohorts: u64, + pub source_evict_atomic_batches: u64, pub source_evict_requested_bytes: u64, pub source_evict_accepted: u64, pub source_evict_in_progress: u64, @@ -306,6 +307,8 @@ pub struct ReplicaCacheNodeObserveSnapshot { pub source_evict_retryable_busy: u64, pub source_evict_stale: u64, pub source_evict_rejected: u64, + pub last_route_removed_members: u64, + pub last_route_removed_bytes: u64, pub capacity_eviction_non_ring_b_entry_total: u64, pub capacity_eviction_hit_committed_slot: u64, pub eviction_reclaim_deduplicated: u64, @@ -484,7 +487,7 @@ pub(crate) struct EvictionReclaimCounters { pub retry_restored: AtomicU64, pub completed: AtomicU64, pub source_evict_rpc_requests: AtomicU64, - pub source_evict_cohorts: AtomicU64, + pub source_evict_atomic_batches: AtomicU64, pub source_evict_requested_bytes: AtomicU64, pub source_evict_accepted: AtomicU64, pub source_evict_in_progress: AtomicU64, @@ -492,13 +495,17 @@ pub(crate) struct EvictionReclaimCounters { pub source_evict_retryable_busy: AtomicU64, pub source_evict_stale: AtomicU64, pub source_evict_rejected: AtomicU64, + /// Exact reclaim commits that removed the final readable route for a key. + pub last_route_removed_members: AtomicU64, + /// Physical backing bytes represented by `last_route_removed_members`. + pub last_route_removed_bytes: AtomicU64, /// A Size event from the ring-B controller resolved to any current route /// outside `Allocation && !owner_local_indexed`. pub capacity_eviction_non_ring_b_entry_total: AtomicU64, /// More specific subset retained for diagnostics/backward-compatible /// metrics: the non-ring-B route used a CommittedSlot backing. pub capacity_eviction_hit_committed_slot: AtomicU64, - /// Duplicate listener/cohort events suppressed while the same physical + /// Duplicate listener/atomic_batch events suppressed while the same physical /// cache version already has an outstanding reclaim lifecycle. pub eviction_reclaim_deduplicated: AtomicU64, } @@ -535,16 +542,25 @@ pub(crate) struct MasterKeyActivityLease { table: Arc, key: String, kind: MasterKeyActivityKind, + cache_pins: Mutex>, released: AtomicBool, } impl MasterKeyActivityLease { + pub(crate) fn attach_cache_pin(&self, pin: PinGuard) { + let mut pins = self.cache_pins.lock(); + if !self.released.load(Ordering::Acquire) { + pins.push(pin); + } + } + pub(crate) fn release_now(&self) { if self .released .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire) .is_ok() { + self.cache_pins.lock().clear(); self.table.release(&self.key, self.kind); } } @@ -681,6 +697,7 @@ impl MasterKeyActivityTable { table: self.clone(), key: key.to_string(), kind, + cache_pins: Mutex::new(Vec::new()), released: AtomicBool::new(false), })) } @@ -824,6 +841,25 @@ pub struct NodeValueReplicaDesc { pub put_id: PutIDForAKey, } +#[derive(Clone, Debug, Hash, Eq, PartialEq)] +pub struct MasterPinAlias { + key: String, + put_time_ms: u64, + put_version: u32, +} + +impl MasterPinAlias { + fn new(key: &str, put_id: PutIDForAKey) -> Self { + Self { + key: key.to_string(), + put_time_ms: put_id.0, + put_version: put_id.1, + } + } +} + +pub type MasterNodeCache = PinAwareMoka; + /// Information about a completed `put` operation that can be retrieved via `get`. /// Now supports multiple replicas per key. #[derive(Clone, Debug)] @@ -1271,7 +1307,7 @@ async fn cleanup_departed_generation_routes( ); } -const MAX_INFERRED_TP_COHORT_SIZE: usize = 256; +const MAX_INFERRED_TP_ATOMIC_BATCH_SIZE: usize = 256; #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub(crate) struct InferredTpKey<'a> { @@ -1300,7 +1336,7 @@ pub(crate) fn infer_sglang_tp_key(key: &str) -> Option> { let rank = raw_rank.parse::().ok()?; let size = raw_size.parse::().ok()?; if size == 0 - || size > MAX_INFERRED_TP_COHORT_SIZE + || size > MAX_INFERRED_TP_ATOMIC_BATCH_SIZE || rank >= size || raw_rank != rank.to_string() || raw_size != size.to_string() @@ -1315,69 +1351,54 @@ pub(crate) fn infer_sglang_tp_key(key: &str) -> Option> { } #[derive(Clone, Copy, Debug, Eq, PartialEq)] -enum CohortExpansionError { +enum AtomicBatchExpansionError { AtomicGroupIncomplete, - TpCohortIncomplete, + TpAtomicBatchIncomplete, } fn take_exact_cache_entries( - cache: &moka::sync::SegmentedCache, + cache: &MasterNodeCache, expected_entries: &HashMap, ) -> Option> { let mut removed_entries = Vec::with_capacity(expected_entries.len()); for (candidate_key, expected_desc) in expected_entries { - let result = cache - .entry(candidate_key.clone()) - .and_compute_with(|current| { - if current.as_ref().is_some_and(|entry| { - entry.value().put_id == expected_desc.put_id - && entry.value().weight_bytes == expected_desc.weight_bytes - }) { - moka::ops::compute::Op::Remove - } else { - moka::ops::compute::Op::Nop - } - }); - match result { - moka::ops::compute::CompResult::Removed(entry) => { - removed_entries.push((candidate_key.clone(), entry.into_value())); - } - _ => { - for (removed_key, removed_desc) in removed_entries { - cache.insert(removed_key, removed_desc); - } - return None; + let removed = cache.take_if(candidate_key, |entry| { + entry.put_id == expected_desc.put_id && entry.weight_bytes == expected_desc.weight_bytes + }); + if let Some(removed) = removed { + removed_entries.push((candidate_key.clone(), removed)); + } else { + for (removed_key, removed_desc) in removed_entries { + insert_master_cache_entry(cache, removed_key, removed_desc); } + return None; } } Some(removed_entries) } fn remove_exact_cache_entry( - cache: &moka::sync::SegmentedCache, + cache: &MasterNodeCache, key: &str, expected_desc: &NodeValueReplicaDesc, ) -> bool { - matches!( - cache.entry(key.to_string()).and_compute_with(|current| { - if current.as_ref().is_some_and(|entry| { - entry.value().put_id == expected_desc.put_id - && entry.value().weight_bytes == expected_desc.weight_bytes - }) { - moka::ops::compute::Op::Remove - } else { - moka::ops::compute::Op::Nop - } - }), - moka::ops::compute::CompResult::Removed(_) - ) + cache + .take_if(&key.to_string(), |entry| { + entry.put_id == expected_desc.put_id && entry.weight_bytes == expected_desc.weight_bytes + }) + .is_some() +} + +fn insert_master_cache_entry(cache: &MasterNodeCache, key: String, desc: NodeValueReplicaDesc) { + let alias = MasterPinAlias::new(&key, desc.put_id); + cache.insert(key, [alias], desc); } fn current_atomic_group_members( key: &str, route: &OneKvNodesRoutes, desc: &NodeValueReplicaDesc, -) -> Result, CohortExpansionError> { +) -> Result, AtomicBatchExpansionError> { let Some(group) = route.atomic_group.as_ref() else { return Ok(vec![msg_pack::PutAtomicGroupMember { key: key.to_string(), @@ -1389,16 +1410,16 @@ fn current_atomic_group_members( .iter() .any(|member| member.key == key && member.put_id == desc.put_id) { - return Err(CohortExpansionError::AtomicGroupIncomplete); + return Err(AtomicBatchExpansionError::AtomicGroupIncomplete); } Ok(group.members.clone()) } -fn current_tp_cohort_keys( +fn current_tp_atomic_batch_keys( key: &str, route: &OneKvNodesRoutes, desc: &NodeValueReplicaDesc, -) -> Result, CohortExpansionError> { +) -> Result, AtomicBatchExpansionError> { let current_members = current_atomic_group_members(key, route, desc)?; let Some(key_tp) = infer_sglang_tp_key(key) else { return Ok(current_members @@ -1416,23 +1437,23 @@ fn current_tp_cohort_keys( let mut logical_members = Vec::with_capacity(current_members.len()); for member in current_members { let Some(member_tp) = infer_sglang_tp_key(&member.key) else { - return Err(CohortExpansionError::TpCohortIncomplete); + return Err(AtomicBatchExpansionError::TpAtomicBatchIncomplete); }; if member_tp.rank != key_tp.rank || member_tp.size != key_tp.size { - return Err(CohortExpansionError::TpCohortIncomplete); + return Err(AtomicBatchExpansionError::TpAtomicBatchIncomplete); } logical_members.push(member_tp.logical_prefix.to_string()); } - let mut cohort_keys = Vec::with_capacity(logical_members.len() * key_tp.size); + let mut atomic_batch_keys = Vec::with_capacity(logical_members.len() * key_tp.size); for rank in 0..key_tp.size { - cohort_keys.extend( + atomic_batch_keys.extend( logical_members .iter() .map(|logical_prefix| format!("{logical_prefix}_{rank}_{}", key_tp.size)), ); } - Ok(cohort_keys) + Ok(atomic_batch_keys) } #[cfg(test)] @@ -1961,7 +1982,7 @@ mod tests { } #[test] - fn tp_cohort_expansion_preserves_every_atomic_member_across_ranks() { + fn tp_atomic_batch_expansion_preserves_every_atomic_member_across_ranks() { let rank0_group = Arc::new(PutAtomicGroup { members: vec![ msg_pack::PutAtomicGroupMember { @@ -1981,7 +2002,7 @@ mod tests { put_id: (10, 0), }; assert_eq!( - current_tp_cohort_keys("page0_model_0_2", &rank0_page0, &desc).unwrap(), + current_tp_atomic_batch_keys("page0_model_0_2", &rank0_page0, &desc).unwrap(), vec![ "page0_model_0_2", "page1_model_0_2", @@ -1993,10 +2014,8 @@ mod tests { #[test] fn exact_cache_detach_rolls_back_identity_mismatch() { - let cache = moka::sync::SegmentedCache::builder(8) - .weigher(Box::new(|_key: &String, desc: &NodeValueReplicaDesc| { - desc.weight_bytes - })) + let cache = MasterNodeCache::builder(1024 * 1024) + .weigher(|_key: &String, desc: &NodeValueReplicaDesc| desc.weight_bytes) .build(); let actual = HashMap::from([ ( @@ -2015,31 +2034,37 @@ mod tests { ), ]); for (key, desc) in &actual { - cache.insert(key.clone(), desc.clone()); + insert_master_cache_entry(&cache, key.clone(), desc.clone()); } let mut stale_expected = actual.clone(); stale_expected.get_mut("rank1").unwrap().put_id = (999, 0); assert!(take_exact_cache_entries(&cache, &stale_expected).is_none()); - assert_eq!(cache.get("rank0").unwrap().put_id, (30, 0)); - assert_eq!(cache.get("rank1").unwrap().put_id, (31, 0)); + assert_eq!(cache.get(&"rank0".to_string()).unwrap().put_id, (30, 0)); + assert_eq!(cache.get(&"rank1".to_string()).unwrap().put_id, (31, 0)); let removed = take_exact_cache_entries(&cache, &actual).unwrap(); assert_eq!(removed.len(), 2); - assert!(cache.get("rank0").is_none()); - assert!(cache.get("rank1").is_none()); + assert!(cache.get(&"rank0".to_string()).is_none()); + assert!(cache.get(&"rank1".to_string()).is_none()); } #[test] fn ring_b_cache_is_bounded_for_every_node_role() { - let cache = moka::sync::SegmentedCache::builder(8) - .max_capacity(64) - .weigher(Box::new(|_key: &u64, weight: &u32| *weight)) + let cache = MasterNodeCache::builder(64) + .weigher(|_key: &String, desc: &NodeValueReplicaDesc| desc.weight_bytes) .build(); - assert_eq!(cache.policy().max_capacity(), Some(64)); + assert_eq!(cache.max_capacity(), Some(64)); for key in 0..128 { - cache.insert(key, 8); + insert_master_cache_entry( + &cache, + key.to_string(), + NodeValueReplicaDesc { + weight_bytes: 8, + put_id: (10, key), + }, + ); } cache.run_pending_tasks(); assert!(cache.weighted_size() <= 64); @@ -2047,15 +2072,14 @@ mod tests { #[test] fn ring_b_live_capacity_update_never_clears_boundary() { - let cache = moka::sync::SegmentedCache::builder(8) - .max_capacity(1024) - .weigher(Box::new(|_key: &u64, weight: &u32| *weight)) + let cache = MasterNodeCache::builder(1024) + .weigher(|_key: &String, desc: &NodeValueReplicaDesc| desc.weight_bytes) .build(); - assert_eq!(cache.policy().max_capacity(), Some(1024)); + assert_eq!(cache.max_capacity(), Some(1024)); cache.set_max_capacity(512).unwrap(); - assert_eq!(cache.policy().max_capacity(), Some(512)); + assert_eq!(cache.max_capacity(), Some(512)); cache.set_max_capacity(2048).unwrap(); - assert_eq!(cache.policy().max_capacity(), Some(2048)); + assert_eq!(cache.max_capacity(), Some(2048)); } #[test] @@ -2074,7 +2098,7 @@ mod tests { } #[test] - fn cohort_reclaim_identity_registration_is_all_or_nothing() { + fn atomic_batch_reclaim_identity_registration_is_all_or_nothing() { let request = |keys: &[&str]| reclaim::EvictionReclaimRequest { owner_node_id: "cpu0".to_string(), owner_node_start_time: None, @@ -2106,7 +2130,7 @@ mod tests { ); // `c` is tentatively installed before the collision on `a`; failure - // must roll it back and preserve only the original cohort. + // must roll it back and preserve only the original atomic_batch. let overlapping = reclaim::EvictionReclaimRequest { members: vec![ reclaim::EvictionReclaimMember { @@ -2168,7 +2192,7 @@ mod tests { #[test] fn closed_lossless_channel_rolls_back_identity_accounting_and_metadata() { - let cache = moka::sync::SegmentedCache::builder(8).build(); + let cache = MasterNodeCache::builder(1024 * 1024).build(); let request = reclaim::EvictionReclaimRequest { owner_node_id: "cpu0".to_string(), owner_node_start_time: None, @@ -2198,12 +2222,12 @@ mod tests { } subtract_pending_eviction_weight(&pending, "cpu0", returned.weight_bytes()); for member in returned.members { - cache.insert(member.key, member.desc); + insert_master_cache_entry(&cache, member.key, member.desc); } assert!(inflight.is_empty()); assert_eq!(pending.load(Ordering::Acquire), 0); - assert!(cache.get("closed-channel").is_some()); + assert!(cache.get(&"closed-channel".to_string()).is_some()); } fn new_test_member(metadata: HashMap) -> ClusterMember { @@ -2330,14 +2354,12 @@ pub struct MasterKvRouterInner { pub prefix_index: ARwLock, /// Support replicas: node_id -> key -> route_info - pub node_kv_cache_controller: - DashMap>>, + pub node_kv_cache_controller: DashMap>, /// Independent pre-writeback tier. Its Size eviction starts a replica task /// while owner residency remains governed by the owner's local hot cache; /// `node_kv_cache_controller` tracks ring B only. - pub node_writeback_tier1_controller: - DashMap>>, + pub node_writeback_tier1_controller: DashMap>, /// Per-node bytes reserved out of moka usable capacity. /// The reservation is reason-grouped, but `total_bytes` is the authority @@ -2348,7 +2370,7 @@ pub struct MasterKvRouterInner { pub eviction_reclaim_pending_weight: DashMap>, /// Exact, versioned metadata identities currently owned by the lossless - /// eviction-reclaim pipeline. This bounds duplicate Size/cohort events; + /// eviction-reclaim pipeline. This bounds duplicate Size/atomic_batch events; /// payload memory is not retained here. pub(crate) eviction_reclaim_inflight: DashSet, @@ -2360,7 +2382,7 @@ pub struct MasterKvRouterInner { /// Bounded maintenance can still process a batch of Size evictions; without /// this gate, concurrent async tasks can park multiple Tokio workers on the /// same blocking Moka lock. It is a scheduling gate, not a correctness or - /// cohort lock, and no cache/global scan occurs under it. + /// atomic_batch lock, and no cache/global scan occurs under it. pub(crate) owner_cache_operation_locks: AMapLock, /// Historical final put placement decisions by target node. @@ -2742,7 +2764,8 @@ impl MasterKvRouter { }, )); } - self.inner() + let lease = self + .inner() .key_activity .reserve(key, MasterKeyActivityKind::Put, reject_if_inflight_same_key) .ok_or_else(|| { @@ -2751,14 +2774,17 @@ impl MasterKvRouter { key: key.to_string(), }, ) - }) + })?; + self.pin_current_master_cache_entries_for_activity(&lease, key); + Ok(lease) } pub(crate) fn reserve_inflight_get_key( &self, key: &str, ) -> Result, KvError> { - self.inner() + let lease = self + .inner() .key_activity .reserve(key, MasterKeyActivityKind::Get, false) .ok_or_else(|| { @@ -2767,7 +2793,9 @@ impl MasterKvRouter { key: key.to_string(), }, ) - }) + })?; + self.pin_current_master_cache_entries_for_activity(&lease, key); + Ok(lease) } pub(crate) fn reserve_prepared_get_requester( @@ -2792,7 +2820,8 @@ impl MasterKvRouter { &self, key: &str, ) -> Result, KvError> { - self.inner() + let lease = self + .inner() .key_activity .reserve(key, MasterKeyActivityKind::Replica, false) .ok_or_else(|| { @@ -2801,7 +2830,99 @@ impl MasterKvRouter { key: key.to_string(), }, ) + })?; + self.pin_current_master_cache_entries_for_activity(&lease, key); + Ok(lease) + } + + fn attach_cache_pin_if_present( + &self, + lease: &Arc, + cache: &MasterNodeCache, + key: &str, + desc: &NodeValueReplicaDesc, + ) { + let alias = MasterPinAlias::new(key, desc.put_id); + if let Some(pin) = cache.try_pin_alias_if(alias, |entry| { + entry.put_id == desc.put_id && entry.weight_bytes == desc.weight_bytes + }) { + lease.attach_cache_pin(pin); + } + } + + pub(crate) fn pin_master_cache_identity_for_activity( + &self, + lease: &Arc, + owner_node_id: &str, + key: &str, + desc: &NodeValueReplicaDesc, + ) { + if let Some(cache) = self + .inner() + .node_kv_cache_controller + .get(owner_node_id) + .map(|entry| entry.value().clone()) + { + self.attach_cache_pin_if_present(lease, cache.as_ref(), key, desc); + } + if let Some(cache) = self + .inner() + .node_writeback_tier1_controller + .get(owner_node_id) + .map(|entry| entry.value().clone()) + { + self.attach_cache_pin_if_present(lease, cache.as_ref(), key, desc); + } + } + + pub(crate) fn pin_current_master_cache_identity_for_activity( + &self, + lease: &Arc, + owner_node_id: &str, + key: &str, + put_id: PutIDForAKey, + ) { + let desc = self.inner().kv_routes.get(key).and_then(|route| { + (route.put_id == put_id).then(|| ring_b_route_replica_desc(&route, owner_node_id))? + }); + if let Some(desc) = desc { + self.pin_master_cache_identity_for_activity(lease, owner_node_id, key, &desc); + } + } + + fn pin_current_master_cache_entries_for_activity( + &self, + lease: &Arc, + key: &str, + ) { + let entries = self + .inner() + .kv_routes + .get(key) + .map(|route| { + let put_id = route.put_id; + route + .nodes_replicas + .read() + .iter() + .filter_map(|(node_id, replica)| { + (!replica.tomb_tag.is_tomb()).then(|| { + ( + node_id.as_ref().to_string(), + NodeValueReplicaDesc { + weight_bytes: u32::try_from(replica.backing.capacity_bytes()) + .unwrap_or(u32::MAX), + put_id, + }, + ) + }) + }) + .collect::>() }) + .unwrap_or_default(); + for (node_id, desc) in entries { + self.pin_master_cache_identity_for_activity(lease, node_id.as_str(), key, &desc); + } } pub fn key_has_live_replica(&self, key: &str) -> bool { @@ -2901,7 +3022,7 @@ impl MasterKvRouter { desc: NodeValueReplicaDesc, origin: reclaim::EvictionReclaimOrigin, ) -> bool { - self.enqueue_eviction_reclaim_cohort( + self.enqueue_eviction_reclaim_atomic_batch( owner_node_id, vec![reclaim::EvictionReclaimMember { key, @@ -2912,27 +3033,33 @@ impl MasterKvRouter { ) } - fn enqueue_eviction_reclaim_cohort( + fn enqueue_eviction_reclaim_atomic_batch( &self, owner_node_id: NodeIDString, members: Vec, origin: reclaim::EvictionReclaimOrigin, ) -> bool { matches!( - self.enqueue_eviction_reclaim_cohort_exact(owner_node_id, None, members, origin, true,), + self.enqueue_eviction_reclaim_atomic_batch_exact( + owner_node_id, + None, + members, + origin, + true, + ), reclaim::EnqueueEvictionReclaimResult::Accepted | reclaim::EnqueueEvictionReclaimResult::AlreadyInProgress ) } - pub(crate) fn enqueue_owner_capacity_eviction_cohort( + pub(crate) fn enqueue_owner_capacity_eviction_atomic_batch( &self, owner_node_id: NodeIDString, owner_node_start_time: i64, members: Vec, allow_new_request: bool, ) -> reclaim::EnqueueEvictionReclaimResult { - self.enqueue_eviction_reclaim_cohort_exact( + self.enqueue_eviction_reclaim_atomic_batch_exact( owner_node_id, Some(owner_node_start_time), members, @@ -2941,7 +3068,7 @@ impl MasterKvRouter { ) } - fn enqueue_eviction_reclaim_cohort_exact( + fn enqueue_eviction_reclaim_atomic_batch_exact( &self, owner_node_id: NodeIDString, owner_node_start_time: Option, @@ -2970,7 +3097,7 @@ impl MasterKvRouter { self.eviction_reclaim_counters(&request.owner_node_id) .eviction_reclaim_deduplicated .fetch_add(1, Ordering::Relaxed); - // An idempotent retry is accepted only when the complete cohort + // An idempotent retry is accepted only when the complete atomic_batch // is already owned by the pipeline. A partial overlap is not a // valid source handoff. return if request @@ -3191,7 +3318,7 @@ impl MasterKvRouter { }; // Restoration is an exact metadata repair after a failed reclaim // dispatch. It must never search for or evict an unrelated victim. - cache.insert(key, desc); + insert_master_cache_entry(cache.as_ref(), key, desc); true } @@ -4498,10 +4625,7 @@ impl MasterKvRouter { }); } - pub fn get_node_cache_controller( - &self, - node_id: &str, - ) -> Option>> { + pub fn get_node_cache_controller(&self, node_id: &str) -> Option> { if !self.replica_cache_enabled() { return None; } @@ -4527,32 +4651,30 @@ impl MasterKvRouter { .or_insert_with(move || { let view = view.clone(); let cache_node_id = node_id_owned.clone(); - let builder = moka::sync::SegmentedCache::builder(8) + let builder = MasterNodeCache::builder(allocation_capacity) // Admission is restricted to unindexed Allocation // routes. CommittedSlot and owner-indexed Allocation // entries belong to ring A and never enter this cache. - .weigher(Box::new(|_key: &String, value: &NodeValueReplicaDesc| { - value.weight_bytes - })) - .eviction_listener(Box::new( + .weigher(|_key: &String, value: &NodeValueReplicaDesc| value.weight_bytes) + .eviction_listener( move |key: Arc, - _value: NodeValueReplicaDesc, + value: NodeValueReplicaDesc, cause: RemovalCause| { if cause == RemovalCause::Size { // Listener work is deliberately O(1): // clone fixed metadata, dedupe, and send - // to a lossless channel. Route/cohort + // to a lossless channel. Route/atomic_batch // lookup belongs to the async actor. let _ = view.master_kv_router().enqueue_eviction_reclaim( cache_node_id.clone(), (*key).clone(), - _value, + value, reclaim::EvictionReclaimOrigin::MasterAllocationCapacity, ); } }, - )); - Arc::new(builder.max_capacity(allocation_capacity).build()) + ); + Arc::new(builder.build()) }) .value() .clone(), @@ -4589,7 +4711,7 @@ impl MasterKvRouter { pub fn get_node_writeback_tier1_controller( &self, node_id: &str, - ) -> Option>> { + ) -> Option> { if !self.tier1_source_node_eligible(node_id) { return None; } @@ -4611,12 +4733,11 @@ impl MasterKvRouter { .or_insert_with(move || { let cache_node_id = node_id_owned.clone(); Arc::new( - moka::sync::SegmentedCache::builder(8) - .max_capacity(base_capacity) - .weigher(Box::new(|_key: &String, value: &NodeValueReplicaDesc| { + MasterNodeCache::builder(base_capacity) + .weigher(|_key: &String, value: &NodeValueReplicaDesc| { value.weight_bytes - })) - .eviction_listener(Box::new( + }) + .eviction_listener( move |key: Arc, value: NodeValueReplicaDesc, cause: RemovalCause| { @@ -4628,7 +4749,7 @@ impl MasterKvRouter { ); } }, - )) + ) .build(), ) }) @@ -5059,7 +5180,6 @@ impl MasterKvRouter { // Every live node's ring-B controller is bounded, independent of // its placement role. let effective_capacity_bytes = cache - .policy() .max_capacity() .expect("ring-B controller must always be bounded"); let pending_eviction_reclaim_bytes = @@ -5088,7 +5208,7 @@ impl MasterKvRouter { .unwrap_or(0), writeback_tier1_capacity_bytes: tier1_cache .as_ref() - .and_then(|cache| cache.policy().max_capacity()) + .and_then(|cache| cache.max_capacity()) .unwrap_or(0), writeback_tier1_triggered: Self::tier1_writeback_counter( &self.inner().tier1_writeback_trigger_counts, @@ -5119,8 +5239,8 @@ impl MasterKvRouter { source_evict_rpc_requests: reclaim_counters .source_evict_rpc_requests .load(Ordering::Relaxed), - source_evict_cohorts: reclaim_counters - .source_evict_cohorts + source_evict_atomic_batches: reclaim_counters + .source_evict_atomic_batches .load(Ordering::Relaxed), source_evict_requested_bytes: reclaim_counters .source_evict_requested_bytes @@ -5141,6 +5261,12 @@ impl MasterKvRouter { source_evict_rejected: reclaim_counters .source_evict_rejected .load(Ordering::Relaxed), + last_route_removed_members: reclaim_counters + .last_route_removed_members + .load(Ordering::Relaxed), + last_route_removed_bytes: reclaim_counters + .last_route_removed_bytes + .load(Ordering::Relaxed), capacity_eviction_non_ring_b_entry_total: reclaim_counters .capacity_eviction_non_ring_b_entry_total .load(Ordering::Relaxed), @@ -5187,7 +5313,7 @@ impl MasterKvRouter { ); for node in snapshot.replica_cache_nodes { tracing::info!( - "replica cache runtime: owner={} entries={} weighted_bytes={} effective_capacity_bytes={} base_capacity_bytes={} reserved_capacity_bytes={} pending_eviction_reclaim_bytes={} writeback_tier1_entries={} writeback_tier1_weighted_bytes={} writeback_tier1_capacity_bytes={} writeback_tier1_triggered={} writeback_tier1_owner_accepted={} writeback_tier1_failed={} reclaim_master_activity_deferred={} reclaim_owner_holder_deferred={} reclaim_owner_other_deferred={} reclaim_route_changed={} reclaim_retry_queued={} reclaim_retry_completed={} reclaim_retry_restored={} reclaim_completed={} source_evict_rpc_requests={} source_evict_cohorts={} source_evict_requested_bytes={} source_evict_accepted={} source_evict_in_progress={} source_evict_completed={} source_evict_retryable_busy={} source_evict_stale={} source_evict_rejected={} capacity_eviction_non_ring_b_entry_total={} capacity_eviction_hit_committed_slot={} eviction_reclaim_deduplicated={}", + "replica cache runtime: owner={} entries={} weighted_bytes={} effective_capacity_bytes={} base_capacity_bytes={} reserved_capacity_bytes={} pending_eviction_reclaim_bytes={} writeback_tier1_entries={} writeback_tier1_weighted_bytes={} writeback_tier1_capacity_bytes={} writeback_tier1_triggered={} writeback_tier1_owner_accepted={} writeback_tier1_failed={} reclaim_master_activity_deferred={} reclaim_owner_holder_deferred={} reclaim_owner_other_deferred={} reclaim_route_changed={} reclaim_retry_queued={} reclaim_retry_completed={} reclaim_retry_restored={} reclaim_completed={} source_evict_rpc_requests={} source_evict_atomic_batches={} source_evict_requested_bytes={} source_evict_accepted={} source_evict_in_progress={} source_evict_completed={} source_evict_retryable_busy={} source_evict_stale={} source_evict_rejected={} last_route_removed_members={} last_route_removed_bytes={} capacity_eviction_non_ring_b_entry_total={} capacity_eviction_hit_committed_slot={} eviction_reclaim_deduplicated={}", node.owner_node, node.entries, node.weighted_bytes, @@ -5210,7 +5336,7 @@ impl MasterKvRouter { node.reclaim_retry_restored, node.reclaim_completed, node.source_evict_rpc_requests, - node.source_evict_cohorts, + node.source_evict_atomic_batches, node.source_evict_requested_bytes, node.source_evict_accepted, node.source_evict_in_progress, @@ -5218,6 +5344,8 @@ impl MasterKvRouter { node.source_evict_retryable_busy, node.source_evict_stale, node.source_evict_rejected, + node.last_route_removed_members, + node.last_route_removed_bytes, node.capacity_eviction_non_ring_b_entry_total, node.capacity_eviction_hit_committed_slot, node.eviction_reclaim_deduplicated, diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs index 048732e..6b23403 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs @@ -372,7 +372,7 @@ pub struct OwnerSourceEvictionMember { /// Atomic/TP members which must enter the reclaim pipeline together. #[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)] -pub struct OwnerSourceEvictionCohort { +pub struct OwnerSourceEvictionAtomicBatch { pub members: Vec, } @@ -381,7 +381,7 @@ pub struct BatchEvictOwnerSourceReq { pub operation_id: u64, /// Membership generation of the authenticated source owner. pub owner_node_start_time: i64, - pub cohorts: Vec, + pub atomic_batches: Vec, } impl MsgPackSerializePart for BatchEvictOwnerSourceReq { @@ -403,8 +403,8 @@ pub enum OwnerSourceEvictionOutcome { } #[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)] -pub struct OwnerSourceEvictionCohortResp { - pub cohort_index: u32, +pub struct OwnerSourceEvictionAtomicBatchResp { + pub atomic_batch_index: u32, pub outcome: OwnerSourceEvictionOutcome, pub detail: String, } @@ -412,7 +412,7 @@ pub struct OwnerSourceEvictionCohortResp { #[derive(Default, Debug, Clone, Encode, Decode)] pub struct BatchEvictOwnerSourceResp { pub operation_id: u64, - pub cohorts: Vec, + pub atomic_batches: Vec, pub error_code: ErrorCode, pub error_json: String, } diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs index 4992419..1edc824 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs @@ -487,6 +487,13 @@ fn reserve_replica_task_excluding( protect_source_on_remote_complete: bool, ) -> msg_and_error::KvResult { let activity_lease = view.master_kv_router().reserve_inflight_replica_key(key)?; + view.master_kv_router() + .pin_current_master_cache_identity_for_activity( + &activity_lease, + source_node_id.as_ref(), + key, + put_id, + ); let (target_node_id, target_allocation) = view .master_kv_router() .inner() diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs index 39f2ee7..e2c8d01 100644 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs @@ -3,7 +3,7 @@ use crate::cluster_manager::{NodeID, NodeIDString}; use crate::master_kv_router::msg_pack::{ BatchEvictOwnerSourceReq, BatchEvictOwnerSourceResp, BatchOwnerReclaimReq, OwnerReclaimBacking, OwnerReclaimItem, OwnerReclaimItemResp, OwnerReclaimItemState, OwnerReclaimPhase, - OwnerReclaimReason, OwnerSourceEvictionCohort, OwnerSourceEvictionCohortResp, + OwnerReclaimReason, OwnerSourceEvictionAtomicBatch, OwnerSourceEvictionAtomicBatchResp, OwnerSourceEvictionOutcome, }; use crate::p2p::msg_pack::{MIN_EXPLICIT_RPC_TIMEOUT_SECS, MsgPack, RPCCaller}; @@ -66,7 +66,7 @@ mod timeout_contract_tests { } #[cfg(test)] -mod cohort_transaction_tests { +mod atomic_batch_transaction_tests { use super::*; use crate::master_kv_router::msg_pack::{ OwnerSourceEvictionMember, PutAtomicGroup, PutAtomicGroupMember, @@ -96,24 +96,24 @@ mod cohort_transaction_tests { } #[test] - fn cohort_master_fences_roll_back_all_members_when_one_is_busy() { + fn atomic_batch_master_fences_roll_back_all_members_when_one_is_busy() { let activity = Arc::new(MasterKeyActivityTable::default()); let items = vec![item("rank0", 1), item("rank1", 2)]; let _busy = activity .reserve("rank1", MasterKeyActivityKind::Get, false) .unwrap(); - assert!(try_install_cohort_master_fences(&activity, &items).is_err()); + assert!(try_install_atomic_batch_master_fences(&activity, &items).is_err()); assert!(!activity.has_reclaim("rank0")); assert!(!activity.has_reclaim("rank1")); } #[test] - fn cohort_master_fences_install_and_clear_as_one_set() { + fn atomic_batch_master_fences_install_and_clear_as_one_set() { let activity = Arc::new(MasterKeyActivityTable::default()); let items = vec![item("rank0", 1), item("rank1", 2)]; - try_install_cohort_master_fences(&activity, &items).unwrap(); + try_install_atomic_batch_master_fences(&activity, &items).unwrap(); assert!(activity.has_reclaim("rank0")); assert!(activity.has_reclaim("rank1")); for item in &items { @@ -231,17 +231,17 @@ mod cohort_transaction_tests { fn exact_source_plan_accepts_with_or_without_a_cpu_replica() { let owner: NodeID = "gpu0".to_string().into(); let member = source_member("single", (10, 1), 7, 3); - let cohort = OwnerSourceEvictionCohort { + let atomic_batch = OwnerSourceEvictionAtomicBatch { members: vec![member.clone()], }; for include_cpu_replica in [false, true] { let route = source_route(&owner, &member, None, include_cpu_replica); - let plan = plan_exact_owner_source_cohort_with(&owner, &cohort, &|key| { + let plan = plan_exact_owner_source_atomic_batch_with(&owner, &atomic_batch, &|key| { (key == "single").then(|| route.clone()) }); match plan { - OwnerSourceCohortPlan::Ready { + OwnerSourceAtomicBatchPlan::Ready { members, all_sources_present, } => { @@ -267,7 +267,14 @@ mod cohort_transaction_tests { let removed = remove_exact_owner_source_route(&routes, &owner, &source_reclaim_item(&member)) .expect("exact GPU source must be removed"); + let counters = crate::master_kv_router::EvictionReclaimCounters::default(); + record_last_route_removal(&counters, &removed); assert!(!removed.removed_last_route); + assert_eq!( + counters.last_route_removed_members.load(Ordering::Relaxed), + 0 + ); + assert_eq!(counters.last_route_removed_bytes.load(Ordering::Relaxed), 0); let remaining = routes.get(&member.key).expect("CPU route must remain"); assert!(!remaining.nodes_replicas.read().contains_key(&owner)); assert!(remaining.nodes_replicas.read().contains_key("cpu0")); @@ -276,8 +283,17 @@ mod cohort_transaction_tests { routes.insert(last.key.clone(), source_route(&owner, &last, None, false)); let removed = remove_exact_owner_source_route(&routes, &owner, &source_reclaim_item(&last)) .expect("last exact GPU source must be removed"); + record_last_route_removal(&counters, &removed); assert!(removed.removed_last_route); assert!(!routes.contains_key(&last.key)); + assert_eq!( + counters.last_route_removed_members.load(Ordering::Relaxed), + 1 + ); + assert_eq!( + counters.last_route_removed_bytes.load(Ordering::Relaxed), + removed.capacity_bytes + ); let stale = source_member("stale", (10, 4), 8, 6); routes.insert(stale.key.clone(), source_route(&owner, &stale, None, false)); @@ -298,7 +314,7 @@ mod cohort_transaction_tests { let owner: NodeID = "gpu0".to_string().into(); let a = source_member("a", (11, 0), 8, 0); let b = source_member("b", (11, 1), 8, 1); - let cohort = OwnerSourceEvictionCohort { + let atomic_batch = OwnerSourceEvictionAtomicBatch { members: vec![a.clone(), b.clone()], }; let group = Arc::new(PutAtomicGroup { @@ -315,27 +331,29 @@ mod cohort_transaction_tests { }); let route_a = source_route(&owner, &a, Some(group), false); - match plan_exact_owner_source_cohort_with(&owner, &cohort, &|key| { + match plan_exact_owner_source_atomic_batch_with(&owner, &atomic_batch, &|key| { (key == "a").then(|| route_a.clone()) }) { - OwnerSourceCohortPlan::Ready { + OwnerSourceAtomicBatchPlan::Ready { all_sources_present, .. } => assert!(!all_sources_present), - _ => panic!("a partially removed accepted cohort must be recognized as replay-only"), + _ => panic!( + "a partially removed accepted atomic_batch must be recognized as replay-only" + ), } assert!(matches!( - plan_exact_owner_source_cohort_with(&owner, &cohort, &|_| None), - OwnerSourceCohortPlan::Completed(_) + plan_exact_owner_source_atomic_batch_with(&owner, &atomic_batch, &|_| None), + OwnerSourceAtomicBatchPlan::Completed(_) )); } #[test] - fn one_stale_or_inconsistent_member_rejects_the_whole_source_cohort() { + fn one_stale_or_inconsistent_member_rejects_the_whole_source_atomic_batch() { let owner: NodeID = "gpu0".to_string().into(); let a = source_member("a", (12, 0), 9, 0); let b = source_member("b", (12, 1), 9, 1); - let cohort = OwnerSourceEvictionCohort { + let atomic_batch = OwnerSourceEvictionAtomicBatch { members: vec![a.clone(), b.clone()], }; let group = Arc::new(PutAtomicGroup { @@ -355,26 +373,26 @@ mod cohort_transaction_tests { let route_b_with_changed_backing = source_route(&owner, &changed_b, Some(group.clone()), false); let stale_backing_plan = - plan_exact_owner_source_cohort_with(&owner, &cohort, &|key| match key { + plan_exact_owner_source_atomic_batch_with(&owner, &atomic_batch, &|key| match key { "a" => Some(route_a.clone()), "b" => Some(route_b_with_changed_backing.clone()), _ => None, }); assert!(matches!( stale_backing_plan, - OwnerSourceCohortPlan::Stale(_) + OwnerSourceAtomicBatchPlan::Stale(_) )); let route_b_without_group = source_route(&owner, &b, None, false); let inconsistent_group_plan = - plan_exact_owner_source_cohort_with(&owner, &cohort, &|key| match key { + plan_exact_owner_source_atomic_batch_with(&owner, &atomic_batch, &|key| match key { "a" => Some(route_a.clone()), "b" => Some(route_b_without_group.clone()), _ => None, }); assert!(matches!( inconsistent_group_plan, - OwnerSourceCohortPlan::Rejected(_) + OwnerSourceAtomicBatchPlan::Rejected(_) )); } } @@ -451,7 +469,7 @@ impl EvictionReclaimRequest { #[derive(Clone, Copy, Debug, Eq, PartialEq)] enum MasterCapacityPlanError { RouteChanged, - InvalidCohort, + InvalidAtomicBatch, WrongRole, CommittedSlot, } @@ -511,9 +529,9 @@ fn allocation_member_from_route( )) } -/// Expand one master Size event by point-looking up its atomic/TP cohort. +/// Expand one master Size event by point-looking up its atomic/TP atomic_batch. /// This function never iterates the resident cache or global route table. -fn plan_master_allocation_capacity_cohort( +fn plan_master_allocation_capacity_atomic_batch( view: &MasterKvRouterView, request: &EvictionReclaimRequest, ) -> Result, MasterCapacityPlanError> { @@ -530,31 +548,31 @@ fn plan_master_allocation_capacity_cohort( { return Err(MasterCapacityPlanError::RouteChanged); } - let mut cohort_keys = - super::current_tp_cohort_keys(&anchor.key, &anchor_route, ¤t_anchor.desc) - .map_err(|_| MasterCapacityPlanError::InvalidCohort)?; - cohort_keys.sort_unstable(); - cohort_keys.dedup(); - if cohort_keys.is_empty() { - return Err(MasterCapacityPlanError::InvalidCohort); + let mut atomic_batch_keys = + super::current_tp_atomic_batch_keys(&anchor.key, &anchor_route, ¤t_anchor.desc) + .map_err(|_| MasterCapacityPlanError::InvalidAtomicBatch)?; + atomic_batch_keys.sort_unstable(); + atomic_batch_keys.dedup(); + if atomic_batch_keys.is_empty() { + return Err(MasterCapacityPlanError::InvalidAtomicBatch); } - let mut members = Vec::with_capacity(cohort_keys.len()); - for key in &cohort_keys { + let mut members = Vec::with_capacity(atomic_batch_keys.len()); + for key in &atomic_batch_keys { let (member, route) = allocation_member_from_route(view, &owner, key)?; - let mut peer_keys = super::current_tp_cohort_keys(key, &route, &member.desc) - .map_err(|_| MasterCapacityPlanError::InvalidCohort)?; + let mut peer_keys = super::current_tp_atomic_batch_keys(key, &route, &member.desc) + .map_err(|_| MasterCapacityPlanError::InvalidAtomicBatch)?; peer_keys.sort_unstable(); peer_keys.dedup(); - if peer_keys != cohort_keys { - return Err(MasterCapacityPlanError::InvalidCohort); + if peer_keys != atomic_batch_keys { + return Err(MasterCapacityPlanError::InvalidAtomicBatch); } members.push(member); } Ok(members) } -fn detach_present_capacity_cohort_siblings( +fn detach_present_capacity_atomic_batch_siblings( view: &MasterKvRouterView, owner_node_id: &str, members: &[EvictionReclaimMember], @@ -861,7 +879,7 @@ fn owner_source_member_weight(backing: &OwnerReclaimBacking) -> Option { } } -enum OwnerSourceCohortPlan { +enum OwnerSourceAtomicBatchPlan { Ready { members: Vec, all_sources_present: bool, @@ -871,12 +889,12 @@ enum OwnerSourceCohortPlan { Rejected(String), } -fn plan_exact_owner_source_cohort( +fn plan_exact_owner_source_atomic_batch( view: &MasterKvRouterView, owner: &NodeID, - cohort: &OwnerSourceEvictionCohort, -) -> OwnerSourceCohortPlan { - plan_exact_owner_source_cohort_with(owner, cohort, &|key| { + atomic_batch: &OwnerSourceEvictionAtomicBatch, +) -> OwnerSourceAtomicBatchPlan { + plan_exact_owner_source_atomic_batch_with(owner, atomic_batch, &|key| { view.master_kv_router() .inner() .kv_routes @@ -885,33 +903,35 @@ fn plan_exact_owner_source_cohort( }) } -fn plan_exact_owner_source_cohort_with( +fn plan_exact_owner_source_atomic_batch_with( owner: &NodeID, - cohort: &OwnerSourceEvictionCohort, + atomic_batch: &OwnerSourceEvictionAtomicBatch, route_lookup: &dyn Fn(&str) -> Option>, -) -> OwnerSourceCohortPlan { - if cohort.members.is_empty() { - return OwnerSourceCohortPlan::Rejected("empty source-eviction cohort".to_string()); +) -> OwnerSourceAtomicBatchPlan { + if atomic_batch.members.is_empty() { + return OwnerSourceAtomicBatchPlan::Rejected( + "empty source-eviction atomic_batch".to_string(), + ); } - let mut expected_keys = cohort + let mut expected_keys = atomic_batch .members .iter() .map(|member| member.key.clone()) .collect::>(); expected_keys.sort_unstable(); expected_keys.dedup(); - if expected_keys.len() != cohort.members.len() { - return OwnerSourceCohortPlan::Rejected( - "source-eviction cohort contains duplicate keys".to_string(), + if expected_keys.len() != atomic_batch.members.len() { + return OwnerSourceAtomicBatchPlan::Rejected( + "source-eviction atomic_batch contains duplicate keys".to_string(), ); } - let mut planned = Vec::with_capacity(cohort.members.len()); + let mut planned = Vec::with_capacity(atomic_batch.members.len()); let mut absent_sources = 0usize; - for member in &cohort.members { + for member in &atomic_batch.members { let Some(weight_bytes) = owner_source_member_weight(&member.backing) else { - return OwnerSourceCohortPlan::Rejected(format!( + return OwnerSourceAtomicBatchPlan::Rejected(format!( "source backing is not an exact committed slot: key={}", member.key )); @@ -931,13 +951,13 @@ fn plan_exact_owner_source_cohort_with( continue; }; if route.put_id != member.put_id { - return OwnerSourceCohortPlan::Stale(format!( + return OwnerSourceAtomicBatchPlan::Stale(format!( "route version changed: key={} expected=({},{}) current=({},{})", member.key, member.put_id.0, member.put_id.1, route.put_id.0, route.put_id.1, )); } if route.lease_id.is_some() { - return OwnerSourceCohortPlan::Rejected(format!( + return OwnerSourceAtomicBatchPlan::Rejected(format!( "leased route is not cache-evictable: key={}", member.key )); @@ -947,7 +967,7 @@ fn plan_exact_owner_source_cohort_with( match replicas.get(owner) { Some(replica) if !replica.tomb_tag.is_tomb() => { if !replica.owner_local_indexed { - return OwnerSourceCohortPlan::Rejected(format!( + return OwnerSourceAtomicBatchPlan::Rejected(format!( "source route is not owner-local indexed: key={}", member.key )); @@ -961,45 +981,46 @@ fn plan_exact_owner_source_cohort_with( } }; if !replica_matches { - return OwnerSourceCohortPlan::Stale(format!( + return OwnerSourceAtomicBatchPlan::Stale(format!( "source backing changed: key={} put_id=({},{})", member.key, member.put_id.0, member.put_id.1 )); } - let mut route_cohort = match super::current_tp_cohort_keys(&member.key, &route, &desc) { - Ok(keys) => keys, - Err(_) => { - return OwnerSourceCohortPlan::Rejected(format!( - "master route has an invalid TP/atomic cohort: key={}", - member.key - )); - } - }; - route_cohort.sort_unstable(); - route_cohort.dedup(); - if route_cohort != expected_keys { - return OwnerSourceCohortPlan::Rejected(format!( - "owner did not submit the complete TP/atomic cohort: key={} expected_members={} route_members={}", + let mut route_atomic_batch = + match super::current_tp_atomic_batch_keys(&member.key, &route, &desc) { + Ok(keys) => keys, + Err(_) => { + return OwnerSourceAtomicBatchPlan::Rejected(format!( + "master route has an invalid TP/atomic atomic_batch: key={}", + member.key + )); + } + }; + route_atomic_batch.sort_unstable(); + route_atomic_batch.dedup(); + if route_atomic_batch != expected_keys { + return OwnerSourceAtomicBatchPlan::Rejected(format!( + "owner did not submit the complete TP/atomic atomic_batch: key={} expected_members={} route_members={}", member.key, expected_keys.len(), - route_cohort.len(), + route_atomic_batch.len(), )); } } - if absent_sources == cohort.members.len() { - OwnerSourceCohortPlan::Completed("all exact source replicas are already absent") + if absent_sources == atomic_batch.members.len() { + OwnerSourceAtomicBatchPlan::Completed("all exact source replicas are already absent") } else if absent_sources != 0 { - // This can be observed while an accepted cohort is between individual + // This can be observed while an accepted atomic_batch is between individual // route removals. The exact inflight registration below distinguishes // that case from a malformed new request. - OwnerSourceCohortPlan::Ready { + OwnerSourceAtomicBatchPlan::Ready { members: planned, all_sources_present: false, } } else { - OwnerSourceCohortPlan::Ready { + OwnerSourceAtomicBatchPlan::Ready { members: planned, all_sources_present: true, } @@ -1018,15 +1039,15 @@ pub(crate) async fn handle_batch_evict_owner_source( counters .source_evict_rpc_requests .fetch_add(1, Ordering::Relaxed); - counters.source_evict_cohorts.fetch_add( - u64::try_from(req.serialize_part.cohorts.len()).unwrap_or(u64::MAX), + counters.source_evict_atomic_batches.fetch_add( + u64::try_from(req.serialize_part.atomic_batches.len()).unwrap_or(u64::MAX), Ordering::Relaxed, ); let requested_bytes = req .serialize_part - .cohorts + .atomic_batches .iter() - .flat_map(|cohort| cohort.members.iter()) + .flat_map(|atomic_batch| atomic_batch.members.iter()) .filter_map(|member| owner_source_member_weight(&member.backing)) .map(u64::from) .fold(0u64, u64::saturating_add); @@ -1039,7 +1060,7 @@ pub(crate) async fn handle_batch_evict_owner_source( .map(|member| member.node_start_time); if current_generation != Some(req.serialize_part.owner_node_start_time) { counters.source_evict_rejected.fetch_add( - u64::try_from(req.serialize_part.cohorts.len()).unwrap_or(u64::MAX), + u64::try_from(req.serialize_part.atomic_batches.len()).unwrap_or(u64::MAX), Ordering::Relaxed, ); let err = KvError::Api(ApiError::InvalidArgument { @@ -1051,7 +1072,7 @@ pub(crate) async fn handle_batch_evict_owner_source( return MsgPack { serialize_part: BatchEvictOwnerSourceResp { operation_id, - cohorts: Vec::new(), + atomic_batches: Vec::new(), error_code: err.code(), error_json: err.to_json(), }, @@ -1059,51 +1080,56 @@ pub(crate) async fn handle_batch_evict_owner_source( }; } - let mut responses = Vec::with_capacity(req.serialize_part.cohorts.len()); - for (index, cohort) in req.serialize_part.cohorts.iter().enumerate() { - let (outcome, detail) = match plan_exact_owner_source_cohort(view, &owner, cohort) { - OwnerSourceCohortPlan::Completed(detail) => { - (OwnerSourceEvictionOutcome::Completed, detail.to_string()) - } - OwnerSourceCohortPlan::Stale(detail) => (OwnerSourceEvictionOutcome::Stale, detail), - OwnerSourceCohortPlan::Rejected(detail) => { - (OwnerSourceEvictionOutcome::RejectedNotEvictable, detail) - } - OwnerSourceCohortPlan::Ready { - members, - all_sources_present, - } => { - match view - .master_kv_router() - .enqueue_owner_capacity_eviction_cohort( - owner.as_ref().to_string(), - req.serialize_part.owner_node_start_time, - members, - all_sources_present, - ) { - EnqueueEvictionReclaimResult::Accepted => ( - OwnerSourceEvictionOutcome::Accepted, - "exact source cohort accepted by reclaim pipeline".to_string(), - ), - EnqueueEvictionReclaimResult::AlreadyInProgress => ( - OwnerSourceEvictionOutcome::AlreadyInProgress, - "same exact source cohort is already in progress".to_string(), - ), - EnqueueEvictionReclaimResult::PartialOverlap => ( - OwnerSourceEvictionOutcome::RetryableBusy, - "source cohort partially overlaps another reclaim transaction".to_string(), - ), - EnqueueEvictionReclaimResult::NotInProgress => ( - OwnerSourceEvictionOutcome::Stale, - "partially absent source cohort is not an in-progress replay".to_string(), - ), - EnqueueEvictionReclaimResult::Closed => ( - OwnerSourceEvictionOutcome::RetryableBusy, - "source reclaim actor is unavailable".to_string(), - ), + let mut responses = Vec::with_capacity(req.serialize_part.atomic_batches.len()); + for (index, atomic_batch) in req.serialize_part.atomic_batches.iter().enumerate() { + let (outcome, detail) = + match plan_exact_owner_source_atomic_batch(view, &owner, atomic_batch) { + OwnerSourceAtomicBatchPlan::Completed(detail) => { + (OwnerSourceEvictionOutcome::Completed, detail.to_string()) } - } - }; + OwnerSourceAtomicBatchPlan::Stale(detail) => { + (OwnerSourceEvictionOutcome::Stale, detail) + } + OwnerSourceAtomicBatchPlan::Rejected(detail) => { + (OwnerSourceEvictionOutcome::RejectedNotEvictable, detail) + } + OwnerSourceAtomicBatchPlan::Ready { + members, + all_sources_present, + } => { + match view + .master_kv_router() + .enqueue_owner_capacity_eviction_atomic_batch( + owner.as_ref().to_string(), + req.serialize_part.owner_node_start_time, + members, + all_sources_present, + ) { + EnqueueEvictionReclaimResult::Accepted => ( + OwnerSourceEvictionOutcome::Accepted, + "exact source atomic_batch accepted by reclaim pipeline".to_string(), + ), + EnqueueEvictionReclaimResult::AlreadyInProgress => ( + OwnerSourceEvictionOutcome::AlreadyInProgress, + "same exact source atomic_batch is already in progress".to_string(), + ), + EnqueueEvictionReclaimResult::PartialOverlap => ( + OwnerSourceEvictionOutcome::RetryableBusy, + "source atomic_batch partially overlaps another reclaim transaction" + .to_string(), + ), + EnqueueEvictionReclaimResult::NotInProgress => ( + OwnerSourceEvictionOutcome::Stale, + "partially absent source atomic_batch is not an in-progress replay" + .to_string(), + ), + EnqueueEvictionReclaimResult::Closed => ( + OwnerSourceEvictionOutcome::RetryableBusy, + "source reclaim actor is unavailable".to_string(), + ), + } + } + }; let outcome_counter = match outcome { OwnerSourceEvictionOutcome::Accepted => &counters.source_evict_accepted, OwnerSourceEvictionOutcome::AlreadyInProgress => &counters.source_evict_in_progress, @@ -1115,8 +1141,8 @@ pub(crate) async fn handle_batch_evict_owner_source( OwnerSourceEvictionOutcome::RejectedNotEvictable => &counters.source_evict_rejected, }; outcome_counter.fetch_add(1, Ordering::Relaxed); - responses.push(OwnerSourceEvictionCohortResp { - cohort_index: u32::try_from(index).unwrap_or(u32::MAX), + responses.push(OwnerSourceEvictionAtomicBatchResp { + atomic_batch_index: u32::try_from(index).unwrap_or(u32::MAX), outcome, detail, }); @@ -1125,7 +1151,7 @@ pub(crate) async fn handle_batch_evict_owner_source( MsgPack { serialize_part: BatchEvictOwnerSourceResp { operation_id, - cohorts: responses, + atomic_batches: responses, error_code: OK, error_json: String::new(), }, @@ -1135,9 +1161,25 @@ pub(crate) async fn handle_batch_evict_owner_source( struct RemovedOwnerSource { desc: NodeValueReplicaDesc, + capacity_bytes: u64, removed_last_route: bool, } +fn record_last_route_removal( + counters: &super::EvictionReclaimCounters, + removed: &RemovedOwnerSource, +) { + if !removed.removed_last_route { + return; + } + counters + .last_route_removed_members + .fetch_add(1, Ordering::Relaxed); + counters + .last_route_removed_bytes + .fetch_add(removed.capacity_bytes, Ordering::Relaxed); +} + fn remove_exact_owner_source_route( routes: &dashmap::DashMap>, owner: &NodeID, @@ -1155,13 +1197,14 @@ fn remove_exact_owner_source_route( if !reclaim_backing_matches(replica, &item.backing) { return None; } + let capacity_bytes = replica.backing.capacity_bytes(); let desc = NodeValueReplicaDesc { - weight_bytes: u32::try_from(replica.backing.capacity_bytes()).unwrap_or(u32::MAX), + weight_bytes: u32::try_from(capacity_bytes).unwrap_or(u32::MAX), put_id: route.put_id, }; - replicas.remove(owner).map(|_| desc) + replicas.remove(owner).map(|_| (desc, capacity_bytes)) }; - let removed_desc = removed_desc?; + let (removed_desc, capacity_bytes) = removed_desc?; let removed_last_route = if route.nodes_replicas.read().is_empty() { routes @@ -1176,6 +1219,7 @@ fn remove_exact_owner_source_route( }; Some(RemovedOwnerSource { desc: removed_desc, + capacity_bytes, removed_last_route, }) } @@ -1196,6 +1240,10 @@ fn remove_reclaimed_replica( let removed = remove_exact_owner_source_route(&view.master_kv_router().inner().kv_routes, owner, item); if let Some(removed) = removed { + let counters = view + .master_kv_router() + .eviction_reclaim_counters(owner.as_ref()); + record_last_route_removal(counters.as_ref(), &removed); if removed.removed_last_route && view.master_kv_router().prefix_index_enabled() { let view_task = view.clone(); let key = item.key.clone(); @@ -1518,7 +1566,7 @@ fn clear_master_fences(view: &MasterKvRouterView, items: &[OwnerReclaimItem]) { } } -fn try_install_cohort_master_fences( +fn try_install_atomic_batch_master_fences( activity: &super::MasterKeyActivityTable, items: &[OwnerReclaimItem], ) -> Result<(), (usize, super::MasterKeyActivitySnapshot)> { @@ -1537,14 +1585,14 @@ fn try_install_cohort_master_fences( Ok(()) } -/// Reclaim one TP/atomic cohort as a transaction. +/// Reclaim one TP/atomic atomic_batch as a transaction. /// /// Before the first owner Commit, any failed fence/validation/Prepare rolls -/// the entire cohort back. Once a response (including an Abort response) +/// the entire atomic_batch back. Once a response (including an Abort response) /// proves that any member was committed, rollback is impossible; the same /// transaction retains every master fence and keeps driving the remaining -/// members until all are committed, then removes/finalizes the whole cohort. -async fn reclaim_cohort_items( +/// members until all are committed, then removes/finalizes the whole atomic_batch. +async fn reclaim_atomic_batch_items( view: &MasterKvRouterView, owner: &NodeID, items: Vec, @@ -1555,14 +1603,15 @@ async fn reclaim_cohort_items( let counters = view .master_kv_router() .eviction_reclaim_counters(owner.as_ref()); - if let Err((failed_index, activity)) = - try_install_cohort_master_fences(&view.master_kv_router().inner().key_activity, &items) - { + if let Err((failed_index, activity)) = try_install_atomic_batch_master_fences( + &view.master_kv_router().inner().key_activity, + &items, + ) { counters .master_activity_deferred .fetch_add(1, Ordering::Relaxed); tracing::trace!( - "cohort reclaim deferred by master activity: owner={} key={} puts={} gets={} replicas={} reclaim_installed={}", + "atomic_batch reclaim deferred by master activity: owner={} key={} puts={} gets={} replicas={} reclaim_installed={}", owner, items[failed_index].key, activity.puts, @@ -1601,7 +1650,7 @@ async fn reclaim_cohort_items( } if !master_only.is_empty() || owner_coordinated.len() != fenced.len() { tracing::error!( - "BUG: one reclaim cohort mixed master-only and owner-coordinated backings: owner={} cohort={} master_only={} owner_coordinated={}", + "BUG: one reclaim atomic_batch mixed master-only and owner-coordinated backings: owner={} atomic_batch={} master_only={} owner_coordinated={}", owner, fenced.len(), master_only.len(), @@ -1713,7 +1762,7 @@ async fn reclaim_cohort_items( if rounds == 8 && !committed_keys.is_empty() { tracing::warn!( - "owner cohort reclaim is rolling forward after partial/uncertain commit: owner={} cohort={} committed={}", + "owner atomic_batch reclaim is rolling forward after partial/uncertain commit: owner={} atomic_batch={} committed={}", owner, owner_coordinated.len(), committed_keys.len(), @@ -2103,7 +2152,7 @@ pub(crate) fn spawn_eviction_reclaim_actor( OwnerReclaimReason::OwnerCapacityEviction, ), EvictionReclaimOrigin::MasterAllocationCapacity => { - let members = match plan_master_allocation_capacity_cohort( + let members = match plan_master_allocation_capacity_atomic_batch( &view_task, &request, ) { @@ -2134,7 +2183,7 @@ pub(crate) fn spawn_eviction_reclaim_actor( counters.route_changed.fetch_add(1, Ordering::Relaxed); continue; } - Err(MasterCapacityPlanError::InvalidCohort) => { + Err(MasterCapacityPlanError::InvalidAtomicBatch) => { retry_requests.push(request); continue; } @@ -2161,7 +2210,7 @@ pub(crate) fn spawn_eviction_reclaim_actor( .owner_cache_operation_locks .get_lock(owner_node_id.clone()); let owner_cache_guard = owner_cache_lock.lock().await; - let detach_result = detach_present_capacity_cohort_siblings( + let detach_result = detach_present_capacity_atomic_batch_siblings( &view_task, &owner_node_id, &members, @@ -2257,7 +2306,7 @@ pub(crate) fn spawn_eviction_reclaim_actor( }) .collect::>>(); if let Some(items) = items { - let _ = reclaim_cohort_items(&view_task, &owner, items).await; + let _ = reclaim_atomic_batch_items(&view_task, &owner, items).await; } for accounting_request in accounting_requests.drain(..) { if request_is_current(&view_task, &accounting_request) { @@ -2276,7 +2325,7 @@ pub(crate) fn spawn_eviction_reclaim_actor( let retry_count = retry_requests.len(); spawn_eviction_reclaim_retry(view_task.clone(), retry_requests); tracing::trace!( - "safe cohort eviction reclaim batch completed: owner={} retry_deferred={}", + "safe atomic_batch eviction reclaim batch completed: owner={} retry_deferred={}", owner_node_id, retry_count, ); diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/route_maintenance.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/route_maintenance.rs index 6ebd982..25edd27 100644 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/route_maintenance.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/route_maintenance.rs @@ -190,7 +190,7 @@ pub(super) async fn apply_post_route_maintenance_batch( continue; } tracing::debug!("Inserting key: {:?} into cache", key); - cache.insert(key.clone(), desc.clone()); + super::insert_master_cache_entry(cache.as_ref(), key.clone(), desc.clone()); tracing::debug!( "Inserted key: {:?} into cache, current cache size: {}", key, @@ -198,7 +198,7 @@ pub(super) async fn apply_post_route_maintenance_batch( ); } // Do not search Moka for a recoverable victim here. CPU append Done - // already carries the exact source key/cohort and performs a validated + // already carries the exact source key/atomic_batch and performs a validated // point demotion. Local-reserve Free/Prepared/Pending/Committed state is // the physical capacity authority while that writeback is in flight. } @@ -228,7 +228,7 @@ pub(super) async fn apply_post_route_maintenance_batch( ) { continue; } - tier1_cache.insert(key, desc); + super::insert_master_cache_entry(tier1_cache.as_ref(), key, desc); } } } diff --git a/fluxon_rs/fluxon_kv/src/memholder/mod.rs b/fluxon_rs/fluxon_kv/src/memholder/mod.rs index 7221f2d..f44f7c3 100755 --- a/fluxon_rs/fluxon_kv/src/memholder/mod.rs +++ b/fluxon_rs/fluxon_kv/src/memholder/mod.rs @@ -23,6 +23,7 @@ use crate::client_kv_api::ClientKvApiView; use crate::{cluster_manager::NodeID, external_client_api::ExternalClientApiView}; use bitcode::{Decode, Encode}; +use fluxon_util::pin_aware_moka::PinGuard; #[derive(Clone, Debug)] pub enum MemoryInfoDropAction { @@ -91,6 +92,7 @@ pub struct UserMemHolder { pub memory_info: Arc, pub refcount: Arc, expose_kind: UserMemHolderExposeKind, + _owner_hot_pin: Option, } impl UserMemHolder { pub fn holder_id(&self) -> u64 { @@ -117,6 +119,14 @@ impl UserMemHolder { refcount: Arc, expose_kind: UserMemHolderExposeKind, ) -> Self { + let owner_hot_pin = match expose_kind { + UserMemHolderExposeKind::SegPtr => refcount + .view + .client_kv_api() + .inner() + .owner_hot_pin_memory_info(&memory_info), + UserMemHolderExposeKind::OwnedCopy => None, + }; tracing::debug!( "Creating UserMemHolder for key '{}', _holder_id_ {}, expose_kind={:?}.", memory_info.key, @@ -127,6 +137,7 @@ impl UserMemHolder { memory_info, refcount, expose_kind, + _owner_hot_pin: owner_hot_pin, } } pub fn memory_info(&self) -> Arc { diff --git a/fluxon_rs/fluxon_util/src/lib.rs b/fluxon_rs/fluxon_util/src/lib.rs index cde6dc7..8d13b8e 100644 --- a/fluxon_rs/fluxon_util/src/lib.rs +++ b/fluxon_rs/fluxon_util/src/lib.rs @@ -7,6 +7,7 @@ pub mod hash; pub mod init_dag_compiler; pub mod map_lock; pub mod merge_recent_async_notifies; +pub mod pin_aware_moka; pub mod prefix_scan; pub mod prom_remote_write; pub mod scoped_future_set; diff --git a/fluxon_rs/fluxon_util/src/pin_aware_moka.rs b/fluxon_rs/fluxon_util/src/pin_aware_moka.rs new file mode 100644 index 0000000..b518fac --- /dev/null +++ b/fluxon_rs/fluxon_util/src/pin_aware_moka.rs @@ -0,0 +1,671 @@ +//! Explicit pin management around Moka without changing Moka's entry key. +//! +//! The first pin removes one entry from Moka. The final unpin inserts the same +//! generation again. A pin alias can be reserved before its entry is inserted. + +use moka::notification::RemovalCause; +use moka::ops::compute::{CompResult, Op}; +use moka::sync::Cache; +use parking_lot::Mutex; +use std::collections::{HashMap, HashSet}; +use std::hash::Hash; +use std::sync::{Arc, Weak}; + +type EvictionListener = dyn Fn(Arc, Value, RemovalCause) + Send + Sync + 'static; +type Weigher = dyn Fn(&Key, &Value) -> u32 + Send + Sync + 'static; + +/// Builder for [`PinAwareMoka`]. +pub struct PinAwareMokaBuilder { + max_capacity: u64, + weigher: Arc>, + eviction_listener: Option>>, + _pin_alias: std::marker::PhantomData, +} + +impl PinAwareMokaBuilder { + fn new(max_capacity: u64) -> Self { + Self { + max_capacity, + weigher: Arc::new(|_, _| 1), + eviction_listener: None, + _pin_alias: std::marker::PhantomData, + } + } + + pub fn weigher( + mut self, + weigher: impl Fn(&Key, &Value) -> u32 + Send + Sync + 'static, + ) -> Self { + self.weigher = Arc::new(weigher); + self + } + + /// Set the listener for Moka removals. + /// + /// Pin/unpin removals are internal and are not sent to this listener. + pub fn eviction_listener( + mut self, + listener: impl Fn(Arc, Value, RemovalCause) + Send + Sync + 'static, + ) -> Self { + self.eviction_listener = Some(Arc::new(listener)); + self + } +} + +impl PinAwareMokaBuilder +where + Key: Clone + Eq + Hash + Send + Sync + 'static, + PinAlias: Clone + Eq + Hash + Send + Sync + 'static, + Value: Clone + Send + Sync + 'static, +{ + pub fn build(self) -> PinAwareMoka { + assert!( + self.max_capacity > 0, + "pin-aware Moka capacity must be positive" + ); + let weigher = self.weigher; + let eviction_listener = self.eviction_listener; + let inner = Arc::new_cyclic(|weak: &Weak>| { + let listener_inner = weak.clone(); + let cache = Cache::builder() + .max_capacity(self.max_capacity) + .weigher(move |_key: &Key, entry: &MokaEntry| entry.weight) + .eviction_listener(move |key, entry, cause| { + if let Some(inner) = listener_inner.upgrade() { + inner.handle_moka_removal(key, entry, cause); + } + }) + .build(); + Inner { + cache, + state: Mutex::new(State::default()), + mutation: Mutex::new(()), + weigher, + eviction_listener, + } + }); + PinAwareMoka { inner } + } +} + +/// A key-preserving Moka wrapper with explicit pin aliases. +pub struct PinAwareMoka { + inner: Arc>, +} + +impl Clone for PinAwareMoka { + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + } + } +} + +#[derive(Clone)] +struct MokaEntry { + generation: u64, + value: Value, + weight: u32, + _pin_alias: std::marker::PhantomData, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum Residency { + InMoka, + Pinned, + Selected, +} + +struct EntryState { + generation: u64, + pin_aliases: Arc<[PinAlias]>, + value: Value, + weight: u32, + pin_count: usize, + residency: Residency, +} + +enum PinLease { + Pending(PinAlias), + Assigned { key: Key, generation: u64 }, +} + +struct State { + next_generation: u64, + next_pin_lease: u64, + entries: HashMap>, + aliases: HashMap, + pin_leases: HashMap>, + pending_pins: HashMap>, +} + +impl Default for State { + fn default() -> Self { + Self { + next_generation: 1, + next_pin_lease: 1, + entries: HashMap::new(), + aliases: HashMap::new(), + pin_leases: HashMap::new(), + pending_pins: HashMap::new(), + } + } +} + +struct Inner { + cache: Cache>, + state: Mutex>, + // State transitions and Moka mutations are serialized, but the state lock + // is always released before calling Moka and its synchronous listener. + mutation: Mutex<()>, + weigher: Arc>, + eviction_listener: Option>>, +} + +impl Inner +where + Key: Clone + Eq + Hash + Send + Sync + 'static, + PinAlias: Clone + Eq + Hash + Send + Sync + 'static, + Value: Clone + Send + Sync + 'static, +{ + fn remove_moka_generation(&self, key: &Key, generation: u64) -> bool { + matches!( + self.cache.entry(key.clone()).and_compute_with(|current| { + if current + .as_ref() + .is_some_and(|entry| entry.value().generation == generation) + { + Op::Remove + } else { + Op::Nop + } + }), + CompResult::Removed(_) + ) + } + + fn handle_moka_removal( + &self, + key: Arc, + entry: MokaEntry, + cause: RemovalCause, + ) { + if cause != RemovalCause::Size { + return; + } + let selected = { + let mut state = self.state.lock(); + let Some(current) = state.entries.get_mut(key.as_ref()) else { + return; + }; + if current.generation != entry.generation || current.residency != Residency::InMoka { + return; + } + debug_assert_eq!(current.pin_count, 0); + current.residency = Residency::Selected; + true + }; + if selected && let Some(listener) = self.eviction_listener.as_ref() { + listener(key, entry.value, cause); + } + } + + fn release_pin(self: &Arc, lease_id: u64) { + let _mutation = self.mutation.lock(); + let entry_to_admit = { + let mut state = self.state.lock(); + let Some(lease) = state.pin_leases.remove(&lease_id) else { + return; + }; + match lease { + PinLease::Pending(alias) => { + if let Some(leases) = state.pending_pins.get_mut(&alias) { + leases.remove(&lease_id); + if leases.is_empty() { + state.pending_pins.remove(&alias); + } + } + None + } + PinLease::Assigned { key, generation } => { + let Some(entry) = state.entries.get_mut(&key) else { + return; + }; + if entry.generation != generation { + return; + } + entry.pin_count = entry + .pin_count + .checked_sub(1) + .expect("pin-aware Moka pin count underflow"); + if entry.pin_count == 0 && entry.residency == Residency::Pinned { + entry.residency = Residency::InMoka; + Some(( + key, + MokaEntry { + generation, + value: entry.value.clone(), + weight: entry.weight, + _pin_alias: std::marker::PhantomData, + }, + )) + } else { + None + } + } + } + }; + if let Some((key, entry)) = entry_to_admit { + self.cache.insert(key, entry); + } + } +} + +impl PinAwareMoka +where + Key: Clone + Eq + Hash + Send + Sync + 'static, + PinAlias: Clone + Eq + Hash + Send + Sync + 'static, + Value: Clone + Send + Sync + 'static, +{ + pub fn builder(max_capacity: u64) -> PinAwareMokaBuilder { + PinAwareMokaBuilder::new(max_capacity) + } + + /// Insert one normal Moka entry with one or more explicit pin identities. + pub fn insert( + &self, + key: Key, + pin_aliases: impl IntoIterator, + value: Value, + ) -> u64 { + let pin_aliases = pin_aliases.into_iter().collect::>(); + assert!( + !pin_aliases.is_empty(), + "a pin-aware Moka entry must have at least one pin alias" + ); + assert_eq!( + pin_aliases.iter().collect::>().len(), + pin_aliases.len(), + "a pin-aware Moka entry cannot contain duplicate pin aliases" + ); + let weight = (self.inner.weigher)(&key, &value); + let pin_aliases: Arc<[PinAlias]> = pin_aliases.into(); + let _mutation = self.inner.mutation.lock(); + let (generation, admit, displaced) = { + let mut state = self.inner.state.lock(); + let generation = state.next_generation; + state.next_generation = state + .next_generation + .checked_add(1) + .expect("pin-aware Moka generation space exhausted"); + + let mut displaced_keys = HashSet::new(); + if state.entries.contains_key(&key) { + displaced_keys.insert(key.clone()); + } + for alias in pin_aliases.iter() { + if let Some((old_key, _)) = state.aliases.get(alias) { + displaced_keys.insert(old_key.clone()); + } + } + let mut displaced = Vec::new(); + for old_key in displaced_keys { + if let Some(old) = state.entries.remove(&old_key) { + for alias in old.pin_aliases.iter() { + if state.aliases.get(alias) == Some(&(old_key.clone(), old.generation)) { + state.aliases.remove(alias); + } + } + displaced.push((old_key, old.generation)); + } + } + + let mut pin_count = 0usize; + for alias in pin_aliases.iter() { + let pending = state.pending_pins.remove(alias).unwrap_or_default(); + pin_count = pin_count + .checked_add(pending.len()) + .expect("pin-aware Moka pin count overflow"); + for lease_id in pending { + *state + .pin_leases + .get_mut(&lease_id) + .expect("pending pin lease must exist") = PinLease::Assigned { + key: key.clone(), + generation, + }; + } + state + .aliases + .insert(alias.clone(), (key.clone(), generation)); + } + let residency = if pin_count == 0 { + Residency::InMoka + } else { + Residency::Pinned + }; + state.entries.insert( + key.clone(), + EntryState { + generation, + pin_aliases: pin_aliases.clone(), + value: value.clone(), + weight, + pin_count, + residency, + }, + ); + let admit = (residency == Residency::InMoka).then(|| MokaEntry { + generation, + value, + weight, + _pin_alias: std::marker::PhantomData, + }); + (generation, admit, displaced) + }; + for (old_key, old_generation) in displaced { + self.inner.remove_moka_generation(&old_key, old_generation); + } + if let Some(entry) = admit { + self.inner.cache.insert(key, entry); + } + generation + } + + /// Pin the entry identified by `alias`, or reserve a pin before insertion. + /// + /// Returns `None` when Moka selection already owns that entry. + pub fn try_pin_alias(&self, alias: PinAlias) -> Option { + self.try_pin_alias_if(alias, |_| true) + } + + /// Pin only if an existing value satisfies `predicate`. + pub fn try_pin_alias_if( + &self, + alias: PinAlias, + predicate: impl FnOnce(&Value) -> bool, + ) -> Option { + let _mutation = self.inner.mutation.lock(); + let mut state = self.inner.state.lock(); + let lease_id = state.next_pin_lease; + state.next_pin_lease = state + .next_pin_lease + .checked_add(1) + .expect("pin-aware Moka pin lease space exhausted"); + let mut remove = None; + if let Some((key, generation)) = state.aliases.get(&alias).cloned() { + let entry = state + .entries + .get_mut(&key) + .expect("pin alias must reference a live entry"); + assert_eq!(entry.generation, generation); + if !predicate(&entry.value) || entry.residency == Residency::Selected { + return None; + } + entry.pin_count = entry + .pin_count + .checked_add(1) + .expect("pin-aware Moka pin count overflow"); + if entry.residency == Residency::InMoka { + entry.residency = Residency::Pinned; + remove = Some((key.clone(), generation)); + } + state + .pin_leases + .insert(lease_id, PinLease::Assigned { key, generation }); + } else { + state + .pending_pins + .entry(alias.clone()) + .or_default() + .insert(lease_id); + state.pin_leases.insert(lease_id, PinLease::Pending(alias)); + } + drop(state); + if let Some((key, generation)) = remove { + self.inner.remove_moka_generation(&key, generation); + } + Some(PinGuard { + _lease: Arc::new(PinGuardLease { + release: Box::new({ + let inner = Arc::downgrade(&self.inner); + move || { + if let Some(inner) = inner.upgrade() { + inner.release_pin(lease_id); + } + } + }), + }), + }) + } + + /// Read and touch an unselected entry. Pinned entries remain readable here. + pub fn get(&self, key: &Key) -> Option { + let _mutation = self.inner.mutation.lock(); + let (generation, value, in_moka) = { + let state = self.inner.state.lock(); + let entry = state.entries.get(key)?; + if entry.residency == Residency::Selected { + return None; + } + ( + entry.generation, + entry.value.clone(), + entry.residency == Residency::InMoka, + ) + }; + if in_moka { + let _ = self + .inner + .cache + .get(key) + .filter(|entry| entry.generation == generation); + } + Some(value) + } + + pub fn contains_key(&self, key: &Key) -> bool { + self.inner + .state + .lock() + .entries + .get(key) + .is_some_and(|entry| entry.residency != Residency::Selected) + } + + /// Remove an entry generation from both the wrapper and Moka. + pub fn invalidate(&self, key: &Key) -> bool { + self.invalidate_if(key, |_| true) + } + + pub fn invalidate_if(&self, key: &Key, predicate: impl FnOnce(&Value) -> bool) -> bool { + self.take_if(key, predicate).is_some() + } + + pub fn take_if(&self, key: &Key, predicate: impl FnOnce(&Value) -> bool) -> Option { + let _mutation = self.inner.mutation.lock(); + let removed = { + let mut state = self.inner.state.lock(); + let Some(entry) = state.entries.get(key) else { + return None; + }; + if !predicate(&entry.value) { + return None; + } + let entry = state + .entries + .remove(key) + .expect("validated pin-aware entry disappeared under lock"); + for alias in entry.pin_aliases.iter() { + if state.aliases.get(alias) == Some(&(key.clone(), entry.generation)) { + state.aliases.remove(alias); + } + } + entry + }; + self.inner.remove_moka_generation(key, removed.generation); + Some(removed.value) + } + + /// Pop LRU entries until at least `weight_to_evict` weight is selected. + pub fn evict_some(&self, weight_to_evict: u64) -> u64 { + let _mutation = self.inner.mutation.lock(); + self.inner.cache.evict_some(weight_to_evict) + } + + pub fn run_pending_tasks(&self) { + let _mutation = self.inner.mutation.lock(); + self.inner.cache.run_pending_tasks(); + } + + pub fn set_max_capacity(&self, capacity: u64) -> Result<(), moka::CapacityError> { + self.inner.cache.set_max_capacity(capacity) + } + + pub fn max_capacity(&self) -> Option { + self.inner.cache.policy().max_capacity() + } + + pub fn weighted_size(&self) -> u64 { + self.inner.cache.weighted_size() + } + + pub fn entry_count(&self) -> u64 { + self.inner.cache.entry_count() + } +} + +/// A cloneable pin. The final clone performs the unpin transition. +#[derive(Clone)] +pub struct PinGuard { + _lease: Arc, +} + +struct PinGuardLease { + release: Box, +} + +impl Drop for PinGuardLease { + fn drop(&mut self) { + (self.release)(); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::sync::Barrier; + use std::thread; + + type TestCache = PinAwareMoka; + + fn cache(capacity: u64, evicted: Arc>>) -> TestCache { + TestCache::builder(capacity) + .weigher(|_, weight| *weight) + .eviction_listener(move |key, _, cause| { + assert_eq!(cause, RemovalCause::Size); + evicted.lock().push((*key).clone()); + }) + .build() + } + + fn insert(cache: &TestCache, key: &str, alias: &str, weight: u32) { + cache.insert(key.to_string(), [alias.to_string()], weight); + cache.run_pending_tasks(); + } + + #[test] + fn first_pin_removes_and_final_unpin_readmits_one_key() { + let cache = cache(100, Arc::new(Mutex::new(Vec::new()))); + insert(&cache, "key", "alias", 10); + let first = cache.try_pin_alias("alias".to_string()).unwrap(); + let second = cache.try_pin_alias("alias".to_string()).unwrap(); + cache.run_pending_tasks(); + assert_eq!(cache.entry_count(), 0); + assert_eq!(cache.get(&"key".to_string()), Some(10)); + + drop(first); + cache.run_pending_tasks(); + assert_eq!(cache.entry_count(), 0); + drop(second); + cache.run_pending_tasks(); + assert_eq!(cache.entry_count(), 1); + } + + #[test] + fn pin_before_insert_defers_moka_admission() { + let cache = cache(100, Arc::new(Mutex::new(Vec::new()))); + let pin = cache.try_pin_alias("alias".to_string()).unwrap(); + insert(&cache, "key", "alias", 10); + assert_eq!(cache.entry_count(), 0); + drop(pin); + cache.run_pending_tasks(); + assert_eq!(cache.entry_count(), 1); + } + + #[test] + fn pin_and_evict_race_has_one_winner() { + for iteration in 0..100 { + let evicted = Arc::new(Mutex::new(Vec::new())); + let cache = cache(100, evicted.clone()); + insert(&cache, "key", "alias", 10); + let barrier = Arc::new(Barrier::new(3)); + let pin_cache = cache.clone(); + let pin_barrier = barrier.clone(); + let pin = thread::spawn(move || { + pin_barrier.wait(); + pin_cache.try_pin_alias("alias".to_string()) + }); + let pop_cache = cache.clone(); + let pop_barrier = barrier.clone(); + let pop = thread::spawn(move || { + pop_barrier.wait(); + pop_cache.evict_some(1) + }); + barrier.wait(); + let pin = pin.join().unwrap(); + let selected_weight = pop.join().unwrap(); + assert_ne!(pin.is_some(), selected_weight != 0, "iteration {iteration}"); + assert_eq!(evicted.lock().len(), usize::from(selected_weight != 0)); + drop(pin); + } + } + + #[test] + fn stale_guard_does_not_readmit_a_new_generation() { + let cache = cache(100, Arc::new(Mutex::new(Vec::new()))); + let stale = cache.try_pin_alias("old-alias".to_string()).unwrap(); + insert(&cache, "key", "old-alias", 10); + insert(&cache, "key", "new-alias", 20); + drop(stale); + cache.run_pending_tasks(); + assert_eq!(cache.get(&"key".to_string()), Some(20)); + assert_eq!(cache.entry_count(), 1); + } + + #[test] + fn selected_entry_rejects_pin_until_restore_or_invalidate() { + let evicted = Arc::new(Mutex::new(Vec::new())); + let cache = cache(100, evicted.clone()); + insert(&cache, "key", "alias", 10); + assert_eq!(cache.evict_some(1), 10); + assert_eq!(&*evicted.lock(), &["key"]); + assert!(cache.try_pin_alias("alias".to_string()).is_none()); + + insert(&cache, "key", "alias", 10); + let pin = cache.try_pin_alias("alias".to_string()).unwrap(); + drop(pin); + assert!(cache.invalidate(&"key".to_string())); + assert!(!cache.contains_key(&"key".to_string())); + } + + #[test] + fn weighted_pop_keeps_key_granularity_and_can_overshoot() { + let evicted = Arc::new(Mutex::new(Vec::new())); + let cache = cache(100, evicted.clone()); + insert(&cache, "first", "a", 12); + insert(&cache, "second", "b", 7); + assert_eq!(cache.evict_some(13), 19); + assert_eq!(evicted.lock().len(), 2); + } +} From aafac1111007b2c7ac8d2fb13358c63e1dca200b Mon Sep 17 00:00:00 2001 From: zTz01 <1773266173@qq.com> Date: Sun, 19 Jul 2026 10:11:03 +0800 Subject: [PATCH 06/10] back 7.3qps --- .../src/client_kv_api/external_api.rs | 94 +- fluxon_rs/fluxon_kv/src/client_kv_api/get.rs | 8 +- .../client_kv_api/local_reserve_rebalance.rs | 32 +- fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs | 1060 +++++++---------- fluxon_rs/fluxon_kv/src/client_kv_api/put.rs | 412 +++---- .../fluxon_kv/src/client_kv_api/reclaim.rs | 40 +- .../fluxon_kv/src/master_kv_router/mod.rs | 274 +---- .../src/master_kv_router/msg_pack.rs | 18 +- .../fluxon_kv/src/master_kv_router/reclaim.rs | 779 +++++------- 9 files changed, 1168 insertions(+), 1549 deletions(-) diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs index 015d41c..09f5e0f 100755 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs @@ -17,7 +17,8 @@ use crate::client_kv_api::msg_pack::{ use crate::client_kv_api::{ self, ExternalGetKeyInterest, ExternalGetKeySharedOp, ExternalGetKeySharedPhase, ExternalGetStartEntry, ExternalGetStartOwnerItem, ExternalGetStartPrefixResult, - ExternalGetStartSharedItemResult, ExternalGetStartTransferOutput, ExternalPendingPutCtx, + ExternalGetStartSharedItemResult, ExternalGetStartTransferOutput, + ExternalLocalFirstPutKeyReservation, ExternalPendingPutCtx, ExternalPutKeyOutcome, OwnerLocalPublishItem, OwnerLocalPublishJob, OwnerLocalReserveSlotLease, OwnerLocalReserveSlotRef, ReplicaTaskTarget, }; @@ -1132,6 +1133,7 @@ mod external_get_start_batch_tests { OwnerKeyControlState { local_puts: 0, external_pending_puts: 0, + external_put: None, source_eviction_selection: None, reclaim: None, external_get: Some(old.clone()), @@ -1160,6 +1162,7 @@ mod external_get_start_batch_tests { OwnerKeyControlState { local_puts: 0, external_pending_puts: 0, + external_put: None, source_eviction_selection: None, reclaim: None, external_get: Some(op.clone()), @@ -2909,29 +2912,82 @@ impl HandlerForExternalClient for ClientKvApi { })); } - let mut pending_fences = Vec::with_capacity(req.items.len()); - for item in &req.items { - let pending_fence = match inner.reserve_external_local_first_put_key( - &item.key, - item.reject_if_inflight_same_key, - item.reject_if_exist_same_key, - ) { - Ok(pending_fence) => pending_fence, - Err(err) => { - let items = req - .items - .iter() - .map(|_| external_local_first_error_item(&err)) - .collect(); + let pending_fences = loop { + let mut pending_fences = Vec::with_capacity(req.items.len()); + let mut wait_for = None; + for item in &req.items { + match inner.reserve_external_local_first_put_key( + &item.key, + item.reject_if_inflight_same_key, + item.reject_if_exist_same_key, + ) { + Ok(ExternalLocalFirstPutKeyReservation::Leader(pending_fence)) => { + pending_fences.push(pending_fence); + } + Ok(ExternalLocalFirstPutKeyReservation::Wait(op)) => { + if atomic_group_lens.len() != 1 { + let err = KvError::Api(ApiError::KeyBeingWritten { + key: item.key.clone(), + }); + return Ok(ExternalBatchPutStartResp { + items: req + .items + .iter() + .map(|_| external_local_first_error_item(&err)) + .collect(), + error_code: OK, + error_json: String::new(), + }); + } + wait_for = Some((item.key.clone(), op)); + break; + } + Err(err) => { + let items = req + .items + .iter() + .map(|_| external_local_first_error_item(&err)) + .collect(); + return Ok(ExternalBatchPutStartResp { + items, + error_code: OK, + error_json: String::new(), + }); + } + } + } + let Some((joined_key, op)) = wait_for else { + break pending_fences; + }; + + // Never retain a partial atomic_batch while waiting for another + // key. Two overlapping requests with different key order must not + // each hold one leader fence and wait forever on the other. + drop(pending_fences); + match op.wait().await { + ExternalPutKeyOutcome::Succeeded => { + tracing::info!( + joined_key, + items = req.items.len(), + "external local-first Put reused an inflight leader result" + ); + let err = KvError::Api(ApiError::KeyAlreadyExists { key: joined_key }); return Ok(ExternalBatchPutStartResp { - items, + items: req + .items + .iter() + .map(|_| external_local_first_error_item(&err)) + .collect(), error_code: OK, error_json: String::new(), }); } - }; - pending_fences.push(pending_fence); - } + ExternalPutKeyOutcome::Failed => continue, + ExternalPutKeyOutcome::InFlight => { + unreachable!("shared Put wait must return a terminal outcome") + } + } + }; // Finish every fallible, purely logical derivation before claiming // physical slots. The per-key fences above are RAII-owned, so any diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs index 8cfbf99..57c7164 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs @@ -620,10 +620,10 @@ impl ClientKvApiInner { results[pending.idx] = Some(Ok(Some((user_mem_holder, Some(get_info))))); } - // All members are in get_cached_info before any hot admission can evict one of them. - // This keeps atomic/TP atomic_batch write-back decisions complete. - for (key, put_id, memory_info, atomic_group) in local_hot_admissions { - self.owner_hot_track_committed(&key, put_id, &memory_info, atomic_group.as_ref()); + // Publish every local index before Moka admission starts selecting + // individual capacity victims. + for (key, put_id, memory_info, _atomic_group) in local_hot_admissions { + self.owner_hot_track_committed(&key, put_id, &memory_info); } Ok(results diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/local_reserve_rebalance.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/local_reserve_rebalance.rs index a9db5e5..5fec74f 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/local_reserve_rebalance.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/local_reserve_rebalance.rs @@ -1,5 +1,6 @@ use super::{ - ClientKvApiInner, ClientKvApiView, OwnerLocalReserveClassState, OwnerLocalReservePoolState, + ClientKvApiInner, ClientKvApiView, OwnerHotEvictionDispatch, OwnerLocalReserveClassState, + OwnerLocalReservePoolState, }; use crate::OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES; use crate::master_kv_router::msg_pack::ReserveLocalGrantOutcome; @@ -107,7 +108,7 @@ fn owner_slot_pressure_request_bytes( fn owner_slot_pressure_projected_reclaim_bytes(inner: &ClientKvApiInner) -> u64 { // Candidate debt starts in Moka's synchronous eviction listener. A - // candidate that is incomplete, pinned, or waiting in the retry queue has + // candidate that is stale, pinned, or waiting in the retry queue has // no installed owner fence and cannot release a slot. Only exact selected // source debt is valid projected reclaim credit. inner @@ -533,7 +534,7 @@ mod tests { } #[test] - fn retry_candidate_debt_is_not_projected_reclaim_credit() { + fn pre_fence_candidate_debt_is_not_projected_reclaim_credit() { let snapshot = RebalanceClassSnapshot { slot_size: 1024 * 1024, slots_per_grant: 4, @@ -776,6 +777,17 @@ pub fn spawn_owner_slot_pressure_actor(view: ClientKvApiView) { let Some(cache) = inner.owner_hot_cache.clone() else { continue; }; + if inner + .owner_hot_eviction_tx + .send(OwnerHotEvictionDispatch::BeginPressure { requested_bytes }) + .is_err() + { + tracing::warn!( + requested_bytes, + "owner slot pressure dispatcher is closed before Moka selection" + ); + return; + } let selected_bytes = match limit_thirdparty::tokio::task::spawn_blocking(move || { cache.evict_some(requested_bytes) }) @@ -788,9 +800,21 @@ pub fn spawn_owner_slot_pressure_actor(view: ClientKvApiView) { err = ?err, "owner slot pressure Moka selection task failed" ); - continue; + 0 } }; + if inner + .owner_hot_eviction_tx + .send(OwnerHotEvictionDispatch::EndPressure { selected_bytes }) + .is_err() + { + tracing::warn!( + requested_bytes, + selected_bytes, + "owner slot pressure dispatcher closed after Moka selection" + ); + return; + } last_kick_at = Some(Instant::now()); tracing::debug!( requested_bytes, diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs index efb4dde..fe309a7 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs @@ -49,6 +49,7 @@ use crate::{ }, rpcresp_kvresult_convert::msg_and_error::{ApiError, ErrorCode, KvError, KvResult}, }; +use ::tokio::sync::watch; use async_trait::async_trait; use dashmap::{DashMap, mapref::entry::Entry as DashMapEntry}; use fluxon_framework::{LogicalModule, define_module}; @@ -120,9 +121,8 @@ pub struct OwnerRuntimeObserveSnapshot { pub hot_eviction_skipped_stale: u64, pub hot_eviction_skipped_reclaim: u64, pub hot_eviction_skipped_active_holders: u64, - pub hot_group_registry_entries: u64, - pub hot_group_trigger_duplicates: u64, - pub hot_group_trigger_incomplete: u64, + pub hot_victim_duplicates: u64, + pub hot_victim_invalid_backing: u64, pub grouped_put_done_batches: u64, pub grouped_put_done_items: u64, pub legacy_put_done_batches: u64, @@ -1260,16 +1260,6 @@ pub(crate) struct OwnerHotReplicaIdentity { put_version: u32, } -impl OwnerHotReplicaIdentity { - fn from_group_member(member: &crate::master_kv_router::msg_pack::PutAtomicGroupMember) -> Self { - Self { - key: member.key.clone(), - put_time_ms: member.put_id.0, - put_version: member.put_id.1, - } - } -} - #[derive(Default)] struct OwnerHotCacheCounters { size_evictions: AtomicU64, @@ -1287,8 +1277,8 @@ struct OwnerHotCacheCounters { skipped_stale: AtomicU64, skipped_reclaim: AtomicU64, skipped_active_holders: AtomicU64, - group_trigger_duplicates: AtomicU64, - group_trigger_incomplete: AtomicU64, + victim_duplicates: AtomicU64, + victim_invalid_backing: AtomicU64, grouped_put_done_batches: AtomicU64, grouped_put_done_items: AtomicU64, legacy_put_done_batches: AtomicU64, @@ -1350,35 +1340,37 @@ pub(crate) struct OwnerHotEvictionEvent { put_id: crate::master_kv_router::put::PutIDForAKey, memory_info: Weak, selection_debt: Arc, - /// The event was dispatched from the bounded retry queue. It may be a - /// pre-selection retry (no atomic_batch yet) or an exact installed-atomic_batch retry. + /// The event was dispatched from the bounded retry queue. retry: bool, - /// Exact owner source-delete atomic_batch retained across RPC retries. Once set, - /// retries never re-expand or re-pin the local atomic_batch. - source_eviction_atomic_batch: - Option>, + /// Exact single-key source-delete transaction retained across RPC retries. + source_eviction_victim: + Option>, /// Failure count follows the event while it is dispatched, preserving /// exponential backoff across queue take/reinsert cycles. retry_failures: u32, } +pub(crate) enum OwnerHotEvictionDispatch { + Victim(OwnerHotEvictionEvent), + BeginPressure { requested_bytes: u64 }, + EndPressure { selected_bytes: u64 }, + Flush, +} + pub(crate) enum OwnerHotEvictionPreparation { Ready { trigger: OwnerHotReplicaIdentity, - sources: Vec<(OwnerHotReplicaIdentity, Arc)>, + source: Arc, }, RetryableReclaimFence, - RetryableIncompleteAtomicBatch, - TemporarilyPinned { - active_members: usize, - }, + TemporarilyPinned, Obsolete, } pub(crate) enum OwnerHotSelectionFenceOutcome { Fenced, Retryable, - TemporarilyPinned { active_members: usize }, + TemporarilyPinned, Obsolete, } @@ -1451,8 +1443,8 @@ impl OwnerHotRetryQueue { if !Arc::ptr_eq(&entry.event.selection_debt, &event.selection_debt) { entry.event.selection_debt.release(); } - if event.source_eviction_atomic_batch.is_none() { - event.source_eviction_atomic_batch = entry.event.source_eviction_atomic_batch.clone(); + if event.source_eviction_victim.is_none() { + event.source_eviction_victim = entry.event.source_eviction_victim.clone(); } entry.failures = entry.failures.max(event.retry_failures).saturating_add(1); event.retry = true; @@ -1565,6 +1557,49 @@ pub(crate) enum OwnerReclaimRecord { Committed(crate::master_kv_router::msg_pack::OwnerReclaimItem), } +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(crate) enum ExternalPutKeyOutcome { + InFlight, + Succeeded, + Failed, +} + +pub(crate) struct ExternalPutKeySharedOp { + outcome: watch::Sender, +} + +impl ExternalPutKeySharedOp { + fn new() -> Arc { + let (outcome, _receiver) = watch::channel(ExternalPutKeyOutcome::InFlight); + Arc::new(Self { outcome }) + } + + fn complete(&self, outcome: ExternalPutKeyOutcome) { + debug_assert_ne!(outcome, ExternalPutKeyOutcome::InFlight); + if *self.outcome.borrow() == ExternalPutKeyOutcome::InFlight { + self.outcome.send_replace(outcome); + } + } + + pub(crate) async fn wait(&self) -> ExternalPutKeyOutcome { + let mut outcome = self.outcome.subscribe(); + loop { + let current = *outcome.borrow_and_update(); + if current != ExternalPutKeyOutcome::InFlight { + return current; + } + if outcome.changed().await.is_err() { + return ExternalPutKeyOutcome::Failed; + } + } + } +} + +pub(crate) enum ExternalLocalFirstPutKeyReservation { + Leader(Arc), + Wait(Arc), +} + #[derive(Default)] pub(crate) struct OwnerKeyControlState { local_puts: u32, @@ -1573,6 +1608,9 @@ pub(crate) struct OwnerKeyControlState { /// guard stored in every context, so cache invalidation cannot clear the /// reclaim fence while a cloned context is still in use. external_pending_puts: u32, + /// The reject-on-inflight local-first Put leader for this key. Followers + /// subscribe to its terminal result without claiming another slot. + external_put: Option>, /// Owner-local pre-Prepare fence installed by the Moka source-eviction /// dispatcher. The matching committed index is moved into this record, /// so a new local Get cannot acquire the source between victim selection @@ -1593,6 +1631,7 @@ impl OwnerKeyControlState { fn is_idle(&self) -> bool { self.local_puts == 0 && self.external_pending_puts == 0 + && self.external_put.is_none() && self.source_eviction_selection.is_none() && self.reclaim.is_none() && self.external_get.is_none() @@ -1642,6 +1681,8 @@ pub(crate) struct ExternalPendingPutFenceGuard { key: String, owner_key_control: Arc, owns_local_put: bool, + local_put_op: Option>, + local_put_succeeded: std::sync::atomic::AtomicBool, local_slot_cleanup_view: Option, local_slot_lease: Mutex>, local_slot_release_failed: std::sync::atomic::AtomicBool, @@ -1658,6 +1699,17 @@ impl std::fmt::Debug for ExternalPendingPutFenceGuard { } impl ExternalPendingPutFenceGuard { + pub(crate) fn mark_local_put_succeeded(&self) { + assert!( + self.owns_local_put, + "only a local-first Put can publish a reusable terminal result" + ); + self.local_put_succeeded.store(true, Ordering::Release); + if let Some(op) = self.local_put_op.as_ref() { + op.complete(ExternalPutKeyOutcome::Succeeded); + } + } + pub(crate) fn attach_local_slot_lease(&self, lease: OwnerLocalReserveSlotLease) { assert!( self.owns_local_put, @@ -1709,6 +1761,8 @@ fn release_external_pending_put_counts( owner_key_control: &Arc, key: &str, owns_local_put: bool, + local_put_op: Option>, + local_put_succeeded: bool, ) { let mut controls = owner_key_control.lock_key(key); let remove = { @@ -1724,12 +1778,28 @@ fn release_external_pending_put_counts( .local_puts .checked_sub(1) .expect("owner local-first Put fence counter underflow"); + if let Some(op) = local_put_op.as_ref() + && state + .external_put + .as_ref() + .is_some_and(|current| Arc::ptr_eq(current, op)) + { + state.external_put = None; + } } state.is_idle() }; if remove { controls.remove(key); } + drop(controls); + if let Some(op) = local_put_op { + op.complete(if local_put_succeeded { + ExternalPutKeyOutcome::Succeeded + } else { + ExternalPutKeyOutcome::Failed + }); + } } fn acquire_external_pending_put_fence_for_key( @@ -1754,6 +1824,8 @@ fn acquire_external_pending_put_fence_for_key( key: key.to_string(), owner_key_control: owner_key_control.clone(), owns_local_put: false, + local_put_op: None, + local_put_succeeded: std::sync::atomic::AtomicBool::new(false), local_slot_cleanup_view: None, local_slot_lease: Mutex::new(None), local_slot_release_failed: std::sync::atomic::AtomicBool::new(false), @@ -1773,6 +1845,8 @@ impl Drop for ExternalPendingPutFenceGuard { let key = self.key.clone(); let owner_key_control = self.owner_key_control.clone(); let owns_local_put = self.owns_local_put; + let local_put_op = self.local_put_op.clone(); + let local_put_succeeded = self.local_put_succeeded.load(Ordering::Acquire); view.spawn("external_pending_put_slot_drop_cleanup", async move { if let Err(err) = worker_view .client_kv_api() @@ -1783,13 +1857,21 @@ impl Drop for ExternalPendingPutFenceGuard { tracing::error!("pending local-first Put slot Drop cleanup failed: {}", err); return; } - release_external_pending_put_counts(&owner_key_control, &key, owns_local_put); + release_external_pending_put_counts( + &owner_key_control, + &key, + owns_local_put, + local_put_op, + local_put_succeeded, + ); }); } else if !self.local_slot_release_failed.load(Ordering::Acquire) { release_external_pending_put_counts( &self.owner_key_control, &self.key, self.owns_local_put, + self.local_put_op.clone(), + self.local_put_succeeded.load(Ordering::Acquire), ); } else { tracing::error!( @@ -1898,208 +1980,11 @@ fn pin_current_owner_hot_source( } } -fn owner_hot_group_anchor_identity( - group: &crate::master_kv_router::msg_pack::PutAtomicGroup, -) -> Option { - group - .members - .first() - .map(OwnerHotReplicaIdentity::from_group_member) -} - -fn register_owner_hot_atomic_group( - atomic_groups: &DashMap< - OwnerHotReplicaIdentity, - Arc, - >, - group: &crate::master_kv_router::msg_pack::PutAtomicGroup, -) { - let Some(anchor) = owner_hot_group_anchor_identity(group) else { - return; - }; - let existing = atomic_groups - .get(&anchor) - .map(|entry| entry.value().clone()); - let group = match existing { - Some(existing) if existing.as_ref() == group => existing, - Some(_) => { - tracing::warn!( - "owner hot atomic-group anchor reused with different membership: key={} put_id=({},{})", - anchor.key, - anchor.put_time_ms, - anchor.put_version - ); - Arc::new(group.clone()) - } - None => Arc::new(group.clone()), - }; - for member in &group.members { - atomic_groups.insert( - OwnerHotReplicaIdentity::from_group_member(member), - group.clone(), - ); - } -} - -fn forget_owner_hot_atomic_group( - atomic_groups: &DashMap< - OwnerHotReplicaIdentity, - Arc, - >, - identity: &OwnerHotReplicaIdentity, -) { - let group = atomic_groups - .get(identity) - .map(|entry| entry.value().clone()); - let Some(group) = group else { - return; - }; - for member in &group.members { - atomic_groups.remove(&OwnerHotReplicaIdentity::from_group_member(member)); - } -} - -fn pin_current_owner_hot_group_sources( - group: &crate::master_kv_router::msg_pack::PutAtomicGroup, - get_cached_info: &DashMap, - counters: &OwnerHotCacheCounters, -) -> Option)>> { - let mut sources = Vec::with_capacity(group.members.len()); - for member in &group.members { - let Some(cached) = get_cached_info.get(&member.key) else { - counters.skipped_reclaim.fetch_add(1, Ordering::Relaxed); - return None; - }; - if (cached.put_time_ms, cached.put_version) != member.put_id { - counters.skipped_stale.fetch_add(1, Ordering::Relaxed); - return None; - } - sources.push(( - OwnerHotReplicaIdentity::from_group_member(member), - cached.mem_holder.clone(), - )); - } - Some(sources) -} - -fn owner_hot_tp_atomic_batch_key_rows( - identity: &OwnerHotReplicaIdentity, - group: Option<&crate::master_kv_router::msg_pack::PutAtomicGroup>, -) -> Result>>, ()> { - let member_keys = group - .map(|group| { - group - .members - .iter() - .map(|member| member.key.as_str()) - .collect::>() - }) - .unwrap_or_else(|| vec![identity.key.as_str()]); - let Some(first_key) = member_keys.first().copied() else { - return Err(()); - }; - let first_tp = crate::master_kv_router::infer_sglang_tp_key(first_key); - let Some(first_tp) = first_tp else { - return member_keys - .iter() - .all(|key| crate::master_kv_router::infer_sglang_tp_key(key).is_none()) - .then_some(None) - .ok_or(()); - }; - let mut logical_members = Vec::with_capacity(member_keys.len()); - for key in member_keys { - let Some(member_tp) = crate::master_kv_router::infer_sglang_tp_key(key) else { - return Err(()); - }; - if member_tp.rank != first_tp.rank || member_tp.size != first_tp.size { - return Err(()); - } - logical_members.push(member_tp.logical_prefix.to_string()); - } - if first_tp.size == 1 { - return Ok(None); - } - Ok(Some( - (0..first_tp.size) - .map(|rank| { - logical_members - .iter() - .map(|logical_prefix| format!("{logical_prefix}_{rank}_{}", first_tp.size)) - .collect::>() - }) - .collect(), - )) -} - -fn pin_current_owner_hot_tp_atomic_batch_sources( - atomic_batch_key_rows: &[Vec], - expect_atomic_group: bool, - get_cached_info: &DashMap, - atomic_groups: &DashMap< - OwnerHotReplicaIdentity, - Arc, - >, - counters: &OwnerHotCacheCounters, -) -> Option)>> { - let mut atomic_batch_sources = Vec::new(); - for rank_keys in atomic_batch_key_rows { - if rank_keys.is_empty() { - return None; - } - let mut rank_sources = Vec::with_capacity(rank_keys.len()); - for key in rank_keys { - let Some(cached) = get_cached_info.get(key) else { - counters.skipped_reclaim.fetch_add(1, Ordering::Relaxed); - return None; - }; - rank_sources.push(( - OwnerHotReplicaIdentity { - key: key.clone(), - put_time_ms: cached.put_time_ms, - put_version: cached.put_version, - }, - cached.mem_holder.clone(), - )); - } - - if expect_atomic_group { - let Some(rank_group) = atomic_groups - .get(&rank_sources[0].0) - .map(|entry| entry.value().clone()) - else { - return None; - }; - if rank_group.members.len() != rank_sources.len() - || rank_group.members.iter().zip(rank_sources.iter()).any( - |(member, (identity, _))| { - member.key != identity.key - || member.put_id != (identity.put_time_ms, identity.put_version) - }, - ) - { - return None; - } - for (identity, _) in &rank_sources { - if !atomic_groups - .get(identity) - .is_some_and(|entry| Arc::ptr_eq(entry.value(), &rank_group)) - { - return None; - } - } - } else if rank_sources.len() != 1 || atomic_groups.contains_key(&rank_sources[0].0) { - return None; - } - atomic_batch_sources.extend(rank_sources); - } - Some(atomic_batch_sources) -} - fn build_owner_hot_cache( capacity_bytes: u64, counters: Arc, retry_queue: Arc, - eviction_tx: tokio::sync::ampsc::UnboundedSender, + eviction_tx: tokio::sync::ampsc::UnboundedSender, ) -> OwnerHotCache { assert!( capacity_bytes > 0, @@ -2127,11 +2012,13 @@ fn build_owner_hot_cache( memory_info: entry.memory_info.clone(), selection_debt, retry: false, - source_eviction_atomic_batch: None, + source_eviction_victim: None, retry_failures: 0, }; - if let Err(err) = eviction_tx.send(event) { - let event = err.0; + if let Err(err) = eviction_tx.send(OwnerHotEvictionDispatch::Victim(event)) { + let OwnerHotEvictionDispatch::Victim(event) = err.0 else { + unreachable!("the Moka listener only sends victim events") + }; counters .source_evict_dispatch_failed .fetch_add(1, Ordering::Relaxed); @@ -2221,14 +2108,11 @@ pub struct ClientKvApiInner { /// Free or the source is restored to owner-hot. owner_source_eviction_selected: Arc>>, - owner_hot_atomic_groups: Arc< - DashMap>, - >, owner_hot_counters: Arc, owner_hot_retry_queue: Arc, - owner_hot_eviction_tx: tokio::sync::ampsc::UnboundedSender, + owner_hot_eviction_tx: tokio::sync::ampsc::UnboundedSender, owner_hot_eviction_rx: - Mutex>>, + Mutex>>, /// Shared delete actor input for owner -> external weak-index invalidation. pub external_invalidate_delete: EnsureMemholderMgmtDeleteHandle, @@ -2338,17 +2222,6 @@ impl ClientKvApiInner { ops } - fn owner_hot_register_atomic_group( - &self, - group: &crate::master_kv_router::msg_pack::PutAtomicGroup, - ) { - register_owner_hot_atomic_group(self.owner_hot_atomic_groups.as_ref(), group); - } - - fn owner_hot_forget_atomic_group_for_member(&self, identity: &OwnerHotReplicaIdentity) { - forget_owner_hot_atomic_group(self.owner_hot_atomic_groups.as_ref(), identity); - } - pub(crate) fn owner_hot_prepare_eviction( &self, event: &OwnerHotEvictionEvent, @@ -2376,66 +2249,12 @@ impl ClientKvApiInner { OwnerHotPinResult::Stale => return OwnerHotEvictionPreparation::Obsolete, }; - // A retry reaches this function only when no source-selection atomic_batch - // has been installed yet. Installed retries are handled from the - // event's exact `source_eviction_atomic_batch` before this method is called. - // Therefore a pre-selection retry must resolve the complete current - // TP/atomic atomic_batch again; degrading it to the trigger key would make - // the master reject a valid victim as an incomplete atomic_batch forever. - // AtomicBatch lookup and pinning deliberately happen after the synchronous - // Moka listener has returned. Each source Arc is cloned directly from - // its current DashMap entry. A concurrent reclaim must wait for that - // shard read guard and then observes the extra strong reference, so no - // global owner-control lock is needed. - let group = self - .owner_hot_atomic_groups - .get(&trigger) - .map(|entry| entry.value().clone()); - let atomic_batch_sources = - match owner_hot_tp_atomic_batch_key_rows(&trigger, group.as_deref()) { - Ok(Some(atomic_batch_key_rows)) => { - // pin_current_owner_hot_tp_atomic_batch_sources clones the trigger - // again. Drop the probe pin first so the active-holder test - // below has the exact index + selection baseline of two Arcs. - drop(memory_info); - pin_current_owner_hot_tp_atomic_batch_sources( - &atomic_batch_key_rows, - group.is_some(), - self.get_cached_info.as_ref(), - self.owner_hot_atomic_groups.as_ref(), - self.owner_hot_counters.as_ref(), - ) - } - Ok(None) => match group.as_deref() { - Some(group) => { - drop(memory_info); - pin_current_owner_hot_group_sources( - group, - self.get_cached_info.as_ref(), - self.owner_hot_counters.as_ref(), - ) - } - None => Some(vec![(trigger.clone(), memory_info)]), - }, - Err(()) => None, - }; - match atomic_batch_sources { - Some(sources) if !sources.is_empty() => { - let active_members = sources - .iter() - .filter(|(_, source)| owner_hot_source_has_active_holders(source)) - .count(); - if active_members == 0 { - OwnerHotEvictionPreparation::Ready { trigger, sources } - } else { - OwnerHotEvictionPreparation::TemporarilyPinned { active_members } - } - } - _ => { - self.owner_hot_counters - .group_trigger_incomplete - .fetch_add(1, Ordering::Relaxed); - OwnerHotEvictionPreparation::RetryableIncompleteAtomicBatch + if owner_hot_source_has_active_holders(&memory_info) { + OwnerHotEvictionPreparation::TemporarilyPinned + } else { + OwnerHotEvictionPreparation::Ready { + trigger, + source: memory_info, } } } @@ -2503,77 +2322,59 @@ impl ClientKvApiInner { Some(debt) } - pub(crate) fn owner_hot_install_source_selection_fences( + pub(crate) fn owner_hot_install_source_selection_fence( &self, - sources: &[(OwnerHotReplicaIdentity, Arc)], + identity: &OwnerHotReplicaIdentity, + source: &Arc, ) -> OwnerHotSelectionFenceOutcome { - let mut installed = Vec::with_capacity(sources.len()); - let mut outcome = OwnerHotSelectionFenceOutcome::Fenced; - - for (identity, source) in sources { - let mut controls = self.owner_key_control.lock_key(&identity.key); - let control_busy = controls.get(&identity.key).is_some_and(|state| { - state.local_puts != 0 - || state.external_pending_puts != 0 - || state.external_get.is_some() - || state.local_access_fenced() - }); - if control_busy - || self - .precommit_local_visible_info - .contains_key(&identity.key) - || self.pending_local_get_info.contains_key(&identity.key) - { - outcome = OwnerHotSelectionFenceOutcome::Retryable; - break; - } - - let cached_info = self - .get_cached_info - .remove_if(&identity.key, |_, cached| { - (cached.put_time_ms, cached.put_version) - == (identity.put_time_ms, identity.put_version) - && Arc::ptr_eq(&cached.mem_holder, source) - }) - .map(|(_, cached)| cached); - let Some(cached_info) = cached_info else { - outcome = OwnerHotSelectionFenceOutcome::Obsolete; - break; - }; - - let state = controls.entry(identity.key.clone()).or_default(); - assert!(state.source_eviction_selection.is_none()); - state.source_eviction_selection = Some(OwnerSourceEvictionSelection { - put_id: (identity.put_time_ms, identity.put_version), - cached_info, - }); - installed.push(identity.clone()); + let mut controls = self.owner_key_control.lock_key(&identity.key); + let control_busy = controls.get(&identity.key).is_some_and(|state| { + state.local_puts != 0 + || state.external_pending_puts != 0 + || state.external_get.is_some() + || state.local_access_fenced() + }); + if control_busy + || self + .precommit_local_visible_info + .contains_key(&identity.key) + || self.pending_local_get_info.contains_key(&identity.key) + { + return OwnerHotSelectionFenceOutcome::Retryable; } - if matches!(outcome, OwnerHotSelectionFenceOutcome::Fenced) { - // Every matching local index is now hidden under its per-key fence. - // Each source has exactly two expected Arcs: the selection record - // and this temporary atomic_batch pin. No new local reader can enter, - // so an extra reference is an already-active holder and the whole - // atomic_batch must be rolled back before choosing another victim. - let active_members = sources - .iter() - .filter(|(_, source)| owner_hot_source_has_active_holders(source)) - .count(); - if active_members != 0 { - outcome = OwnerHotSelectionFenceOutcome::TemporarilyPinned { active_members }; - } - } + let cached_info = self + .get_cached_info + .remove_if(&identity.key, |_, cached| { + (cached.put_time_ms, cached.put_version) + == (identity.put_time_ms, identity.put_version) + && Arc::ptr_eq(&cached.mem_holder, source) + }) + .map(|(_, cached)| cached); + let Some(cached_info) = cached_info else { + return OwnerHotSelectionFenceOutcome::Obsolete; + }; - if !matches!(outcome, OwnerHotSelectionFenceOutcome::Fenced) { - for identity in installed.iter().rev() { - assert!( - self.owner_hot_restore_source_selection(identity), - "partial owner source selection rollback must find every installed fence" - ); - } + let state = controls.entry(identity.key.clone()).or_default(); + assert!(state.source_eviction_selection.is_none()); + state.source_eviction_selection = Some(OwnerSourceEvictionSelection { + put_id: (identity.put_time_ms, identity.put_version), + cached_info, + }); + drop(controls); + + // The index Arc moved into source_eviction_selection. The temporary + // source Arc is the second expected reference; any extra Arc is an + // active reader or transfer that arrived before the fence was installed. + if owner_hot_source_has_active_holders(source) { + assert!( + self.owner_hot_restore_source_selection(identity), + "a pinned single-key victim must restore its source fence" + ); + OwnerHotSelectionFenceOutcome::TemporarilyPinned + } else { + OwnerHotSelectionFenceOutcome::Fenced } - outcome } fn owner_hot_track_committed( @@ -2581,7 +2382,6 @@ impl ClientKvApiInner { key: &str, put_id: crate::master_kv_router::put::PutIDForAKey, memory_info: &Arc, - atomic_group: Option<&crate::master_kv_router::msg_pack::PutAtomicGroup>, ) { let Some(cache) = self.owner_hot_cache.as_ref() else { return; @@ -2589,9 +2389,6 @@ impl ClientKvApiInner { if !self.owner_hot_source_is_current(key, put_id, memory_info) { return; } - if let Some(group) = atomic_group { - self.owner_hot_register_atomic_group(group); - } cache.insert( key.to_string(), [OwnerHotPinAlias::new(memory_info)], @@ -2610,7 +2407,6 @@ impl ClientKvApiInner { &self, key: &str, put_id: crate::master_kv_router::put::PutIDForAKey, - atomic_group: Option<&crate::master_kv_router::msg_pack::PutAtomicGroup>, ) -> bool { let memory_info = self.get_cached_info.get(key).and_then(|cached| { ((cached.put_time_ms, cached.put_version) == put_id).then(|| cached.mem_holder.clone()) @@ -2618,7 +2414,7 @@ impl ClientKvApiInner { let Some(memory_info) = memory_info else { return false; }; - self.owner_hot_track_committed(key, put_id, &memory_info, atomic_group); + self.owner_hot_track_committed(key, put_id, &memory_info); true } @@ -2636,7 +2432,7 @@ impl ClientKvApiInner { }) { return; } - self.owner_hot_track_committed(key, put_id, memory_info, None); + self.owner_hot_track_committed(key, put_id, memory_info); } pub(crate) fn owner_hot_source_is_current( @@ -2679,7 +2475,6 @@ impl ClientKvApiInner { .fetch_add(1, Ordering::Relaxed); } self.owner_hot_retry_queue.remove(&identity); - self.owner_hot_forget_atomic_group_for_member(&identity); } pub(crate) fn release_local_reserve_route_for_memory_info(&self, memory_info: &MemoryInfo) { @@ -2755,7 +2550,7 @@ impl ClientKvApiInner { key: &str, reject_if_inflight_same_key: bool, reject_if_exist_same_key: bool, - ) -> KvResult> { + ) -> KvResult { let mut controls = self.owner_key_control.lock_key(key); if controls .get(key) @@ -2776,10 +2571,26 @@ impl ClientKvApiInner { })); } let state = controls.entry(key.to_string()).or_default(); + let reusable_singleflight = reject_if_inflight_same_key && reject_if_exist_same_key; if reject_if_inflight_same_key && state.local_puts > 0 { - return Err(KvError::Api(ApiError::KeyBeingWritten { - key: key.to_string(), - })); + return (reusable_singleflight) + .then(|| state.external_put.clone()) + .flatten() + .map_or_else( + || { + Err(KvError::Api(ApiError::KeyBeingWritten { + key: key.to_string(), + })) + }, + |op| Ok(ExternalLocalFirstPutKeyReservation::Wait(op)), + ); + } + let local_put_op = reusable_singleflight.then(ExternalPutKeySharedOp::new); + if let Some(op) = local_put_op.as_ref() { + assert!( + state.external_put.replace(op.clone()).is_none(), + "a reject-on-inflight Put leader must own an empty shared-op slot" + ); } state.local_puts = state .local_puts @@ -2789,14 +2600,18 @@ impl ClientKvApiInner { .external_pending_puts .checked_add(1) .expect("external pending Put fence counter overflow"); - Ok(Arc::new(ExternalPendingPutFenceGuard { - key: key.to_string(), - owner_key_control: self.owner_key_control.clone(), - owns_local_put: true, - local_slot_cleanup_view: Some(self.view.clone_view()), - local_slot_lease: Mutex::new(None), - local_slot_release_failed: std::sync::atomic::AtomicBool::new(false), - })) + Ok(ExternalLocalFirstPutKeyReservation::Leader(Arc::new( + ExternalPendingPutFenceGuard { + key: key.to_string(), + owner_key_control: self.owner_key_control.clone(), + owns_local_put: true, + local_put_op, + local_put_succeeded: std::sync::atomic::AtomicBool::new(false), + local_slot_cleanup_view: Some(self.view.clone_view()), + local_slot_lease: Mutex::new(None), + local_slot_release_failed: std::sync::atomic::AtomicBool::new(false), + }, + ))) } pub(crate) fn acquire_external_pending_put_fence( @@ -3184,7 +2999,7 @@ impl ClientKvApiInner { }, ); } - self.owner_hot_track_committed(key, put_id, &memory_info, None); + self.owner_hot_track_committed(key, put_id, &memory_info); Ok(()) } @@ -3227,7 +3042,7 @@ impl ClientKvApiInner { }, ); } - self.owner_hot_track_committed(key, put_id, &memory_info, None); + self.owner_hot_track_committed(key, put_id, &memory_info); true } @@ -4020,23 +3835,21 @@ impl OwnerLocalReserveClassState { #[cfg(test)] mod owner_reclaim_slot_tests { use super::{ - ExternalPendingPutCtx, ExternalPendingPutFenceGuard, OwnerHotCacheCounters, - OwnerHotCacheEntry, OwnerHotEvictionEvent, OwnerHotPinAlias, OwnerHotReplicaIdentity, + ExternalLocalFirstPutKeyReservation, ExternalPendingPutCtx, ExternalPendingPutFenceGuard, + ExternalPutKeyOutcome, ExternalPutKeySharedOp, OwnerHotCacheCounters, OwnerHotCacheEntry, + OwnerHotEvictionDispatch, OwnerHotEvictionEvent, OwnerHotPinAlias, OwnerHotReplicaIdentity, OwnerHotRetryQueue, OwnerHotSelectionDebt, OwnerHotSelectionFenceOutcome, OwnerKeyControlState, OwnerKeyControlTable, OwnerLocalReserveGrantState, OwnerLocalReserveSlotLease, OwnerLocalReserveSlotRef, OwnerLocalReserveSlotState, OwnerReclaimRecord, acquire_external_pending_put_fence_for_key, allocate_external_holding_id, build_owner_hot_cache, clone_if_owner_hot_entry_matches, - forget_owner_hot_atomic_group, owner_hot_source_has_active_holders, - owner_hot_tp_atomic_batch_key_rows, pin_current_owner_hot_source_from_index, - register_owner_hot_atomic_group, + owner_hot_source_has_active_holders, pin_current_owner_hot_source_from_index, }; use crate::master_kv_router::msg_pack::{ BatchOwnerReclaimReq, OwnerReclaimBacking, OwnerReclaimItem, OwnerReclaimItemState, - OwnerReclaimPhase, OwnerReclaimReason, PutAtomicGroup, PutAtomicGroupMember, + OwnerReclaimPhase, OwnerReclaimReason, OwnerSourceEvictionVictim, }; use crate::p2p::msg_pack::MsgPack; - use dashmap::DashMap; use parking_lot::Mutex; use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::{Arc, Weak}; @@ -4091,6 +3904,7 @@ mod owner_reclaim_slot_tests { OwnerKeyControlState { local_puts: 1, external_pending_puts: 1, + external_put: None, source_eviction_selection: None, reclaim: None, external_get: None, @@ -4100,6 +3914,8 @@ mod owner_reclaim_slot_tests { key: "local-key".to_string(), owner_key_control: controls.clone(), owns_local_put: true, + local_put_op: None, + local_put_succeeded: std::sync::atomic::AtomicBool::new(false), local_slot_cleanup_view: None, local_slot_lease: Mutex::new(None), local_slot_release_failed: std::sync::atomic::AtomicBool::new(false), @@ -4109,6 +3925,79 @@ mod owner_reclaim_slot_tests { assert!(controls.lock_key("local-key").get("local-key").is_none()); } + #[limit_thirdparty::tokio::test] + async fn same_key_put_waiter_reuses_one_leader_terminal_result() { + let key = "put-singleflight"; + let op = ExternalPutKeySharedOp::new(); + let controls = controls_with_state( + key, + OwnerKeyControlState { + local_puts: 1, + external_pending_puts: 1, + external_put: Some(op.clone()), + source_eviction_selection: None, + reclaim: None, + external_get: None, + }, + ); + let leader = Arc::new(ExternalPendingPutFenceGuard { + key: key.to_string(), + owner_key_control: controls.clone(), + owns_local_put: true, + local_put_op: Some(op.clone()), + local_put_succeeded: std::sync::atomic::AtomicBool::new(false), + local_slot_cleanup_view: None, + local_slot_lease: Mutex::new(None), + local_slot_release_failed: std::sync::atomic::AtomicBool::new(false), + }); + + leader.mark_local_put_succeeded(); + assert_eq!( + ::tokio::time::timeout(Duration::from_secs(1), op.wait()) + .await + .expect("the follower must observe the leader terminal result"), + ExternalPutKeyOutcome::Succeeded + ); + drop(leader); + assert!(controls.lock_key(key).get(key).is_none()); + } + + #[limit_thirdparty::tokio::test] + async fn failed_put_leader_wakes_waiter_only_after_its_fence_is_released() { + let key = "put-singleflight-failed"; + let op = ExternalPutKeySharedOp::new(); + let controls = controls_with_state( + key, + OwnerKeyControlState { + local_puts: 1, + external_pending_puts: 1, + external_put: Some(op.clone()), + source_eviction_selection: None, + reclaim: None, + external_get: None, + }, + ); + let leader = Arc::new(ExternalPendingPutFenceGuard { + key: key.to_string(), + owner_key_control: controls.clone(), + owns_local_put: true, + local_put_op: Some(op.clone()), + local_put_succeeded: std::sync::atomic::AtomicBool::new(false), + local_slot_cleanup_view: None, + local_slot_lease: Mutex::new(None), + local_slot_release_failed: std::sync::atomic::AtomicBool::new(false), + }); + + drop(leader); + assert_eq!( + ::tokio::time::timeout(Duration::from_secs(1), op.wait()) + .await + .expect("the failed leader must wake its follower"), + ExternalPutKeyOutcome::Failed + ); + assert!(controls.lock_key(key).get(key).is_none()); + } + #[test] fn failed_local_slot_release_keeps_key_fence_closed() { let controls = controls_with_state( @@ -4116,6 +4005,7 @@ mod owner_reclaim_slot_tests { OwnerKeyControlState { local_puts: 1, external_pending_puts: 1, + external_put: None, source_eviction_selection: None, reclaim: None, external_get: None, @@ -4125,6 +4015,8 @@ mod owner_reclaim_slot_tests { key: "failed-slot".to_string(), owner_key_control: controls.clone(), owns_local_put: true, + local_put_op: None, + local_put_succeeded: std::sync::atomic::AtomicBool::new(false), local_slot_cleanup_view: None, local_slot_lease: Mutex::new(None), local_slot_release_failed: std::sync::atomic::AtomicBool::new(true), @@ -4143,6 +4035,7 @@ mod owner_reclaim_slot_tests { OwnerKeyControlState { local_puts: 1, external_pending_puts: 1, + external_put: None, source_eviction_selection: None, reclaim: None, external_get: None, @@ -4152,6 +4045,8 @@ mod owner_reclaim_slot_tests { key: "committed-slot".to_string(), owner_key_control: controls.clone(), owns_local_put: true, + local_put_op: None, + local_put_succeeded: std::sync::atomic::AtomicBool::new(false), local_slot_cleanup_view: None, local_slot_lease: Mutex::new(None), local_slot_release_failed: std::sync::atomic::AtomicBool::new(false), @@ -4260,7 +4155,7 @@ mod owner_reclaim_slot_tests { } #[limit_thirdparty::tokio::test(flavor = "multi_thread", worker_threads = 8)] - async fn source_selection_fence_closes_late_get_and_rolls_back_whole_atomic_batch() { + async fn single_key_source_selection_fence_closes_late_get_and_rolls_back() { use crate::client_kv_api::PutOptionalArgs; use crate::kvcore_test_lib::{ integration_test_lock, start_master_and_client, stop_master_and_client, @@ -4274,85 +4169,90 @@ mod owner_reclaim_slot_tests { .await; let owner_view = client.client_kv_api_view(); let inner = owner_view.client_kv_api().inner(); - let keys = ["selection-rank0", "selection-rank1"]; - for key in keys { - inner - .put(key, &[7u8; 4096], PutOptionalArgs::default()) - .await - .expect("owner put must publish a committed route"); - let (holder, _remote) = inner - .get(key) - .await - .expect("owner get must succeed") - .expect("committed route must be readable"); - drop(holder); - } + let join_probe_leader = match inner + .reserve_external_local_first_put_key("put-join-probe", true, true) + .expect("the first same-key Put must become leader") + { + ExternalLocalFirstPutKeyReservation::Leader(leader) => leader, + ExternalLocalFirstPutKeyReservation::Wait(_) => { + panic!("the first same-key Put cannot be a follower") + } + }; + let join_probe_waiter = match inner + .reserve_external_local_first_put_key("put-join-probe", true, true) + .expect("the second same-key Put must join the leader") + { + ExternalLocalFirstPutKeyReservation::Wait(waiter) => waiter, + ExternalLocalFirstPutKeyReservation::Leader(_) => { + panic!("the second same-key Put must not claim a second leader fence") + } + }; + join_probe_leader.mark_local_put_succeeded(); + assert_eq!( + join_probe_waiter.wait().await, + ExternalPutKeyOutcome::Succeeded + ); + drop(join_probe_leader); - let sources = keys - .iter() - .map(|key| { - let cached = inner - .get_cached_info - .get(*key) - .expect("committed owner source must be indexed"); - ( - OwnerHotReplicaIdentity { - key: (*key).to_string(), - put_time_ms: cached.put_time_ms, - put_version: cached.put_version, - }, - cached.mem_holder.clone(), - ) - }) - .collect::>(); + let key = "selection-single"; + inner + .put(key, &[7u8; 4096], PutOptionalArgs::default()) + .await + .expect("owner put must publish a committed route"); + let (holder, _remote) = inner + .get(key) + .await + .expect("owner get must succeed") + .expect("committed route must be readable"); + drop(holder); + + let cached = inner + .get_cached_info + .get(key) + .expect("committed owner source must be indexed"); + let identity = OwnerHotReplicaIdentity { + key: key.to_string(), + put_time_ms: cached.put_time_ms, + put_version: cached.put_version, + }; + let source = cached.mem_holder.clone(); + drop(cached); assert!( - sources - .iter() - .all(|(_, source)| !owner_hot_source_has_active_holders(source)), + !owner_hot_source_has_active_holders(&source), "the initial victim check must see only index plus selection pins" ); - // Reproduce the r11 TOCTOU exactly: a local Get acquires one atomic_batch - // member after the dispatcher's first holder check but before the - // source-selection fence is installed. + // Reproduce the r11 TOCTOU: a local Get acquires the single victim after + // the dispatcher's first holder check but before its fence is installed. let late_reader = inner - .local_visible_mem_holder(keys[1]) + .local_visible_mem_holder(key) .expect("late local Get must acquire the source before fencing"); assert!(matches!( - inner.owner_hot_install_source_selection_fences(&sources), - OwnerHotSelectionFenceOutcome::TemporarilyPinned { active_members: 1 } + inner.owner_hot_install_source_selection_fence(&identity, &source), + OwnerHotSelectionFenceOutcome::TemporarilyPinned )); - for key in keys { - assert!(inner.get_cached_info.contains_key(key)); - assert!( - inner - .owner_key_control - .lock_key(key) - .get(key) - .is_none_or(|state| state.source_eviction_selection.is_none()), - "a pinned member must roll back every partial atomic_batch fence" - ); - } + assert!(inner.get_cached_info.contains_key(key)); + assert!( + inner + .owner_key_control + .lock_key(key) + .get(key) + .is_none_or(|state| state.source_eviction_selection.is_none()), + "a pinned victim must roll back its source fence" + ); drop(late_reader); assert!(matches!( - inner.owner_hot_install_source_selection_fences(&sources), + inner.owner_hot_install_source_selection_fence(&identity, &source), OwnerHotSelectionFenceOutcome::Fenced )); - for key in keys { - assert!(!inner.get_cached_info.contains_key(key)); - assert!(inner.local_visible_mem_holder(key).is_none()); - assert!( - acquire_external_pending_put_fence_for_key(&inner.owner_key_control, key).is_err(), - "a new local Put must not cross a source-selection fence" - ); - } - - let identities = sources - .iter() - .map(|(identity, _)| identity.clone()) - .collect::>(); - drop(sources); + assert!(!inner.get_cached_info.contains_key(key)); + assert!(inner.local_visible_mem_holder(key).is_none()); + assert!( + acquire_external_pending_put_fence_for_key(&inner.owner_key_control, key).is_err(), + "a new local Put must not cross a source-selection fence" + ); + drop(source); let master_id = master .cluster_manager_view() .cluster_manager() @@ -4360,11 +4260,8 @@ mod owner_reclaim_slot_tests { .id; let mismatched = OwnerReclaimItem { - key: identities[0].key.clone(), - put_id: ( - identities[0].put_time_ms, - identities[0].put_version.wrapping_add(1), - ), + key: identity.key.clone(), + put_id: (identity.put_time_ms, identity.put_version.wrapping_add(1)), epoch: 90, backing: OwnerReclaimBacking::Allocation, reason: OwnerReclaimReason::OwnerCapacityEviction, @@ -4388,29 +4285,25 @@ mod owner_reclaim_slot_tests { assert!( inner .owner_key_control - .lock_key(&identities[0].key) - .get(&identities[0].key) + .lock_key(&identity.key) + .get(&identity.key) .is_some_and(|state| state.source_eviction_selection.is_some()), "a mismatched Prepare must not consume the owner selection" ); - let matching = identities - .iter() - .enumerate() - .map(|(index, identity)| OwnerReclaimItem { - key: identity.key.clone(), - put_id: (identity.put_time_ms, identity.put_version), - epoch: 100 + index as u64, - backing: OwnerReclaimBacking::Allocation, - reason: OwnerReclaimReason::OwnerCapacityEviction, - }) - .collect::>(); + let matching = OwnerReclaimItem { + key: identity.key.clone(), + put_id: (identity.put_time_ms, identity.put_version), + epoch: 100, + backing: OwnerReclaimBacking::Allocation, + reason: OwnerReclaimReason::OwnerCapacityEviction, + }; let prepare_resp = super::reclaim::handle_batch_owner_reclaim( &owner_view, MsgPack { serialize_part: BatchOwnerReclaimReq { phase: OwnerReclaimPhase::Prepare, - items: matching.clone(), + items: vec![matching.clone()], }, raw_bytes: Vec::new(), }, @@ -4418,84 +4311,94 @@ mod owner_reclaim_slot_tests { ) .await; assert!( - prepare_resp - .serialize_part - .items - .iter() - .all(|item| item.state == OwnerReclaimItemState::Prepared), - "matching Prepare must atomically promote each selection into reclaim" + prepare_resp.serialize_part.items[0].state == OwnerReclaimItemState::Prepared, + "matching Prepare must promote the single selection into reclaim" ); - for key in keys { - assert!(inner.local_visible_mem_holder(key).is_none()); - } + assert!(inner.local_visible_mem_holder(key).is_none()); let abort_resp = super::reclaim::handle_batch_owner_reclaim( &owner_view, MsgPack { serialize_part: BatchOwnerReclaimReq { phase: OwnerReclaimPhase::Abort, - items: matching, + items: vec![matching], }, raw_bytes: Vec::new(), }, master_id.into(), ) .await; + assert!(abort_resp.serialize_part.items[0].state == OwnerReclaimItemState::Aborted); assert!( - abort_resp - .serialize_part - .items - .iter() - .all(|item| item.state == OwnerReclaimItemState::Aborted) + inner.local_visible_mem_holder(key).is_some(), + "Abort must restore the exact committed local index" ); - for key in keys { - assert!( - inner.local_visible_mem_holder(key).is_some(), - "Abort must restore the exact committed local index" - ); - } - let group = PutAtomicGroup { - members: identities - .iter() - .map(|identity| PutAtomicGroupMember { - key: identity.key.clone(), - put_id: (identity.put_time_ms, identity.put_version), - }) - .collect(), - }; - inner.owner_hot_register_atomic_group(&group); let trigger_weak = { let cached = inner .get_cached_info - .get(&identities[0].key) + .get(key) .expect("Abort-restored trigger must be indexed"); Arc::downgrade(&cached.mem_holder) }; let retry_event = OwnerHotEvictionEvent { - key: identities[0].key.clone(), - put_id: (identities[0].put_time_ms, identities[0].put_version), + key: identity.key.clone(), + put_id: (identity.put_time_ms, identity.put_version), memory_info: trigger_weak, selection_debt: OwnerHotSelectionDebt::new( 4096, inner.owner_hot_counters.selection_debt_bytes.clone(), ), retry: true, - source_eviction_atomic_batch: None, + source_eviction_victim: None, retry_failures: 1, }; match inner.owner_hot_prepare_eviction(&retry_event) { - super::OwnerHotEvictionPreparation::Ready { sources, .. } => { - assert_eq!( - sources.len(), - identities.len(), - "a pre-selection retry must resolve the complete atomic atomic_batch" - ); + super::OwnerHotEvictionPreparation::Ready { trigger, source } => { + assert_eq!(trigger, identity); + assert_eq!(source.key, key); } - _ => panic!("a pre-selection retry with a complete atomic_batch must be ready"), + _ => panic!("a current single-key retry must be ready"), } retry_event.selection_debt.release(); + let cached = inner + .get_cached_info + .get(key) + .expect("the aborted source must still be locally indexed"); + let source = cached.mem_holder.clone(); + drop(cached); + assert!(matches!( + inner.owner_hot_install_source_selection_fence(&identity, &source), + OwnerHotSelectionFenceOutcome::Fenced + )); + drop(source); + assert!( + inner.owner_hot_install_source_selection_debt( + identity.clone(), + OwnerHotSelectionDebt::new( + 4096, + inner.owner_hot_counters.selection_debt_bytes.clone(), + ), + ) + ); + super::reclaim::complete_owner_source_eviction( + inner, + &OwnerSourceEvictionVictim { + key: key.to_string(), + put_id: (identity.put_time_ms, identity.put_version), + backing: OwnerReclaimBacking::Allocation, + }, + 101, + ) + .expect("one direct-delete response must release and finalize the local source"); + assert!(inner.local_visible_mem_holder(key).is_none()); + assert!(!inner.owner_source_eviction_selected.contains_key(&identity)); + assert!( + inner.owner_key_control.lock_key(key).get(key).is_none(), + "direct local completion must clear the source fence in one call" + ); + stop_master_and_client(master, client).await; } @@ -4559,7 +4462,7 @@ mod owner_reclaim_slot_tests { memory_info: Weak::new(), selection_debt: debt, retry: true, - source_eviction_atomic_batch: None, + source_eviction_victim: None, retry_failures: 0, }; retry_queue.schedule(event.clone(), "first failure"); @@ -4603,7 +4506,7 @@ mod owner_reclaim_slot_tests { memory_info: Weak::new(), selection_debt: debt, retry: true, - source_eviction_atomic_batch: None, + source_eviction_victim: None, retry_failures: 0, }; @@ -4644,7 +4547,7 @@ mod owner_reclaim_slot_tests { memory_info: Weak::new(), selection_debt: remove_debt, retry: true, - source_eviction_atomic_batch: None, + source_eviction_victim: None, retry_failures: 0, }; for _ in 0..CHURN { @@ -4658,77 +4561,6 @@ mod owner_reclaim_slot_tests { assert_eq!(counters.selection_debt_bytes.load(Ordering::Acquire), 0); } - #[test] - fn hot_atomic_group_registry_interns_members_and_forgets_as_one_unit() { - let group = PutAtomicGroup { - members: vec![ - PutAtomicGroupMember { - key: "group-a".to_string(), - put_id: (10, 1), - }, - PutAtomicGroupMember { - key: "group-b".to_string(), - put_id: (10, 2), - }, - ], - }; - let atomic_groups = DashMap::new(); - register_owner_hot_atomic_group(&atomic_groups, &group); - register_owner_hot_atomic_group(&atomic_groups, &group); - assert_eq!(atomic_groups.len(), 2); - - let first = OwnerHotReplicaIdentity::from_group_member(&group.members[0]); - let second = OwnerHotReplicaIdentity::from_group_member(&group.members[1]); - let first_group = atomic_groups.get(&first).unwrap().value().clone(); - let second_group = atomic_groups.get(&second).unwrap().value().clone(); - assert!(Arc::ptr_eq(&first_group, &second_group)); - - forget_owner_hot_atomic_group(&atomic_groups, &second); - assert!(atomic_groups.is_empty()); - } - - #[test] - fn owner_hot_tp_atomic_batch_expands_the_same_group_boundary_across_ranks() { - let identity = OwnerHotReplicaIdentity { - key: "page0_model_0_2".to_string(), - put_time_ms: 10, - put_version: 1, - }; - let rank0_group = PutAtomicGroup { - members: vec![ - PutAtomicGroupMember { - key: "page0_model_0_2".to_string(), - put_id: (10, 1), - }, - PutAtomicGroupMember { - key: "page1_model_0_2".to_string(), - put_id: (10, 2), - }, - ], - }; - assert_eq!( - owner_hot_tp_atomic_batch_key_rows(&identity, Some(&rank0_group)), - Ok(Some(vec![ - vec!["page0_model_0_2".to_string(), "page1_model_0_2".to_string(),], - vec!["page0_model_1_2".to_string(), "page1_model_1_2".to_string(),], - ])) - ); - - let mixed_rank_group = PutAtomicGroup { - members: vec![ - rank0_group.members[0].clone(), - PutAtomicGroupMember { - key: "page1_model_1_2".to_string(), - put_id: (11, 2), - }, - ], - }; - assert_eq!( - owner_hot_tp_atomic_batch_key_rows(&identity, Some(&mixed_rank_group)), - Err(()) - ); - } - #[test] fn hot_cache_only_dispatches_size_removals_and_keeps_capacity() { let counters = Arc::new(OwnerHotCacheCounters::default()); @@ -4756,9 +4588,12 @@ mod owner_reclaim_slot_tests { cache.run_pending_tasks(); assert!(counters.size_evictions.load(Ordering::Relaxed) >= 1); assert_eq!(cache.max_capacity(), Some(10)); - let event = rx + let dispatch = rx .try_recv() .expect("the Moka listener must emit lightweight metadata without pinning"); + let OwnerHotEvictionDispatch::Victim(event) = dispatch else { + panic!("the Moka listener must emit a victim event") + }; assert!(event.memory_info.upgrade().is_none()); } @@ -4775,6 +4610,7 @@ mod owner_reclaim_slot_tests { OwnerKeyControlState { local_puts: 0, external_pending_puts: 0, + external_put: None, source_eviction_selection: None, reclaim: Some(OwnerReclaimRecord::Committed(OwnerReclaimItem { key: "fenced".to_string(), @@ -5241,14 +5077,13 @@ impl ClientKvApiInner { .owner_hot_counters .skipped_active_holders .load(Ordering::Relaxed), - hot_group_registry_entries: self.owner_hot_atomic_groups.len() as u64, - hot_group_trigger_duplicates: self + hot_victim_duplicates: self .owner_hot_counters - .group_trigger_duplicates + .victim_duplicates .load(Ordering::Relaxed), - hot_group_trigger_incomplete: self + hot_victim_invalid_backing: self .owner_hot_counters - .group_trigger_incomplete + .victim_invalid_backing .load(Ordering::Relaxed), grouped_put_done_batches: self .owner_hot_counters @@ -5810,9 +5645,8 @@ impl ClientKvApi { skipped_stale = snapshot.hot_eviction_skipped_stale, skipped_reclaim = snapshot.hot_eviction_skipped_reclaim, skipped_active_holders = snapshot.hot_eviction_skipped_active_holders, - group_registry_entries = snapshot.hot_group_registry_entries, - group_trigger_duplicates = snapshot.hot_group_trigger_duplicates, - group_trigger_incomplete = snapshot.hot_group_trigger_incomplete, + victim_duplicates = snapshot.hot_victim_duplicates, + victim_invalid_backing = snapshot.hot_victim_invalid_backing, grouped_put_done_batches = snapshot.grouped_put_done_batches, grouped_put_done_items = snapshot.grouped_put_done_items, legacy_put_done_batches = snapshot.legacy_put_done_batches, @@ -5843,14 +5677,13 @@ impl ClientKvApi { // The Moka eviction listener is synchronous and must never block while // holding Moka's housekeeper lock. Events contain only weak payload // references and are deduplicated by exact selected identities, so use - // a lossless metadata channel instead of dropping atomic_batches when the old + // a lossless metadata channel instead of dropping victims when the old // bounded queue briefly filled under cache pressure. let (owner_hot_eviction_tx, owner_hot_eviction_rx) = tokio::sync::ampsc::unbounded_channel(); let get_cached_info = Arc::new(DashMap::new()); let owner_key_control = Arc::new(OwnerKeyControlTable::default()); let owner_source_eviction_selected = Arc::new(DashMap::new()); - let owner_hot_atomic_groups = Arc::new(DashMap::new()); let owner_hot_counters = Arc::new(OwnerHotCacheCounters::default()); let owner_hot_retry_queue = Arc::new(OwnerHotRetryQueue::new(owner_hot_counters.clone())); let owner_hot_cache = owner_hot_cache_capacity_bytes.map(|capacity_bytes| { @@ -5882,7 +5715,6 @@ impl ClientKvApi { owner_key_control, owner_hot_cache, owner_source_eviction_selected, - owner_hot_atomic_groups, owner_hot_counters, owner_hot_retry_queue, owner_hot_eviction_tx, diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs index 862adab..8c70d68 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs @@ -1,10 +1,9 @@ use super::{ - ClientKvApiInner, OwnerHotEvictionEvent, OwnerHotEvictionPreparation, OwnerHotSelectionDebt, + ClientKvApiInner, OwnerHotEvictionEvent, OwnerHotEvictionPreparation, OwnerHotSelectionFenceOutcome, OwnerLocalReserveClassState, OwnerLocalReserveGrantState, OwnerLocalReservePoolState, OwnerLocalReserveSlotLease, OwnerLocalReserveSlotRef, ReplicaTaskJob, ReplicaTaskTarget, local_reserve_rebalance::{owner_local_reserve_timeout_config, wait_owner_local_reserve_ready}, - owner_hot_weight_bytes, }; use crate::OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES; use crate::cluster_manager::NodeIDString; @@ -27,11 +26,12 @@ use crate::{ BatchPutStartItemReq, BatchPutStartReq, BatchPutStartResp, BatchReleasePutKeyReservationsReq, BatchReleasePutKeyReservationsResp, EnqueueReplicaTaskItemResp, GroupedBatchPutDoneItemReq, GroupedBatchPutDoneReq, - GroupedBatchPutDoneResp, OwnerReclaimBacking, OwnerSourceEvictionAtomicBatch, - OwnerSourceEvictionMember, OwnerSourceEvictionOutcome, PutAppendDoneReq, PutAppendDoneResp, - PutAppendRevokeReq, PutAppendStartOutcome, PutAppendStartReq, PutAppendStartResp, - PutAtomicGroup, PutDoneCommittedSlot, PutDoneReq, PutRevokeReq, PutStartReq, PutStartResp, + GroupedBatchPutDoneResp, OwnerReclaimBacking, OwnerSourceEvictionOutcome, + OwnerSourceEvictionVictim, PutAppendDoneReq, PutAppendDoneResp, PutAppendRevokeReq, + PutAppendStartOutcome, PutAppendStartReq, PutAppendStartResp, PutAtomicGroup, + PutDoneCommittedSlot, PutDoneReq, PutRevokeReq, PutStartReq, PutStartResp, ReleaseLocalGrantReq, ReserveLocalGrantOutcome, ReserveLocalGrantReq, + owner_source_eviction_epoch, }, memholder::{UserMemHolder, UserMemHolderExposeKind}, p2p::msg_pack::MsgPack, @@ -2225,12 +2225,12 @@ impl ClientKvApiInner { pub async fn batch_evict_owner_source( &self, - atomic_batches: Vec, + victims: Vec, ) -> KvResult { - if atomic_batches.is_empty() { + if victims.is_empty() { return Ok(BatchEvictOwnerSourceResp { operation_id: 0, - atomic_batches: Vec::new(), + victims: Vec::new(), error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, error_json: String::new(), }); @@ -2248,7 +2248,7 @@ impl ClientKvApiInner { serialize_part: BatchEvictOwnerSourceReq { operation_id, owner_node_start_time: self_info.node_start_time, - atomic_batches, + victims, }, raw_bytes: Vec::new(), }; @@ -2960,21 +2960,21 @@ async fn start_replica_append_with_retry( } fn owner_source_eviction_identity( - member: &OwnerSourceEvictionMember, + victim: &OwnerSourceEvictionVictim, ) -> super::OwnerHotReplicaIdentity { super::OwnerHotReplicaIdentity { - key: member.key.clone(), - put_time_ms: member.put_id.0, - put_version: member.put_id.1, + key: victim.key.clone(), + put_time_ms: victim.put_id.0, + put_version: victim.put_id.1, } } -fn owner_source_eviction_member( +fn owner_source_eviction_victim( identity: &super::OwnerHotReplicaIdentity, memory_info: &crate::memholder::MemoryInfo, -) -> Option { +) -> Option { let (slot_size, grant_id, slot_index) = memory_info.local_reserve_resident_slot_ref()?; - Some(OwnerSourceEvictionMember { + Some(OwnerSourceEvictionVictim { key: identity.key.clone(), put_id: (identity.put_time_ms, identity.put_version), backing: OwnerReclaimBacking::CommittedSlot { @@ -2987,55 +2987,49 @@ fn owner_source_eviction_member( fn finish_owner_source_selection( inner: &ClientKvApiInner, - atomic_batch: &OwnerSourceEvictionAtomicBatch, + victim: &OwnerSourceEvictionVictim, restore_current: bool, reason: &str, ) { - for member in &atomic_batch.members { - let identity = owner_source_eviction_identity(member); - if let Some(debt) = inner.owner_hot_remove_source_selection_debt(&identity) { - debt.release(); - inner - .owner_hot_counters - .source_evict_restored_members - .fetch_add(1, Ordering::Relaxed); - } - inner.owner_hot_retry_queue.remove(&identity); - if !restore_current { - continue; - } - inner.owner_hot_restore_source_selection(&identity); - let group = inner - .owner_hot_atomic_groups - .get(&identity) - .map(|entry| entry.value().clone()); - if inner.owner_hot_admit_published_committed(&member.key, member.put_id, group.as_deref()) { - tracing::warn!( - key = member.key, - put_time_ms = member.put_id.0, - put_version = member.put_id.1, - reason, - "restored current source to owner-hot after source eviction did not enter reclaim" - ); - } + let identity = owner_source_eviction_identity(victim); + if let Some(debt) = inner.owner_hot_remove_source_selection_debt(&identity) { + debt.release(); + inner + .owner_hot_counters + .source_evict_restored_members + .fetch_add(1, Ordering::Relaxed); + } + inner.owner_hot_retry_queue.remove(&identity); + if !restore_current { + return; + } + inner.owner_hot_restore_source_selection(&identity); + if inner.owner_hot_admit_published_committed(&victim.key, victim.put_id) { + tracing::warn!( + key = victim.key, + put_time_ms = victim.put_id.0, + put_version = victim.put_id.1, + reason, + "restored current source to owner-hot after source eviction did not enter reclaim" + ); } } fn schedule_owner_source_eviction_retry( inner: &ClientKvApiInner, mut event: OwnerHotEvictionEvent, - atomic_batch: Arc, + victim: Arc, reason: &'static str, ) { event.retry = true; - event.source_eviction_atomic_batch = Some(atomic_batch); + event.source_eviction_victim = Some(victim); inner.owner_hot_retry_queue.schedule(event, reason); } fn prepare_owner_source_eviction_event( inner: &ClientKvApiInner, mut event: OwnerHotEvictionEvent, -) -> Option<(OwnerHotEvictionEvent, Arc)> { +) -> Option<(OwnerHotEvictionEvent, Arc)> { let trigger = super::OwnerHotReplicaIdentity { key: event.key.clone(), put_time_ms: event.put_id.0, @@ -3045,22 +3039,15 @@ fn prepare_owner_source_eviction_event( if event.retry { let _ = inner.owner_hot_retry_queue.take_for_inflight(&trigger); } - if let Some(atomic_batch) = event.source_eviction_atomic_batch.clone() { - if atomic_batch.members.iter().all(|member| { - inner - .owner_source_eviction_selected - .contains_key(&owner_source_eviction_identity(member)) - }) { - return Some((event, atomic_batch)); + if let Some(victim) = event.source_eviction_victim.clone() { + if inner + .owner_source_eviction_selected + .contains_key(&owner_source_eviction_identity(&victim)) + { + return Some((event, victim)); } - // Commit/invalidation may win the race with a due retry. Any remaining - // selected members are restored rather than leaving false projected credit. - finish_owner_source_selection( - inner, - &atomic_batch, - true, - "retry atomic_batch lost selected identity", - ); + // Commit/invalidation may win the race with a due retry. + finish_owner_source_selection(inner, &victim, true, "retry victim lost selected identity"); event.selection_debt.release(); return None; } @@ -3069,13 +3056,13 @@ fn prepare_owner_source_eviction_event( event.selection_debt.release(); inner .owner_hot_counters - .group_trigger_duplicates + .victim_duplicates .fetch_add(1, Ordering::Relaxed); return None; } - let (resolved_trigger, sources) = match inner.owner_hot_prepare_eviction(&event) { - OwnerHotEvictionPreparation::Ready { trigger, sources } => (trigger, sources), + let (resolved_trigger, source) = match inner.owner_hot_prepare_eviction(&event) { + OwnerHotEvictionPreparation::Ready { trigger, source } => (trigger, source), OwnerHotEvictionPreparation::RetryableReclaimFence => { inner.owner_hot_retry_queue.schedule( event, @@ -3083,39 +3070,24 @@ fn prepare_owner_source_eviction_event( ); return None; } - OwnerHotEvictionPreparation::RetryableIncompleteAtomicBatch => { - inner - .owner_hot_retry_queue - .schedule(event, "owner source atomic_batch is temporarily incomplete"); - return None; - } - OwnerHotEvictionPreparation::TemporarilyPinned { active_members } => { - // This event was removed from Moka, but its source atomic_batch is still + OwnerHotEvictionPreparation::TemporarilyPinned => { + // This event was removed from Moka, but its source is still // serving a local reader. Do not hand it to the master's reclaim // loop and do not retain projected selection credit. Re-admission // refreshes the trigger's recency so the next pressure kick can // choose a different, currently reclaimable victim. event.selection_debt.release(); - inner.owner_hot_counters.skipped_active_holders.fetch_add( - u64::try_from(active_members).unwrap_or(u64::MAX), - Ordering::Relaxed, - ); - let group = inner - .owner_hot_atomic_groups - .get(&trigger) - .map(|entry| entry.value().clone()); - let restored = inner.owner_hot_admit_published_committed( - &event.key, - event.put_id, - group.as_deref(), - ); + inner + .owner_hot_counters + .skipped_active_holders + .fetch_add(1, Ordering::Relaxed); + let restored = inner.owner_hot_admit_published_committed(&event.key, event.put_id); tracing::debug!( key = event.key, put_time_ms = event.put_id.0, put_version = event.put_id.1, - active_members, restored, - "owner pressure eviction skipped an actively held source atomic_batch" + "owner pressure eviction skipped an actively held source" ); return None; } @@ -3130,15 +3102,11 @@ fn prepare_owner_source_eviction_event( }; debug_assert_eq!(resolved_trigger, trigger); - let members = sources - .iter() - .map(|(identity, memory_info)| owner_source_eviction_member(identity, memory_info.as_ref())) - .collect::>>(); - let Some(members) = members else { + let Some(victim) = owner_source_eviction_victim(&trigger, source.as_ref()) else { event.selection_debt.release(); inner .owner_hot_counters - .group_trigger_incomplete + .victim_invalid_backing .fetch_add(1, Ordering::Relaxed); tracing::error!( key = event.key, @@ -3148,9 +3116,9 @@ fn prepare_owner_source_eviction_event( ); return None; }; - let atomic_batch = Arc::new(OwnerSourceEvictionAtomicBatch { members }); + let victim = Arc::new(victim); - match inner.owner_hot_install_source_selection_fences(&sources) { + match inner.owner_hot_install_source_selection_fence(&trigger, &source) { OwnerHotSelectionFenceOutcome::Fenced => {} OwnerHotSelectionFenceOutcome::Retryable => { inner @@ -3158,17 +3126,13 @@ fn prepare_owner_source_eviction_event( .schedule(event, "owner source selection fence is temporarily busy"); return None; } - OwnerHotSelectionFenceOutcome::TemporarilyPinned { active_members } => { + OwnerHotSelectionFenceOutcome::TemporarilyPinned => { event.selection_debt.release(); - inner.owner_hot_counters.skipped_active_holders.fetch_add( - u64::try_from(active_members).unwrap_or(u64::MAX), - Ordering::Relaxed, - ); - let group = inner - .owner_hot_atomic_groups - .get(&trigger) - .map(|entry| entry.value().clone()); - inner.owner_hot_admit_published_committed(&event.key, event.put_id, group.as_deref()); + inner + .owner_hot_counters + .skipped_active_holders + .fetch_add(1, Ordering::Relaxed); + inner.owner_hot_admit_published_committed(&event.key, event.put_id); return None; } OwnerHotSelectionFenceOutcome::Obsolete => { @@ -3181,52 +3145,24 @@ fn prepare_owner_source_eviction_event( } } - if atomic_batch.members.iter().any(|member| { - inner - .owner_source_eviction_selected - .contains_key(&owner_source_eviction_identity(member)) - }) { - for member in &atomic_batch.members { - inner.owner_hot_restore_source_selection(&owner_source_eviction_identity(member)); - } + if inner.owner_source_eviction_selected.contains_key(&trigger) { + inner.owner_hot_restore_source_selection(&trigger); event.selection_debt.release(); inner .owner_hot_counters - .group_trigger_duplicates + .victim_duplicates .fetch_add(1, Ordering::Relaxed); return None; } - let mut installed = Vec::with_capacity(atomic_batch.members.len()); - for ((identity, memory_info), member) in sources.iter().zip(atomic_batch.members.iter()) { - debug_assert_eq!(identity, &owner_source_eviction_identity(member)); - let debt = if identity == &trigger { - event.selection_debt.clone() - } else { - OwnerHotSelectionDebt::new( - u64::from(owner_hot_weight_bytes(memory_info.as_ref())), - inner.owner_hot_counters.selection_debt_bytes.clone(), - ) - }; - if !inner.owner_hot_install_source_selection_debt(identity.clone(), debt.clone()) { - debt.release(); - for installed_identity in installed { - if let Some(installed_debt) = - inner.owner_hot_remove_source_selection_debt(&installed_identity) - { - installed_debt.release(); - } - } - for member in &atomic_batch.members { - inner.owner_hot_restore_source_selection(&owner_source_eviction_identity(member)); - } - event.selection_debt.release(); - return None; - } - installed.push(identity.clone()); + if !inner.owner_hot_install_source_selection_debt(trigger.clone(), event.selection_debt.clone()) + { + inner.owner_hot_restore_source_selection(&trigger); + event.selection_debt.release(); + return None; } - event.source_eviction_atomic_batch = Some(atomic_batch.clone()); - Some((event, atomic_batch)) + event.source_eviction_victim = Some(victim.clone()); + Some((event, victim)) } async fn process_owner_source_eviction_events( @@ -3241,44 +3177,44 @@ async fn process_owner_source_eviction_events( if prepared.is_empty() { return; } - let atomic_batches = prepared + let victims = prepared .iter() - .map(|(_, atomic_batch)| atomic_batch.as_ref().clone()) + .map(|(_, victim)| victim.as_ref().clone()) .collect::>(); - let response = inner.batch_evict_owner_source(atomic_batches).await; + let response = inner.batch_evict_owner_source(victims).await; let Ok(response) = response else { - for (event, atomic_batch) in prepared { + for (event, victim) in prepared { schedule_owner_source_eviction_retry( inner, event, - atomic_batch, + victim, "owner source-eviction RPC failed", ); } return; }; - if response.atomic_batches.len() != prepared.len() { - for (event, atomic_batch) in prepared { + if response.victims.len() != prepared.len() { + for (event, victim) in prepared { schedule_owner_source_eviction_retry( inner, event, - atomic_batch, + victim, "owner source-eviction response length mismatch", ); } return; } - for (index, ((event, atomic_batch), result)) in prepared + for (index, ((event, victim), result)) in prepared .into_iter() - .zip(response.atomic_batches.into_iter()) + .zip(response.victims.into_iter()) .enumerate() { - if result.atomic_batch_index != u32::try_from(index).unwrap_or(u32::MAX) { + if result.victim_index != u32::try_from(index).unwrap_or(u32::MAX) { schedule_owner_source_eviction_retry( inner, event, - atomic_batch, + victim, "owner source-eviction response identity mismatch", ); continue; @@ -3289,45 +3225,63 @@ async fn process_owner_source_eviction_events( inner .owner_hot_counters .source_evict_handoff_members - .fetch_add(atomic_batch.members.len() as u64, Ordering::Relaxed); + .fetch_add(1, Ordering::Relaxed); // Selected debt stays live until owner reclaim Commit calls - // owner_hot_invalidate_version for every exact member. + // owner_hot_invalidate_version for the exact victim. } OwnerSourceEvictionOutcome::Completed => { - finish_owner_source_selection( - inner, - &atomic_batch, - true, - "master reported source deletion already completed", - ); + let epoch = owner_source_eviction_epoch(response.operation_id, index); + match super::reclaim::complete_owner_source_eviction(inner, &victim, epoch) { + Ok(()) => { + inner + .owner_hot_counters + .source_evict_handoff_members + .fetch_add(1, Ordering::Relaxed); + } + Err(detail) => { + tracing::warn!( + key = victim.key, + put_time_ms = victim.put_id.0, + put_version = victim.put_id.1, + detail, + "master deleted source route but owner slot release must retry" + ); + schedule_owner_source_eviction_retry( + inner, + event, + victim, + "owner slot release after master direct-delete is temporarily busy", + ); + } + } } OwnerSourceEvictionOutcome::RetryableBusy | OwnerSourceEvictionOutcome::Unspecified => { schedule_owner_source_eviction_retry( inner, event, - atomic_batch, + victim, "master source reclaim is temporarily busy", ); } OwnerSourceEvictionOutcome::Stale => { finish_owner_source_selection( inner, - &atomic_batch, + &victim, true, "master rejected stale source identity", ); } OwnerSourceEvictionOutcome::RejectedNotEvictable => { tracing::error!( - atomic_batch_members = atomic_batch.members.len(), + key = victim.key, detail = result.detail, - "owner selected a source atomic_batch that master declared non-evictable" + "owner selected a source victim that master declared non-evictable" ); finish_owner_source_selection( inner, - &atomic_batch, + &victim, true, - "master rejected non-evictable source atomic_batch", + "master rejected non-evictable source victim", ); } } @@ -3336,39 +3290,87 @@ async fn process_owner_source_eviction_events( pub fn spawn_owner_source_eviction_dispatcher( view: ClientKvApiView, - mut rx: tokio::sync::ampsc::UnboundedReceiver, + mut rx: tokio::sync::ampsc::UnboundedReceiver, ) { - const MAX_ATOMIC_BATCHES_PER_RPC: usize = 128; - const MERGE_WINDOW: Duration = Duration::from_millis(2); + const ORPHAN_MERGE_WINDOW: Duration = Duration::from_millis(2); let view_task = view.clone(); let _ = view.spawn("owner_source_eviction_dispatcher", async move { let mut shutdown_waiter = view_task.register_shutdown_waiter(); + let mut events = Vec::new(); + let mut pressure_open = false; loop { - let first = tokio::select! { - _ = shutdown_waiter.wait() => { - tracing::info!("owner source-eviction dispatcher stopping due to shutdown"); - break; + let dispatch = if events.is_empty() || pressure_open { + tokio::select! { + _ = shutdown_waiter.wait() => { + tracing::info!("owner source-eviction dispatcher stopping due to shutdown"); + break; + } + dispatch = rx.recv() => dispatch, + } + } else { + tokio::select! { + _ = shutdown_waiter.wait() => { + tracing::info!("owner source-eviction dispatcher stopping due to shutdown"); + break; + } + dispatch = rx.recv() => dispatch, + _ = tokio::time::sleep(ORPHAN_MERGE_WINDOW) => { + process_owner_source_eviction_events( + &view_task, + std::mem::take(&mut events), + ) + .await; + continue; + } } - event = rx.recv() => { - let Some(event) = event else { break; }; - event + }; + let Some(dispatch) = dispatch else { + if !events.is_empty() { + process_owner_source_eviction_events(&view_task, std::mem::take(&mut events)) + .await; } + break; }; - let mut events = Vec::with_capacity(MAX_ATOMIC_BATCHES_PER_RPC); - events.push(first); - let merge_window = tokio::time::sleep(MERGE_WINDOW); - tokio::pin!(merge_window); - while events.len() < MAX_ATOMIC_BATCHES_PER_RPC { - tokio::select! { - _ = &mut merge_window => break, - event = rx.recv() => { - let Some(event) = event else { break; }; - events.push(event); + match dispatch { + super::OwnerHotEvictionDispatch::Victim(event) => events.push(event), + super::OwnerHotEvictionDispatch::BeginPressure { requested_bytes } => { + if pressure_open { + tracing::error!( + requested_bytes, + "nested owner pressure selection batch is not allowed" + ); + } + if !events.is_empty() { + process_owner_source_eviction_events( + &view_task, + std::mem::take(&mut events), + ) + .await; + } + pressure_open = true; + } + super::OwnerHotEvictionDispatch::EndPressure { selected_bytes } => { + if !pressure_open { + tracing::warn!( + selected_bytes, + "owner pressure selection ended without a matching begin marker" + ); + } + pressure_open = false; + process_owner_source_eviction_events(&view_task, std::mem::take(&mut events)) + .await; + } + super::OwnerHotEvictionDispatch::Flush => { + if !pressure_open && !events.is_empty() { + process_owner_source_eviction_events( + &view_task, + std::mem::take(&mut events), + ) + .await; } } } - process_owner_source_eviction_events(&view_task, events).await; } }); } @@ -3399,8 +3401,13 @@ pub fn spawn_owner_hot_retry_actor(view: ClientKvApiView) { } let inner = view_task.client_kv_api().inner(); for event in events { - if let Err(err) = inner.owner_hot_eviction_tx.send(event) { - let event = err.0; + if let Err(err) = inner + .owner_hot_eviction_tx + .send(super::OwnerHotEvictionDispatch::Victim(event)) + { + let super::OwnerHotEvictionDispatch::Victim(event) = err.0 else { + unreachable!("the retry actor only sends victim events") + }; retry_queue.schedule(event, "retry dispatcher closed"); return; } @@ -3409,6 +3416,13 @@ pub fn spawn_owner_hot_retry_actor(view: ClientKvApiView) { .source_evict_retry_emitted .fetch_add(1, Ordering::Relaxed); } + if inner + .owner_hot_eviction_tx + .send(super::OwnerHotEvictionDispatch::Flush) + .is_err() + { + return; + } } }); } @@ -4236,11 +4250,7 @@ pub(crate) async fn publish_owner_local_job(view: ClientKvApiView, job: OwnerLoc ); continue; } - let _ = inner.owner_hot_admit_published_committed( - &item.key, - item.put_id, - item.atomic_group.as_ref(), - ); + let _ = inner.owner_hot_admit_published_committed(&item.key, item.put_id); } for item in promoted_items { @@ -4264,6 +4274,10 @@ pub(crate) async fn publish_owner_local_job(view: ClientKvApiView, job: OwnerLoc } } } + + for context in &job.external_pending_contexts { + context._pending_fence.mark_local_put_succeeded(); + } } release_owner_local_publish_reservations(inner, job.key_reservation_ids).await; diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs index 0071968..97b36a0 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs @@ -2,7 +2,8 @@ use super::{ClientKvApiInner, ClientKvApiView, OwnerPreparedReclaim, OwnerReclai use crate::cluster_manager::{NodeID, NodeRole}; use crate::master_kv_router::msg_pack::{ BatchOwnerReclaimReq, BatchOwnerReclaimResp, OwnerReclaimBacking, OwnerReclaimItem, - OwnerReclaimItemResp, OwnerReclaimItemState, OwnerReclaimPhase, + OwnerReclaimItemResp, OwnerReclaimItemState, OwnerReclaimPhase, OwnerReclaimReason, + OwnerSourceEvictionVictim, }; use crate::p2p::msg_pack::MsgPack; use crate::rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, OK}; @@ -391,6 +392,7 @@ mod tests { let state = OwnerKeyControlState { local_puts: 0, external_pending_puts: 0, + external_put: None, source_eviction_selection: None, reclaim: Some(OwnerReclaimRecord::Releasing(item.clone())), external_get: Some(Arc::new(ExternalGetKeySharedOp::new( @@ -402,6 +404,7 @@ mod tests { let local_put_state = OwnerKeyControlState { local_puts: 1, external_pending_puts: 0, + external_put: None, source_eviction_selection: None, reclaim: Some(OwnerReclaimRecord::Releasing(item.clone())), external_get: state.external_get, @@ -522,6 +525,41 @@ fn finalize_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerRecla } } +pub(crate) fn complete_owner_source_eviction( + inner: &ClientKvApiInner, + victim: &OwnerSourceEvictionVictim, + epoch: u64, +) -> Result<(), String> { + let item = OwnerReclaimItem { + key: victim.key.clone(), + put_id: victim.put_id, + epoch, + backing: victim.backing.clone(), + reason: OwnerReclaimReason::OwnerCapacityEviction, + }; + let prepared = prepare_one(inner, &item); + match prepared.state { + OwnerReclaimItemState::Prepared => {} + OwnerReclaimItemState::Committed => { + let finalized = finalize_one(inner, &item); + return (finalized.state == OwnerReclaimItemState::Finalized) + .then_some(()) + .ok_or(finalized.detail); + } + OwnerReclaimItemState::Finalized => return Ok(()), + _ => return Err(prepared.detail), + } + + let committed = commit_one(inner, &item); + if committed.state != OwnerReclaimItemState::Committed { + return Err(committed.detail); + } + let finalized = finalize_one(inner, &item); + (finalized.state == OwnerReclaimItemState::Finalized) + .then_some(()) + .ok_or(finalized.detail) +} + pub async fn handle_batch_owner_reclaim( view: &ClientKvApiView, req: MsgPack, diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs index 2bc3846..3be65fe 100644 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs @@ -26,10 +26,9 @@ use self::{ BatchPutAppendStartReq, BatchPutDoneReq, BatchPutRevokeReq, BatchPutStartReq, BatchReleasePutKeyReservationsReq, CountPrefixReq, CountPrefixResp, DeleteAckReq, DeleteReq, GetAllocationMode, GetDoneReq, GetDoneResp, GetMetaReq, GetRevokeReq, - GetStartReq, GroupedBatchPutDoneReq, OwnerReclaimBacking, OwnerReclaimItem, - OwnerReclaimReason, PutAppendDoneReq, PutAppendRevokeReq, PutAppendStartReq, - PutAtomicGroup, PutDoneReq, PutRevokeReq, PutStartReq, ReleaseLocalGrantReq, - ReserveLocalGrantReq, + GetStartReq, GroupedBatchPutDoneReq, OwnerReclaimItem, PutAppendDoneReq, + PutAppendRevokeReq, PutAppendStartReq, PutAtomicGroup, PutDoneReq, PutRevokeReq, + PutStartReq, ReleaseLocalGrantReq, ReserveLocalGrantReq, }, placement::{PlacementPolicy, build_placement_policy}, put::{ @@ -299,7 +298,7 @@ pub struct ReplicaCacheNodeObserveSnapshot { pub reclaim_retry_restored: u64, pub reclaim_completed: u64, pub source_evict_rpc_requests: u64, - pub source_evict_atomic_batches: u64, + pub source_evict_victims: u64, pub source_evict_requested_bytes: u64, pub source_evict_accepted: u64, pub source_evict_in_progress: u64, @@ -487,7 +486,7 @@ pub(crate) struct EvictionReclaimCounters { pub retry_restored: AtomicU64, pub completed: AtomicU64, pub source_evict_rpc_requests: AtomicU64, - pub source_evict_atomic_batches: AtomicU64, + pub source_evict_victims: AtomicU64, pub source_evict_requested_bytes: AtomicU64, pub source_evict_accepted: AtomicU64, pub source_evict_in_progress: AtomicU64, @@ -505,7 +504,7 @@ pub(crate) struct EvictionReclaimCounters { /// More specific subset retained for diagnostics/backward-compatible /// metrics: the non-ring-B route used a CommittedSlot backing. pub capacity_eviction_hit_committed_slot: AtomicU64, - /// Duplicate listener/atomic_batch events suppressed while the same physical + /// Duplicate listener/victim events suppressed while the same physical /// cache version already has an outstanding reclaim lifecycle. pub eviction_reclaim_deduplicated: AtomicU64, } @@ -1307,76 +1306,6 @@ async fn cleanup_departed_generation_routes( ); } -const MAX_INFERRED_TP_ATOMIC_BATCH_SIZE: usize = 256; - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub(crate) struct InferredTpKey<'a> { - pub(crate) logical_prefix: &'a str, - pub(crate) rank: usize, - pub(crate) size: usize, -} - -/// Decode the canonical SGLang HiCache suffix `__`. -/// -/// This is deliberately strict and is only used to make owner reclaim more -/// conservative. A key that cannot be decoded keeps the existing non-TP -/// behavior; a decoded TP key whose peer routes are absent or inconsistent is -/// never considered recoverable. -pub(crate) fn infer_sglang_tp_key(key: &str) -> Option> { - let (before_size, raw_size) = key.rsplit_once('_')?; - let (logical_prefix, raw_rank) = before_size.rsplit_once('_')?; - if logical_prefix.is_empty() - || raw_rank.is_empty() - || raw_size.is_empty() - || !raw_rank.bytes().all(|byte| byte.is_ascii_digit()) - || !raw_size.bytes().all(|byte| byte.is_ascii_digit()) - { - return None; - } - let rank = raw_rank.parse::().ok()?; - let size = raw_size.parse::().ok()?; - if size == 0 - || size > MAX_INFERRED_TP_ATOMIC_BATCH_SIZE - || rank >= size - || raw_rank != rank.to_string() - || raw_size != size.to_string() - { - return None; - } - Some(InferredTpKey { - logical_prefix, - rank, - size, - }) -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -enum AtomicBatchExpansionError { - AtomicGroupIncomplete, - TpAtomicBatchIncomplete, -} - -fn take_exact_cache_entries( - cache: &MasterNodeCache, - expected_entries: &HashMap, -) -> Option> { - let mut removed_entries = Vec::with_capacity(expected_entries.len()); - for (candidate_key, expected_desc) in expected_entries { - let removed = cache.take_if(candidate_key, |entry| { - entry.put_id == expected_desc.put_id && entry.weight_bytes == expected_desc.weight_bytes - }); - if let Some(removed) = removed { - removed_entries.push((candidate_key.clone(), removed)); - } else { - for (removed_key, removed_desc) in removed_entries { - insert_master_cache_entry(cache, removed_key, removed_desc); - } - return None; - } - } - Some(removed_entries) -} - fn remove_exact_cache_entry( cache: &MasterNodeCache, key: &str, @@ -1394,72 +1323,11 @@ fn insert_master_cache_entry(cache: &MasterNodeCache, key: String, desc: NodeVal cache.insert(key, [alias], desc); } -fn current_atomic_group_members( - key: &str, - route: &OneKvNodesRoutes, - desc: &NodeValueReplicaDesc, -) -> Result, AtomicBatchExpansionError> { - let Some(group) = route.atomic_group.as_ref() else { - return Ok(vec![msg_pack::PutAtomicGroupMember { - key: key.to_string(), - put_id: desc.put_id, - }]); - }; - if !group - .members - .iter() - .any(|member| member.key == key && member.put_id == desc.put_id) - { - return Err(AtomicBatchExpansionError::AtomicGroupIncomplete); - } - Ok(group.members.clone()) -} - -fn current_tp_atomic_batch_keys( - key: &str, - route: &OneKvNodesRoutes, - desc: &NodeValueReplicaDesc, -) -> Result, AtomicBatchExpansionError> { - let current_members = current_atomic_group_members(key, route, desc)?; - let Some(key_tp) = infer_sglang_tp_key(key) else { - return Ok(current_members - .into_iter() - .map(|member| member.key) - .collect()); - }; - if key_tp.size == 1 { - return Ok(current_members - .into_iter() - .map(|member| member.key) - .collect()); - } - - let mut logical_members = Vec::with_capacity(current_members.len()); - for member in current_members { - let Some(member_tp) = infer_sglang_tp_key(&member.key) else { - return Err(AtomicBatchExpansionError::TpAtomicBatchIncomplete); - }; - if member_tp.rank != key_tp.rank || member_tp.size != key_tp.size { - return Err(AtomicBatchExpansionError::TpAtomicBatchIncomplete); - } - logical_members.push(member_tp.logical_prefix.to_string()); - } - - let mut atomic_batch_keys = Vec::with_capacity(logical_members.len() * key_tp.size); - for rank in 0..key_tp.size { - atomic_batch_keys.extend( - logical_members - .iter() - .map(|logical_prefix| format!("{logical_prefix}_{rank}_{}", key_tp.size)), - ); - } - Ok(atomic_batch_keys) -} - #[cfg(test)] mod tests { use super::*; use crate::cluster_manager::ClusterMember; + use crate::master_kv_router::msg_pack::{OwnerReclaimBacking, OwnerReclaimReason}; use std::collections::HashMap; #[test] @@ -1965,90 +1833,6 @@ mod tests { assert!(!member_left_can_forward_to_registration_actor(Some(17))); } - #[test] - fn infer_sglang_tp_key_accepts_only_canonical_suffix() { - assert_eq!( - infer_sglang_tp_key("prefix:page_model_1_2"), - Some(InferredTpKey { - logical_prefix: "prefix:page_model", - rank: 1, - size: 2, - }) - ); - assert!(infer_sglang_tp_key("prefix:page_model_2_2").is_none()); - assert!(infer_sglang_tp_key("prefix:page_model_01_2").is_none()); - assert!(infer_sglang_tp_key("prefix:page_model_x_2").is_none()); - assert!(infer_sglang_tp_key("prefix:page_model_0_0").is_none()); - } - - #[test] - fn tp_atomic_batch_expansion_preserves_every_atomic_member_across_ranks() { - let rank0_group = Arc::new(PutAtomicGroup { - members: vec![ - msg_pack::PutAtomicGroupMember { - key: "page0_model_0_2".to_string(), - put_id: (10, 0), - }, - msg_pack::PutAtomicGroupMember { - key: "page1_model_0_2".to_string(), - put_id: (10, 1), - }, - ], - }); - let mut rank0_page0 = test_route((10, 0), None, vec![("gpu0", false)]); - rank0_page0.atomic_group = Some(rank0_group); - let desc = NodeValueReplicaDesc { - weight_bytes: 1024, - put_id: (10, 0), - }; - assert_eq!( - current_tp_atomic_batch_keys("page0_model_0_2", &rank0_page0, &desc).unwrap(), - vec![ - "page0_model_0_2", - "page1_model_0_2", - "page0_model_1_2", - "page1_model_1_2", - ] - ); - } - - #[test] - fn exact_cache_detach_rolls_back_identity_mismatch() { - let cache = MasterNodeCache::builder(1024 * 1024) - .weigher(|_key: &String, desc: &NodeValueReplicaDesc| desc.weight_bytes) - .build(); - let actual = HashMap::from([ - ( - "rank0".to_string(), - NodeValueReplicaDesc { - weight_bytes: 1024, - put_id: (30, 0), - }, - ), - ( - "rank1".to_string(), - NodeValueReplicaDesc { - weight_bytes: 1024, - put_id: (31, 0), - }, - ), - ]); - for (key, desc) in &actual { - insert_master_cache_entry(&cache, key.clone(), desc.clone()); - } - let mut stale_expected = actual.clone(); - stale_expected.get_mut("rank1").unwrap().put_id = (999, 0); - - assert!(take_exact_cache_entries(&cache, &stale_expected).is_none()); - assert_eq!(cache.get(&"rank0".to_string()).unwrap().put_id, (30, 0)); - assert_eq!(cache.get(&"rank1".to_string()).unwrap().put_id, (31, 0)); - - let removed = take_exact_cache_entries(&cache, &actual).unwrap(); - assert_eq!(removed.len(), 2); - assert!(cache.get(&"rank0".to_string()).is_none()); - assert!(cache.get(&"rank1".to_string()).is_none()); - } - #[test] fn ring_b_cache_is_bounded_for_every_node_role() { let cache = MasterNodeCache::builder(64) @@ -2098,7 +1882,7 @@ mod tests { } #[test] - fn atomic_batch_reclaim_identity_registration_is_all_or_nothing() { + fn multi_identity_registration_rolls_back_partial_insert() { let request = |keys: &[&str]| reclaim::EvictionReclaimRequest { owner_node_id: "cpu0".to_string(), owner_node_start_time: None, @@ -2130,7 +1914,7 @@ mod tests { ); // `c` is tentatively installed before the collision on `a`; failure - // must roll it back and preserve only the original atomic_batch. + // must roll it back and preserve only the original request. let overlapping = reclaim::EvictionReclaimRequest { members: vec![ reclaim::EvictionReclaimMember { @@ -2370,7 +2154,7 @@ pub struct MasterKvRouterInner { pub eviction_reclaim_pending_weight: DashMap>, /// Exact, versioned metadata identities currently owned by the lossless - /// eviction-reclaim pipeline. This bounds duplicate Size/atomic_batch events; + /// eviction-reclaim pipeline. This bounds duplicate Size/victim events; /// payload memory is not retained here. pub(crate) eviction_reclaim_inflight: DashSet, @@ -2382,7 +2166,7 @@ pub struct MasterKvRouterInner { /// Bounded maintenance can still process a batch of Size evictions; without /// this gate, concurrent async tasks can park multiple Tokio workers on the /// same blocking Moka lock. It is a scheduling gate, not a correctness or - /// atomic_batch lock, and no cache/global scan occurs under it. + /// request lock, and no cache/global scan occurs under it. pub(crate) owner_cache_operation_locks: AMapLock, /// Historical final put placement decisions by target node. @@ -3022,7 +2806,7 @@ impl MasterKvRouter { desc: NodeValueReplicaDesc, origin: reclaim::EvictionReclaimOrigin, ) -> bool { - self.enqueue_eviction_reclaim_atomic_batch( + self.enqueue_eviction_reclaim_request( owner_node_id, vec![reclaim::EvictionReclaimMember { key, @@ -3033,14 +2817,14 @@ impl MasterKvRouter { ) } - fn enqueue_eviction_reclaim_atomic_batch( + fn enqueue_eviction_reclaim_request( &self, owner_node_id: NodeIDString, members: Vec, origin: reclaim::EvictionReclaimOrigin, ) -> bool { matches!( - self.enqueue_eviction_reclaim_atomic_batch_exact( + self.enqueue_eviction_reclaim_request_exact( owner_node_id, None, members, @@ -3052,23 +2836,22 @@ impl MasterKvRouter { ) } - pub(crate) fn enqueue_owner_capacity_eviction_atomic_batch( + pub(crate) fn enqueue_owner_capacity_eviction_victim( &self, owner_node_id: NodeIDString, owner_node_start_time: i64, - members: Vec, - allow_new_request: bool, + victim: reclaim::EvictionReclaimMember, ) -> reclaim::EnqueueEvictionReclaimResult { - self.enqueue_eviction_reclaim_atomic_batch_exact( + self.enqueue_eviction_reclaim_request_exact( owner_node_id, Some(owner_node_start_time), - members, + vec![victim], reclaim::EvictionReclaimOrigin::OwnerCapacityEviction, - allow_new_request, + true, ) } - fn enqueue_eviction_reclaim_atomic_batch_exact( + fn enqueue_eviction_reclaim_request_exact( &self, owner_node_id: NodeIDString, owner_node_start_time: Option, @@ -3076,7 +2859,7 @@ impl MasterKvRouter { origin: reclaim::EvictionReclaimOrigin, allow_new_request: bool, ) -> reclaim::EnqueueEvictionReclaimResult { - if members.is_empty() { + if members.len() != 1 { return reclaim::EnqueueEvictionReclaimResult::PartialOverlap; } let request = reclaim::EvictionReclaimRequest { @@ -3097,9 +2880,8 @@ impl MasterKvRouter { self.eviction_reclaim_counters(&request.owner_node_id) .eviction_reclaim_deduplicated .fetch_add(1, Ordering::Relaxed); - // An idempotent retry is accepted only when the complete atomic_batch - // is already owned by the pipeline. A partial overlap is not a - // valid source handoff. + // An idempotent retry is accepted only when the exact victim is + // already owned by the pipeline. return if request .identities() .iter() @@ -4663,7 +4445,7 @@ impl MasterKvRouter { if cause == RemovalCause::Size { // Listener work is deliberately O(1): // clone fixed metadata, dedupe, and send - // to a lossless channel. Route/atomic_batch + // to a lossless channel. Route/victim // lookup belongs to the async actor. let _ = view.master_kv_router().enqueue_eviction_reclaim( cache_node_id.clone(), @@ -5239,8 +5021,8 @@ impl MasterKvRouter { source_evict_rpc_requests: reclaim_counters .source_evict_rpc_requests .load(Ordering::Relaxed), - source_evict_atomic_batches: reclaim_counters - .source_evict_atomic_batches + source_evict_victims: reclaim_counters + .source_evict_victims .load(Ordering::Relaxed), source_evict_requested_bytes: reclaim_counters .source_evict_requested_bytes @@ -5313,7 +5095,7 @@ impl MasterKvRouter { ); for node in snapshot.replica_cache_nodes { tracing::info!( - "replica cache runtime: owner={} entries={} weighted_bytes={} effective_capacity_bytes={} base_capacity_bytes={} reserved_capacity_bytes={} pending_eviction_reclaim_bytes={} writeback_tier1_entries={} writeback_tier1_weighted_bytes={} writeback_tier1_capacity_bytes={} writeback_tier1_triggered={} writeback_tier1_owner_accepted={} writeback_tier1_failed={} reclaim_master_activity_deferred={} reclaim_owner_holder_deferred={} reclaim_owner_other_deferred={} reclaim_route_changed={} reclaim_retry_queued={} reclaim_retry_completed={} reclaim_retry_restored={} reclaim_completed={} source_evict_rpc_requests={} source_evict_atomic_batches={} source_evict_requested_bytes={} source_evict_accepted={} source_evict_in_progress={} source_evict_completed={} source_evict_retryable_busy={} source_evict_stale={} source_evict_rejected={} last_route_removed_members={} last_route_removed_bytes={} capacity_eviction_non_ring_b_entry_total={} capacity_eviction_hit_committed_slot={} eviction_reclaim_deduplicated={}", + "replica cache runtime: owner={} entries={} weighted_bytes={} effective_capacity_bytes={} base_capacity_bytes={} reserved_capacity_bytes={} pending_eviction_reclaim_bytes={} writeback_tier1_entries={} writeback_tier1_weighted_bytes={} writeback_tier1_capacity_bytes={} writeback_tier1_triggered={} writeback_tier1_owner_accepted={} writeback_tier1_failed={} reclaim_master_activity_deferred={} reclaim_owner_holder_deferred={} reclaim_owner_other_deferred={} reclaim_route_changed={} reclaim_retry_queued={} reclaim_retry_completed={} reclaim_retry_restored={} reclaim_completed={} source_evict_rpc_requests={} source_evict_victims={} source_evict_requested_bytes={} source_evict_accepted={} source_evict_in_progress={} source_evict_completed={} source_evict_retryable_busy={} source_evict_stale={} source_evict_rejected={} last_route_removed_members={} last_route_removed_bytes={} capacity_eviction_non_ring_b_entry_total={} capacity_eviction_hit_committed_slot={} eviction_reclaim_deduplicated={}", node.owner_node, node.entries, node.weighted_bytes, @@ -5336,7 +5118,7 @@ impl MasterKvRouter { node.reclaim_retry_restored, node.reclaim_completed, node.source_evict_rpc_requests, - node.source_evict_atomic_batches, + node.source_evict_victims, node.source_evict_requested_bytes, node.source_evict_accepted, node.source_evict_in_progress, diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs index 6b23403..da9b0b8 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs @@ -364,16 +364,16 @@ pub enum OwnerReclaimReason { /// One exact owner-local source selected for capacity eviction. #[derive(Default, Debug, Clone, Hash, PartialEq, Eq, Encode, Decode)] -pub struct OwnerSourceEvictionMember { +pub struct OwnerSourceEvictionVictim { pub key: String, pub put_id: PutIDForAKey, pub backing: OwnerReclaimBacking, } -/// Atomic/TP members which must enter the reclaim pipeline together. -#[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)] -pub struct OwnerSourceEvictionAtomicBatch { - pub members: Vec, +pub(crate) fn owner_source_eviction_epoch(operation_id: u64, victim_index: usize) -> u64 { + operation_id + .rotate_left(32) + .wrapping_add(u64::try_from(victim_index).unwrap_or(u64::MAX)) } #[derive(Default, Debug, Clone, Encode, Decode)] @@ -381,7 +381,7 @@ pub struct BatchEvictOwnerSourceReq { pub operation_id: u64, /// Membership generation of the authenticated source owner. pub owner_node_start_time: i64, - pub atomic_batches: Vec, + pub victims: Vec, } impl MsgPackSerializePart for BatchEvictOwnerSourceReq { @@ -403,8 +403,8 @@ pub enum OwnerSourceEvictionOutcome { } #[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)] -pub struct OwnerSourceEvictionAtomicBatchResp { - pub atomic_batch_index: u32, +pub struct OwnerSourceEvictionVictimResp { + pub victim_index: u32, pub outcome: OwnerSourceEvictionOutcome, pub detail: String, } @@ -412,7 +412,7 @@ pub struct OwnerSourceEvictionAtomicBatchResp { #[derive(Default, Debug, Clone, Encode, Decode)] pub struct BatchEvictOwnerSourceResp { pub operation_id: u64, - pub atomic_batches: Vec, + pub victims: Vec, pub error_code: ErrorCode, pub error_json: String, } diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs index e2c8d01..22f7df6 100644 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs @@ -3,8 +3,8 @@ use crate::cluster_manager::{NodeID, NodeIDString}; use crate::master_kv_router::msg_pack::{ BatchEvictOwnerSourceReq, BatchEvictOwnerSourceResp, BatchOwnerReclaimReq, OwnerReclaimBacking, OwnerReclaimItem, OwnerReclaimItemResp, OwnerReclaimItemState, OwnerReclaimPhase, - OwnerReclaimReason, OwnerSourceEvictionAtomicBatch, OwnerSourceEvictionAtomicBatchResp, - OwnerSourceEvictionOutcome, + OwnerReclaimReason, OwnerSourceEvictionOutcome, OwnerSourceEvictionVictim, + OwnerSourceEvictionVictimResp, owner_source_eviction_epoch, }; use crate::p2p::msg_pack::{MIN_EXPLICIT_RPC_TIMEOUT_SECS, MsgPack, RPCCaller}; use crate::rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, OK}; @@ -66,10 +66,10 @@ mod timeout_contract_tests { } #[cfg(test)] -mod atomic_batch_transaction_tests { +mod single_victim_transaction_tests { use super::*; use crate::master_kv_router::msg_pack::{ - OwnerSourceEvictionMember, PutAtomicGroup, PutAtomicGroupMember, + OwnerSourceEvictionVictim, PutAtomicGroup, PutAtomicGroupMember, }; use crate::master_kv_router::{ CommittedSlotReplica, KvRouteInfo, MasterKeyActivityKind, MasterKeyActivityTable, @@ -79,7 +79,7 @@ mod atomic_batch_transaction_tests { use parking_lot::RwLock; use std::collections::HashMap; use std::sync::Arc; - use std::sync::atomic::AtomicU32; + use std::sync::atomic::{AtomicBool, AtomicU32}; fn item(key: &str, epoch: u64) -> OwnerReclaimItem { OwnerReclaimItem { @@ -96,26 +96,24 @@ mod atomic_batch_transaction_tests { } #[test] - fn atomic_batch_master_fences_roll_back_all_members_when_one_is_busy() { + fn single_victim_master_fence_rejects_a_busy_key() { let activity = Arc::new(MasterKeyActivityTable::default()); - let items = vec![item("rank0", 1), item("rank1", 2)]; + let items = vec![item("victim", 1)]; let _busy = activity - .reserve("rank1", MasterKeyActivityKind::Get, false) + .reserve("victim", MasterKeyActivityKind::Get, false) .unwrap(); - assert!(try_install_atomic_batch_master_fences(&activity, &items).is_err()); - assert!(!activity.has_reclaim("rank0")); - assert!(!activity.has_reclaim("rank1")); + assert!(try_install_master_fences(&activity, &items).is_err()); + assert!(!activity.has_reclaim("victim")); } #[test] - fn atomic_batch_master_fences_install_and_clear_as_one_set() { + fn single_victim_master_fence_installs_and_clears() { let activity = Arc::new(MasterKeyActivityTable::default()); - let items = vec![item("rank0", 1), item("rank1", 2)]; + let items = vec![item("victim", 1)]; - try_install_atomic_batch_master_fences(&activity, &items).unwrap(); - assert!(activity.has_reclaim("rank0")); - assert!(activity.has_reclaim("rank1")); + try_install_master_fences(&activity, &items).unwrap(); + assert!(activity.has_reclaim("victim")); for item in &items { assert!(activity.clear_reclaim(item)); } @@ -138,13 +136,13 @@ mod atomic_batch_transaction_tests { ); } - fn source_member( + fn source_victim( key: &str, put_id: (u64, u32), grant_id: u64, slot_index: u32, - ) -> OwnerSourceEvictionMember { - OwnerSourceEvictionMember { + ) -> OwnerSourceEvictionVictim { + OwnerSourceEvictionVictim { key: key.to_string(), put_id, backing: OwnerReclaimBacking::CommittedSlot { @@ -157,7 +155,7 @@ mod atomic_batch_transaction_tests { fn source_route( owner: &NodeID, - member: &OwnerSourceEvictionMember, + member: &OwnerSourceEvictionVictim, atomic_group: Option>, include_cpu_replica: bool, ) -> Arc { @@ -217,7 +215,7 @@ mod atomic_batch_transaction_tests { }) } - fn source_reclaim_item(member: &OwnerSourceEvictionMember) -> OwnerReclaimItem { + fn source_reclaim_item(member: &OwnerSourceEvictionVictim) -> OwnerReclaimItem { OwnerReclaimItem { key: member.key.clone(), put_id: member.put_id, @@ -230,25 +228,17 @@ mod atomic_batch_transaction_tests { #[test] fn exact_source_plan_accepts_with_or_without_a_cpu_replica() { let owner: NodeID = "gpu0".to_string().into(); - let member = source_member("single", (10, 1), 7, 3); - let atomic_batch = OwnerSourceEvictionAtomicBatch { - members: vec![member.clone()], - }; + let member = source_victim("single", (10, 1), 7, 3); for include_cpu_replica in [false, true] { let route = source_route(&owner, &member, None, include_cpu_replica); - let plan = plan_exact_owner_source_atomic_batch_with(&owner, &atomic_batch, &|key| { + let plan = plan_exact_owner_source_victim_with(&owner, &member, &|key| { (key == "single").then(|| route.clone()) }); match plan { - OwnerSourceAtomicBatchPlan::Ready { - members, - all_sources_present, - } => { - assert!(all_sources_present); - assert_eq!(members.len(), 1); - assert_eq!(members[0].key, "single"); - assert_eq!(members[0].expected_backing, Some(member.backing.clone())); + OwnerSourceVictimPlan::Ready(planned) => { + assert_eq!(planned.key, "single"); + assert_eq!(planned.expected_backing, Some(member.backing.clone())); } _ => panic!("exact current owner source must be accepted"), } @@ -258,7 +248,7 @@ mod atomic_batch_transaction_tests { #[test] fn exact_source_removal_deletes_only_gpu_when_cpu_exists_and_last_route_otherwise() { let owner: NodeID = "gpu0".to_string().into(); - let member = source_member("with-cpu", (10, 2), 7, 4); + let member = source_victim("with-cpu", (10, 2), 7, 4); let routes = dashmap::DashMap::new(); routes.insert( member.key.clone(), @@ -279,7 +269,7 @@ mod atomic_batch_transaction_tests { assert!(!remaining.nodes_replicas.read().contains_key(&owner)); assert!(remaining.nodes_replicas.read().contains_key("cpu0")); - let last = source_member("last", (10, 3), 7, 5); + let last = source_victim("last", (10, 3), 7, 5); routes.insert(last.key.clone(), source_route(&owner, &last, None, false)); let removed = remove_exact_owner_source_route(&routes, &owner, &source_reclaim_item(&last)) .expect("last exact GPU source must be removed"); @@ -295,9 +285,9 @@ mod atomic_batch_transaction_tests { removed.capacity_bytes ); - let stale = source_member("stale", (10, 4), 8, 6); + let stale = source_victim("stale", (10, 4), 8, 6); routes.insert(stale.key.clone(), source_route(&owner, &stale, None, false)); - let wrong_identity = source_member("stale", stale.put_id, 999, 6); + let wrong_identity = source_victim("stale", stale.put_id, 999, 6); assert!( remove_exact_owner_source_route( &routes, @@ -310,13 +300,10 @@ mod atomic_batch_transaction_tests { } #[test] - fn partial_source_absence_is_replay_only_and_all_absent_is_completed() { + fn singleton_source_is_independent_of_atomic_group_siblings() { let owner: NodeID = "gpu0".to_string().into(); - let a = source_member("a", (11, 0), 8, 0); - let b = source_member("b", (11, 1), 8, 1); - let atomic_batch = OwnerSourceEvictionAtomicBatch { - members: vec![a.clone(), b.clone()], - }; + let a = source_victim("a", (12, 0), 9, 0); + let b = source_victim("b", (12, 1), 9, 1); let group = Arc::new(PutAtomicGroup { members: vec![ PutAtomicGroupMember { @@ -329,71 +316,100 @@ mod atomic_batch_transaction_tests { }, ], }); - let route_a = source_route(&owner, &a, Some(group), false); - - match plan_exact_owner_source_atomic_batch_with(&owner, &atomic_batch, &|key| { + let route_a = source_route(&owner, &a, Some(group.clone()), false); + match plan_exact_owner_source_victim_with(&owner, &a, &|key| { (key == "a").then(|| route_a.clone()) }) { - OwnerSourceAtomicBatchPlan::Ready { - all_sources_present, - .. - } => assert!(!all_sources_present), - _ => panic!( - "a partially removed accepted atomic_batch must be recognized as replay-only" - ), + OwnerSourceVictimPlan::Ready(planned) => assert_eq!(planned.key, "a"), + _ => panic!("one current key must be reclaimable without its siblings"), } + + let changed_a = source_victim("a", a.put_id, 99, 0); + let changed_route = source_route(&owner, &changed_a, Some(group), false); assert!(matches!( - plan_exact_owner_source_atomic_batch_with(&owner, &atomic_batch, &|_| None), - OwnerSourceAtomicBatchPlan::Completed(_) + plan_exact_owner_source_victim_with(&owner, &a, &|key| { + (key == "a").then(|| changed_route.clone()) + }), + OwnerSourceVictimPlan::Stale(_) )); } #[test] - fn one_stale_or_inconsistent_member_rejects_the_whole_source_atomic_batch() { + fn absent_single_source_is_already_completed() { let owner: NodeID = "gpu0".to_string().into(); - let a = source_member("a", (12, 0), 9, 0); - let b = source_member("b", (12, 1), 9, 1); - let atomic_batch = OwnerSourceEvictionAtomicBatch { - members: vec![a.clone(), b.clone()], - }; - let group = Arc::new(PutAtomicGroup { - members: vec![ - PutAtomicGroupMember { - key: a.key.clone(), - put_id: a.put_id, - }, - PutAtomicGroupMember { - key: b.key.clone(), - put_id: b.put_id, - }, - ], - }); - let route_a = source_route(&owner, &a, Some(group.clone()), false); - let changed_b = source_member("b", b.put_id, 99, 1); - let route_b_with_changed_backing = - source_route(&owner, &changed_b, Some(group.clone()), false); - let stale_backing_plan = - plan_exact_owner_source_atomic_batch_with(&owner, &atomic_batch, &|key| match key { - "a" => Some(route_a.clone()), - "b" => Some(route_b_with_changed_backing.clone()), - _ => None, - }); + let victim = source_victim("gone", (13, 0), 10, 0); assert!(matches!( - stale_backing_plan, - OwnerSourceAtomicBatchPlan::Stale(_) + plan_exact_owner_source_victim_with(&owner, &victim, &|_| None), + OwnerSourceVictimPlan::Completed(_) )); + } - let route_b_without_group = source_route(&owner, &b, None, false); - let inconsistent_group_plan = - plan_exact_owner_source_atomic_batch_with(&owner, &atomic_batch, &|key| match key { - "a" => Some(route_a.clone()), - "b" => Some(route_b_without_group.clone()), - _ => None, - }); - assert!(matches!( - inconsistent_group_plan, - OwnerSourceAtomicBatchPlan::Rejected(_) - )); + #[test] + fn direct_delete_batch_keeps_results_independent_and_replay_idempotent() { + let owner: NodeID = "gpu0".to_string().into(); + let ready = source_victim("ready", (14, 0), 11, 0); + let busy = source_victim("busy", (14, 1), 11, 1); + let stale = source_victim("stale", (14, 2), 11, 2); + let routes = dashmap::DashMap::new(); + for victim in [&ready, &busy, &stale] { + routes.insert( + victim.key.clone(), + source_route(&owner, victim, None, false), + ); + } + let activity = Arc::new(MasterKeyActivityTable::default()); + let _busy_get = activity + .reserve(&busy.key, MasterKeyActivityKind::Get, false) + .expect("busy victim must hold a master Get lease"); + let stale_request = source_victim("stale", stale.put_id, 999, 2); + let victims = vec![ready.clone(), busy.clone(), stale_request]; + let responses = direct_delete_exact_owner_source_batch_with( + activity.as_ref(), + &owner, + 77, + &victims, + &|key| routes.get(key).map(|route| route.clone()), + |item| remove_exact_owner_source_route(&routes, &owner, item).is_some(), + ); + + assert_eq!( + responses + .iter() + .map(|response| response.outcome) + .collect::>(), + vec![ + OwnerSourceEvictionOutcome::Completed, + OwnerSourceEvictionOutcome::RetryableBusy, + OwnerSourceEvictionOutcome::Stale, + ] + ); + assert_eq!( + responses + .iter() + .map(|response| response.victim_index) + .collect::>(), + vec![0, 1, 2], + "one batch response vector must stay aligned with every input victim" + ); + assert!(!routes.contains_key(&ready.key)); + assert!(routes.contains_key(&busy.key)); + assert!(routes.contains_key(&stale.key)); + assert!(!activity.has_reclaim(&ready.key)); + + let replay_delete_called = AtomicBool::new(false); + let replay = direct_delete_exact_owner_source_with( + activity.as_ref(), + &owner, + &ready, + owner_source_eviction_epoch(77, 0), + &|key| routes.get(key).map(|route| route.clone()), + |_| { + replay_delete_called.store(true, Ordering::Relaxed); + false + }, + ); + assert_eq!(replay.0, OwnerSourceEvictionOutcome::Completed); + assert!(!replay_delete_called.load(Ordering::Relaxed)); } } @@ -469,7 +485,6 @@ impl EvictionReclaimRequest { #[derive(Clone, Copy, Debug, Eq, PartialEq)] enum MasterCapacityPlanError { RouteChanged, - InvalidAtomicBatch, WrongRole, CommittedSlot, } @@ -529,84 +544,25 @@ fn allocation_member_from_route( )) } -/// Expand one master Size event by point-looking up its atomic/TP atomic_batch. -/// This function never iterates the resident cache or global route table. -fn plan_master_allocation_capacity_atomic_batch( +/// Validate one exact key popped by the master Allocation Moka. +fn plan_master_allocation_capacity_victim( view: &MasterKvRouterView, request: &EvictionReclaimRequest, -) -> Result, MasterCapacityPlanError> { +) -> Result { if request.origin != EvictionReclaimOrigin::MasterAllocationCapacity - || request.members.is_empty() + || request.members.len() != 1 { return Err(MasterCapacityPlanError::WrongRole); } let owner: NodeID = request.owner_node_id.clone().into(); let anchor = &request.members[0]; - let (current_anchor, anchor_route) = allocation_member_from_route(view, &owner, &anchor.key)?; + let (current_anchor, _route) = allocation_member_from_route(view, &owner, &anchor.key)?; if current_anchor.desc.put_id != anchor.desc.put_id || current_anchor.desc.weight_bytes != anchor.desc.weight_bytes { return Err(MasterCapacityPlanError::RouteChanged); } - let mut atomic_batch_keys = - super::current_tp_atomic_batch_keys(&anchor.key, &anchor_route, ¤t_anchor.desc) - .map_err(|_| MasterCapacityPlanError::InvalidAtomicBatch)?; - atomic_batch_keys.sort_unstable(); - atomic_batch_keys.dedup(); - if atomic_batch_keys.is_empty() { - return Err(MasterCapacityPlanError::InvalidAtomicBatch); - } - - let mut members = Vec::with_capacity(atomic_batch_keys.len()); - for key in &atomic_batch_keys { - let (member, route) = allocation_member_from_route(view, &owner, key)?; - let mut peer_keys = super::current_tp_atomic_batch_keys(key, &route, &member.desc) - .map_err(|_| MasterCapacityPlanError::InvalidAtomicBatch)?; - peer_keys.sort_unstable(); - peer_keys.dedup(); - if peer_keys != atomic_batch_keys { - return Err(MasterCapacityPlanError::InvalidAtomicBatch); - } - members.push(member); - } - Ok(members) -} - -fn detach_present_capacity_atomic_batch_siblings( - view: &MasterKvRouterView, - owner_node_id: &str, - members: &[EvictionReclaimMember], -) -> Result, MasterCapacityPlanError> { - let cache = view - .master_kv_router() - .get_node_cache_controller(owner_node_id) - .ok_or(MasterCapacityPlanError::RouteChanged)?; - let mut expected = HashMap::new(); - for member in members { - if let Some(cached) = cache.get(&member.key) { - if cached.put_id != member.desc.put_id - || cached.weight_bytes != member.desc.weight_bytes - { - return Err(MasterCapacityPlanError::RouteChanged); - } - expected.insert(member.key.clone(), member.desc.clone()); - } - } - if expected.is_empty() { - return Ok(Vec::new()); - } - super::take_exact_cache_entries(&cache, &expected) - .map(|removed| { - removed - .into_iter() - .map(|(key, desc)| EvictionReclaimMember { - key, - desc, - expected_backing: None, - }) - .collect() - }) - .ok_or(MasterCapacityPlanError::RouteChanged) + Ok(current_anchor) } fn route_item( @@ -879,152 +835,170 @@ fn owner_source_member_weight(backing: &OwnerReclaimBacking) -> Option { } } -enum OwnerSourceAtomicBatchPlan { - Ready { - members: Vec, - all_sources_present: bool, - }, +enum OwnerSourceVictimPlan { + Ready(EvictionReclaimMember), Completed(&'static str), Stale(String), Rejected(String), } -fn plan_exact_owner_source_atomic_batch( - view: &MasterKvRouterView, +fn plan_exact_owner_source_victim_with( owner: &NodeID, - atomic_batch: &OwnerSourceEvictionAtomicBatch, -) -> OwnerSourceAtomicBatchPlan { - plan_exact_owner_source_atomic_batch_with(owner, atomic_batch, &|key| { - view.master_kv_router() - .inner() - .kv_routes - .get(key) - .map(|entry| entry.clone()) - }) -} - -fn plan_exact_owner_source_atomic_batch_with( - owner: &NodeID, - atomic_batch: &OwnerSourceEvictionAtomicBatch, + victim: &OwnerSourceEvictionVictim, route_lookup: &dyn Fn(&str) -> Option>, -) -> OwnerSourceAtomicBatchPlan { - if atomic_batch.members.is_empty() { - return OwnerSourceAtomicBatchPlan::Rejected( - "empty source-eviction atomic_batch".to_string(), - ); - } +) -> OwnerSourceVictimPlan { + let Some(weight_bytes) = owner_source_member_weight(&victim.backing) else { + return OwnerSourceVictimPlan::Rejected(format!( + "source backing is not an exact committed slot: key={}", + victim.key + )); + }; + let desc = NodeValueReplicaDesc { + weight_bytes, + put_id: victim.put_id, + }; + let planned = EvictionReclaimMember { + key: victim.key.clone(), + desc: desc.clone(), + expected_backing: Some(victim.backing.clone()), + }; - let mut expected_keys = atomic_batch - .members - .iter() - .map(|member| member.key.clone()) - .collect::>(); - expected_keys.sort_unstable(); - expected_keys.dedup(); - if expected_keys.len() != atomic_batch.members.len() { - return OwnerSourceAtomicBatchPlan::Rejected( - "source-eviction atomic_batch contains duplicate keys".to_string(), - ); + let Some(route) = route_lookup(&victim.key) else { + return OwnerSourceVictimPlan::Completed("exact source replica is already absent"); + }; + if route.put_id != victim.put_id { + return OwnerSourceVictimPlan::Stale(format!( + "route version changed: key={} expected=({},{}) current=({},{})", + victim.key, victim.put_id.0, victim.put_id.1, route.put_id.0, route.put_id.1, + )); } - - let mut planned = Vec::with_capacity(atomic_batch.members.len()); - let mut absent_sources = 0usize; - for member in &atomic_batch.members { - let Some(weight_bytes) = owner_source_member_weight(&member.backing) else { - return OwnerSourceAtomicBatchPlan::Rejected(format!( - "source backing is not an exact committed slot: key={}", - member.key - )); - }; - let desc = NodeValueReplicaDesc { - weight_bytes, - put_id: member.put_id, - }; - planned.push(EvictionReclaimMember { - key: member.key.clone(), - desc: desc.clone(), - expected_backing: Some(member.backing.clone()), - }); - - let Some(route) = route_lookup(&member.key) else { - absent_sources += 1; - continue; - }; - if route.put_id != member.put_id { - return OwnerSourceAtomicBatchPlan::Stale(format!( - "route version changed: key={} expected=({},{}) current=({},{})", - member.key, member.put_id.0, member.put_id.1, route.put_id.0, route.put_id.1, - )); - } - if route.lease_id.is_some() { - return OwnerSourceAtomicBatchPlan::Rejected(format!( - "leased route is not cache-evictable: key={}", - member.key - )); - } - let replica_matches = { - let replicas = route.nodes_replicas.read(); - match replicas.get(owner) { - Some(replica) if !replica.tomb_tag.is_tomb() => { - if !replica.owner_local_indexed { - return OwnerSourceAtomicBatchPlan::Rejected(format!( - "source route is not owner-local indexed: key={}", - member.key - )); - } - reclaim_backing_matches(replica, &member.backing) - } - _ => { - absent_sources += 1; - continue; + if route.lease_id.is_some() { + return OwnerSourceVictimPlan::Rejected(format!( + "leased route is not cache-evictable: key={}", + victim.key + )); + } + let replica_matches = { + let replicas = route.nodes_replicas.read(); + match replicas.get(owner) { + Some(replica) if !replica.tomb_tag.is_tomb() => { + if !replica.owner_local_indexed { + return OwnerSourceVictimPlan::Rejected(format!( + "source route is not owner-local indexed: key={}", + victim.key + )); } + reclaim_backing_matches(replica, &victim.backing) + } + _ => { + return OwnerSourceVictimPlan::Completed("exact source replica is already absent"); } - }; - if !replica_matches { - return OwnerSourceAtomicBatchPlan::Stale(format!( - "source backing changed: key={} put_id=({},{})", - member.key, member.put_id.0, member.put_id.1 - )); } + }; + if !replica_matches { + return OwnerSourceVictimPlan::Stale(format!( + "source backing changed: key={} put_id=({},{})", + victim.key, victim.put_id.0, victim.put_id.1 + )); + } + OwnerSourceVictimPlan::Ready(planned) +} - let mut route_atomic_batch = - match super::current_tp_atomic_batch_keys(&member.key, &route, &desc) { - Ok(keys) => keys, - Err(_) => { - return OwnerSourceAtomicBatchPlan::Rejected(format!( - "master route has an invalid TP/atomic atomic_batch: key={}", - member.key - )); - } - }; - route_atomic_batch.sort_unstable(); - route_atomic_batch.dedup(); - if route_atomic_batch != expected_keys { - return OwnerSourceAtomicBatchPlan::Rejected(format!( - "owner did not submit the complete TP/atomic atomic_batch: key={} expected_members={} route_members={}", - member.key, - expected_keys.len(), - route_atomic_batch.len(), - )); +fn direct_delete_exact_owner_source_with( + activity: &super::MasterKeyActivityTable, + owner: &NodeID, + victim: &OwnerSourceEvictionVictim, + epoch: u64, + route_lookup: &dyn Fn(&str) -> Option>, + delete: impl FnOnce(&OwnerReclaimItem) -> bool, +) -> (OwnerSourceEvictionOutcome, String) { + let member = match plan_exact_owner_source_victim_with(owner, victim, route_lookup) { + OwnerSourceVictimPlan::Ready(member) => member, + OwnerSourceVictimPlan::Completed(detail) => { + return (OwnerSourceEvictionOutcome::Completed, detail.to_string()); + } + OwnerSourceVictimPlan::Stale(detail) => { + return (OwnerSourceEvictionOutcome::Stale, detail); + } + OwnerSourceVictimPlan::Rejected(detail) => { + return (OwnerSourceEvictionOutcome::RejectedNotEvictable, detail); } + }; + let item = OwnerReclaimItem { + key: member.key, + put_id: member.desc.put_id, + epoch, + backing: member + .expected_backing + .expect("exact owner source plan must retain its backing"), + reason: OwnerReclaimReason::OwnerCapacityEviction, + }; + if let Err(snapshot) = activity.try_install_reclaim(&item) { + return ( + OwnerSourceEvictionOutcome::RetryableBusy, + format!( + "master key activity is busy: puts={} gets={} replicas={} reclaim_installed={}", + snapshot.puts, snapshot.gets, snapshot.replicas, snapshot.reclaim_installed + ), + ); } - if absent_sources == atomic_batch.members.len() { - OwnerSourceAtomicBatchPlan::Completed("all exact source replicas are already absent") - } else if absent_sources != 0 { - // This can be observed while an accepted atomic_batch is between individual - // route removals. The exact inflight registration below distinguishes - // that case from a malformed new request. - OwnerSourceAtomicBatchPlan::Ready { - members: planned, - all_sources_present: false, + let result = match plan_exact_owner_source_victim_with(owner, victim, route_lookup) { + OwnerSourceVictimPlan::Ready(_) => { + if delete(&item) { + ( + OwnerSourceEvictionOutcome::Completed, + "exact source route deleted by batch handler".to_string(), + ) + } else { + ( + OwnerSourceEvictionOutcome::RetryableBusy, + "exact source route could not be deleted under its master fence".to_string(), + ) + } } - } else { - OwnerSourceAtomicBatchPlan::Ready { - members: planned, - all_sources_present: true, + OwnerSourceVictimPlan::Completed(detail) => { + (OwnerSourceEvictionOutcome::Completed, detail.to_string()) } - } + OwnerSourceVictimPlan::Stale(detail) => (OwnerSourceEvictionOutcome::Stale, detail), + OwnerSourceVictimPlan::Rejected(detail) => { + (OwnerSourceEvictionOutcome::RejectedNotEvictable, detail) + } + }; + assert!( + activity.clear_reclaim(&item), + "direct-delete master fence must remain installed until route deletion completes" + ); + result +} + +fn direct_delete_exact_owner_source_batch_with( + activity: &super::MasterKeyActivityTable, + owner: &NodeID, + operation_id: u64, + victims: &[OwnerSourceEvictionVictim], + route_lookup: &dyn Fn(&str) -> Option>, + delete: impl Fn(&OwnerReclaimItem) -> bool, +) -> Vec { + victims + .iter() + .enumerate() + .map(|(index, victim)| { + let (outcome, detail) = direct_delete_exact_owner_source_with( + activity, + owner, + victim, + owner_source_eviction_epoch(operation_id, index), + route_lookup, + |item| delete(item), + ); + OwnerSourceEvictionVictimResp { + victim_index: u32::try_from(index).unwrap_or(u32::MAX), + outcome, + detail, + } + }) + .collect() } pub(crate) async fn handle_batch_evict_owner_source( @@ -1039,16 +1013,15 @@ pub(crate) async fn handle_batch_evict_owner_source( counters .source_evict_rpc_requests .fetch_add(1, Ordering::Relaxed); - counters.source_evict_atomic_batches.fetch_add( - u64::try_from(req.serialize_part.atomic_batches.len()).unwrap_or(u64::MAX), + counters.source_evict_victims.fetch_add( + u64::try_from(req.serialize_part.victims.len()).unwrap_or(u64::MAX), Ordering::Relaxed, ); let requested_bytes = req .serialize_part - .atomic_batches + .victims .iter() - .flat_map(|atomic_batch| atomic_batch.members.iter()) - .filter_map(|member| owner_source_member_weight(&member.backing)) + .filter_map(|victim| owner_source_member_weight(&victim.backing)) .map(u64::from) .fold(0u64, u64::saturating_add); counters @@ -1060,7 +1033,7 @@ pub(crate) async fn handle_batch_evict_owner_source( .map(|member| member.node_start_time); if current_generation != Some(req.serialize_part.owner_node_start_time) { counters.source_evict_rejected.fetch_add( - u64::try_from(req.serialize_part.atomic_batches.len()).unwrap_or(u64::MAX), + u64::try_from(req.serialize_part.victims.len()).unwrap_or(u64::MAX), Ordering::Relaxed, ); let err = KvError::Api(ApiError::InvalidArgument { @@ -1072,7 +1045,7 @@ pub(crate) async fn handle_batch_evict_owner_source( return MsgPack { serialize_part: BatchEvictOwnerSourceResp { operation_id, - atomic_batches: Vec::new(), + victims: Vec::new(), error_code: err.code(), error_json: err.to_json(), }, @@ -1080,57 +1053,22 @@ pub(crate) async fn handle_batch_evict_owner_source( }; } - let mut responses = Vec::with_capacity(req.serialize_part.atomic_batches.len()); - for (index, atomic_batch) in req.serialize_part.atomic_batches.iter().enumerate() { - let (outcome, detail) = - match plan_exact_owner_source_atomic_batch(view, &owner, atomic_batch) { - OwnerSourceAtomicBatchPlan::Completed(detail) => { - (OwnerSourceEvictionOutcome::Completed, detail.to_string()) - } - OwnerSourceAtomicBatchPlan::Stale(detail) => { - (OwnerSourceEvictionOutcome::Stale, detail) - } - OwnerSourceAtomicBatchPlan::Rejected(detail) => { - (OwnerSourceEvictionOutcome::RejectedNotEvictable, detail) - } - OwnerSourceAtomicBatchPlan::Ready { - members, - all_sources_present, - } => { - match view - .master_kv_router() - .enqueue_owner_capacity_eviction_atomic_batch( - owner.as_ref().to_string(), - req.serialize_part.owner_node_start_time, - members, - all_sources_present, - ) { - EnqueueEvictionReclaimResult::Accepted => ( - OwnerSourceEvictionOutcome::Accepted, - "exact source atomic_batch accepted by reclaim pipeline".to_string(), - ), - EnqueueEvictionReclaimResult::AlreadyInProgress => ( - OwnerSourceEvictionOutcome::AlreadyInProgress, - "same exact source atomic_batch is already in progress".to_string(), - ), - EnqueueEvictionReclaimResult::PartialOverlap => ( - OwnerSourceEvictionOutcome::RetryableBusy, - "source atomic_batch partially overlaps another reclaim transaction" - .to_string(), - ), - EnqueueEvictionReclaimResult::NotInProgress => ( - OwnerSourceEvictionOutcome::Stale, - "partially absent source atomic_batch is not an in-progress replay" - .to_string(), - ), - EnqueueEvictionReclaimResult::Closed => ( - OwnerSourceEvictionOutcome::RetryableBusy, - "source reclaim actor is unavailable".to_string(), - ), - } - } - }; - let outcome_counter = match outcome { + let responses = direct_delete_exact_owner_source_batch_with( + &view.master_kv_router().inner().key_activity, + &owner, + operation_id, + &req.serialize_part.victims, + &|key| { + view.master_kv_router() + .inner() + .kv_routes + .get(key) + .map(|route| route.clone()) + }, + |item| remove_reclaimed_replica(view, &owner, item), + ); + for response in &responses { + let outcome_counter = match response.outcome { OwnerSourceEvictionOutcome::Accepted => &counters.source_evict_accepted, OwnerSourceEvictionOutcome::AlreadyInProgress => &counters.source_evict_in_progress, OwnerSourceEvictionOutcome::Completed => &counters.source_evict_completed, @@ -1141,17 +1079,29 @@ pub(crate) async fn handle_batch_evict_owner_source( OwnerSourceEvictionOutcome::RejectedNotEvictable => &counters.source_evict_rejected, }; outcome_counter.fetch_add(1, Ordering::Relaxed); - responses.push(OwnerSourceEvictionAtomicBatchResp { - atomic_batch_index: u32::try_from(index).unwrap_or(u32::MAX), - outcome, - detail, - }); } + let completed = responses + .iter() + .filter(|response| response.outcome == OwnerSourceEvictionOutcome::Completed) + .count(); + let retryable = responses + .iter() + .filter(|response| response.outcome == OwnerSourceEvictionOutcome::RetryableBusy) + .count(); + tracing::info!( + owner = %owner, + operation_id, + victims = responses.len(), + completed, + retryable, + "owner source direct-delete batch completed" + ); + MsgPack { serialize_part: BatchEvictOwnerSourceResp { operation_id, - atomic_batches: responses, + victims: responses, error_code: OK, error_json: String::new(), }, @@ -1566,7 +1516,7 @@ fn clear_master_fences(view: &MasterKvRouterView, items: &[OwnerReclaimItem]) { } } -fn try_install_atomic_batch_master_fences( +fn try_install_master_fences( activity: &super::MasterKeyActivityTable, items: &[OwnerReclaimItem], ) -> Result<(), (usize, super::MasterKeyActivitySnapshot)> { @@ -1585,33 +1535,31 @@ fn try_install_atomic_batch_master_fences( Ok(()) } -/// Reclaim one TP/atomic atomic_batch as a transaction. -/// -/// Before the first owner Commit, any failed fence/validation/Prepare rolls -/// the entire atomic_batch back. Once a response (including an Abort response) -/// proves that any member was committed, rollback is impossible; the same -/// transaction retains every master fence and keeps driving the remaining -/// members until all are committed, then removes/finalizes the whole atomic_batch. -async fn reclaim_atomic_batch_items( +/// Reclaim one independently selected key. +async fn reclaim_single_victim( view: &MasterKvRouterView, owner: &NodeID, items: Vec, ) -> u32 { - if items.is_empty() { + if items.len() != 1 { + tracing::error!( + owner = %owner, + victims = items.len(), + "single-key reclaim received a non-singleton request" + ); return 0; } let counters = view .master_kv_router() .eviction_reclaim_counters(owner.as_ref()); - if let Err((failed_index, activity)) = try_install_atomic_batch_master_fences( - &view.master_kv_router().inner().key_activity, - &items, - ) { + if let Err((failed_index, activity)) = + try_install_master_fences(&view.master_kv_router().inner().key_activity, &items) + { counters .master_activity_deferred .fetch_add(1, Ordering::Relaxed); tracing::trace!( - "atomic_batch reclaim deferred by master activity: owner={} key={} puts={} gets={} replicas={} reclaim_installed={}", + "single-key reclaim deferred by master activity: owner={} key={} puts={} gets={} replicas={} reclaim_installed={}", owner, items[failed_index].key, activity.puts, @@ -1650,7 +1598,7 @@ async fn reclaim_atomic_batch_items( } if !master_only.is_empty() || owner_coordinated.len() != fenced.len() { tracing::error!( - "BUG: one reclaim atomic_batch mixed master-only and owner-coordinated backings: owner={} atomic_batch={} master_only={} owner_coordinated={}", + "BUG: one single-key reclaim mixed master-only and owner-coordinated backings: owner={} victims={} master_only={} owner_coordinated={}", owner, fenced.len(), master_only.len(), @@ -1762,7 +1710,7 @@ async fn reclaim_atomic_batch_items( if rounds == 8 && !committed_keys.is_empty() { tracing::warn!( - "owner atomic_batch reclaim is rolling forward after partial/uncertain commit: owner={} atomic_batch={} committed={}", + "owner single-key reclaim is rolling forward after uncertain commit: owner={} victims={} committed={}", owner, owner_coordinated.len(), committed_keys.len(), @@ -2152,11 +2100,11 @@ pub(crate) fn spawn_eviction_reclaim_actor( OwnerReclaimReason::OwnerCapacityEviction, ), EvictionReclaimOrigin::MasterAllocationCapacity => { - let members = match plan_master_allocation_capacity_atomic_batch( + let member = match plan_master_allocation_capacity_victim( &view_task, &request, ) { - Ok(members) => members, + Ok(member) => member, Err(MasterCapacityPlanError::CommittedSlot) => { counters .capacity_eviction_non_ring_b_entry_total @@ -2183,10 +2131,6 @@ pub(crate) fn spawn_eviction_reclaim_actor( counters.route_changed.fetch_add(1, Ordering::Relaxed); continue; } - Err(MasterCapacityPlanError::InvalidAtomicBatch) => { - retry_requests.push(request); - continue; - } Err(MasterCapacityPlanError::WrongRole) => { counters .capacity_eviction_non_ring_b_entry_total @@ -2204,80 +2148,9 @@ pub(crate) fn spawn_eviction_reclaim_actor( continue; } }; - let owner_cache_lock = view_task - .master_kv_router() - .inner() - .owner_cache_operation_locks - .get_lock(owner_node_id.clone()); - let owner_cache_guard = owner_cache_lock.lock().await; - let detach_result = detach_present_capacity_atomic_batch_siblings( - &view_task, - &owner_node_id, - &members, - ); - drop(owner_cache_guard); - if detach_result.is_err() { - retry_requests.push(request); - continue; - } - - let planned = members - .iter() - .map(|member| { - ( - member.key.clone(), - member.desc.put_id, - member.desc.weight_bytes, - ) - }) - .collect::>(); - let mut accounting_requests = vec![request]; - let mut retained = std::collections::VecDeque::new(); - while let Some(other) = pending.pop_front() { - let belongs = other.origin - == EvictionReclaimOrigin::MasterAllocationCapacity - && other.members.iter().all(|member| { - planned.contains(&( - member.key.clone(), - member.desc.put_id, - member.desc.weight_bytes, - )) - }); - if belongs { - accounting_requests.push(other); - } else { - retained.push_back(other); - } - } - pending = retained; - - let mut accounted = accounting_requests - .iter() - .flat_map(EvictionReclaimRequest::identities) - .collect::>(); - for member in &members { - let synthetic = EvictionReclaimRequest { - owner_node_id: owner_node_id.clone(), - owner_node_start_time: None, - members: vec![member.clone()], - origin: EvictionReclaimOrigin::MasterAllocationCapacity, - retry_count: 0, - }; - let identity = synthetic.identities().pop().unwrap(); - if accounted.contains(&identity) { - continue; - } - if view_task - .master_kv_router() - .register_eviction_reclaim(&synthetic) - { - accounted.insert(identity); - accounting_requests.push(synthetic); - } - } ( - members, - accounting_requests, + vec![member], + vec![request], OwnerReclaimReason::MasterAllocationCapacity, ) } @@ -2306,7 +2179,7 @@ pub(crate) fn spawn_eviction_reclaim_actor( }) .collect::>>(); if let Some(items) = items { - let _ = reclaim_atomic_batch_items(&view_task, &owner, items).await; + let _ = reclaim_single_victim(&view_task, &owner, items).await; } for accounting_request in accounting_requests.drain(..) { if request_is_current(&view_task, &accounting_request) { @@ -2325,7 +2198,7 @@ pub(crate) fn spawn_eviction_reclaim_actor( let retry_count = retry_requests.len(); spawn_eviction_reclaim_retry(view_task.clone(), retry_requests); tracing::trace!( - "safe atomic_batch eviction reclaim batch completed: owner={} retry_deferred={}", + "single-key eviction reclaim batch completed: owner={} retry_deferred={}", owner_node_id, retry_count, ); From 1cb188c8847120933969f659afb6ea73a3ddf204 Mon Sep 17 00:00:00 2001 From: zTz01 <1773266173@qq.com> Date: Tue, 21 Jul 2026 13:41:38 +0800 Subject: [PATCH 07/10] backup 9qps --- ...06\346\210\220\350\256\276\350\256\241.md" | 26 +- fluxon_py/config.py | 2 +- fluxon_py/kvclient/fluxon.py | 40 +- fluxon_py/kvclient/kvclient_interface.py | 6 +- .../src/client_kv_api/external_api.rs | 471 +++++++-- fluxon_rs/fluxon_kv/src/client_kv_api/get.rs | 93 +- fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs | 871 +++++++++++++++-- .../fluxon_kv/src/client_kv_api/msg_pack.rs | 63 +- fluxon_rs/fluxon_kv/src/client_kv_api/put.rs | 923 ++++++------------ .../fluxon_kv/src/client_kv_api/reclaim.rs | 32 +- fluxon_rs/fluxon_kv/src/config.rs | 6 +- .../external_client_api/delete_ack_batch.rs | 366 +++++++ .../fluxon_kv/src/external_client_api/mod.rs | 386 ++++++-- .../fluxon_kv/src/master_kv_router/mod.rs | 260 ++++- .../src/master_kv_router/msg_pack.rs | 11 + .../fluxon_kv/src/master_kv_router/put.rs | 149 ++- .../fluxon_kv/src/master_kv_router/reclaim.rs | 190 +++- fluxon_rs/fluxon_kv/src/memholder/lifetime.rs | 77 +- fluxon_rs/fluxon_kv/src/memholder/mod.rs | 1 - .../rpcresp_kvresult_convert.rs | 29 +- fluxon_rs/fluxon_pyo3/src/lib.rs | 15 +- 21 files changed, 2987 insertions(+), 1030 deletions(-) create mode 100644 fluxon_rs/fluxon_kv/src/external_client_api/delete_ack_batch.rs diff --git "a/fluxon_doc_cn/design/sglang_fluxon_kv\351\233\206\346\210\220\350\256\276\350\256\241.md" "b/fluxon_doc_cn/design/sglang_fluxon_kv\351\233\206\346\210\220\350\256\276\350\256\241.md" index 9c38aa5..8d6fa0f 100644 --- "a/fluxon_doc_cn/design/sglang_fluxon_kv\351\233\206\346\210\220\350\256\276\350\256\241.md" +++ "b/fluxon_doc_cn/design/sglang_fluxon_kv\351\233\206\346\210\220\350\256\276\350\256\241.md" @@ -185,7 +185,7 @@ flowchart LR | `GetStartResult` | SGLang hostless 读取 | 描述连续命中前缀、可传输长度、atomic group 命中数和第一个 miss 位置。 | | `GetStartHandle` | SGLang hostless 读取 | 持有一次 get-start 结果和 backend handle;必须被 `get_transfer` 消费或被 `cancel_get_transfer` 取消。 | | `get_start(keys, prefix_best_effort, atomic_group_lens)` | SGLang hostless 读取 | 按 key 顺序计算连续命中的 prefix,并返回 `GetStartHandle`。 | -| `get_transfer(handle)` | SGLang hostless 读取 | 消费 handle 的可传输前缀,执行必要 transfer,并返回 readable `plan_ptr`。 | +| `get_transfer(handle, *, consume_prefix_len=None)` | SGLang hostless 读取 | 消费 handle 的全部可传输前缀,或消费由 `consume_prefix_len` 选定的更短完整 atomic-group 前缀;释放 tail,执行必要 transfer,并返回 readable `plan_ptr`。 | | `cancel_get_transfer(handle)` | SGLang hostless 读取 | 放弃未 transfer 的 `GetStartHandle`,释放 get-start 期间持有的 owner/external 资源。 | | `release_views(plan_ptr)` | SGLang hostless 读取 | 释放 get-transfer 产生的 readable plan,丢弃其持有的 holder 引用。 | @@ -475,7 +475,7 @@ hostless restore 的核心约束是:SGLang 只能恢复有序 page keys 的连 因此读取侧分成 prefetch 和 restore 两段。当前实现把 start-to-transfer 计划显式限定为两个分支: - Prefetch:`get_start(keys, prefix_best_effort, atomic_group_lens)` 按 key 顺序做 local visible check / owner get start,计算 page 级连续命中前缀 `raw_prefix_hit_len`,再按 `atomic_group_lens` 向下收敛成 `transferable_len`。全 owner-local 批次返回 `InlineLocal { items }`:owner 为每个导出 page 安装独立 external holding,并把 offset、len、holding ID 和 owner generation 随 start response 返回;该分支不创建 transfer registry,也不启动后台 transfer。混合命中、master fallback 或需要远端 materialization 的批次返回 `OwnerRpc`,继续由 shared op 保存后台 prefetch 的 holder / transfer result。 -- Restore:SGLang 拿到 `transferable_len` 后再决定是否分配 GPU KV pages 并继续恢复。`get_transfer(handle)` 消费 `get_start` 返回的 handle。`InlineLocal` 分支在 external 进程校验 owner generation 和 mmap 范围后直接构造 holders;`OwnerRpc` 分支等待或取得原有 prefetch 结果。两个分支最终都生成持有 holder 引用的 readable `plan_ptr`,随后 SGLang native kernel 使用 `restore_*_from_fluxon_values(...)` 把 Fluxon value memory 拷回 GPU KV cache。 +- Restore:SGLang 拿到 `transferable_len` 后再决定是否分配 GPU KV pages 并继续恢复。`get_transfer(handle, consume_prefix_len=...)` 可以消费不超过 `transferable_len` 的更短完整 atomic-group 前缀;省略该参数时消费全部可传输前缀。`InlineLocal` 分支在 external 进程校验 owner generation 和 mmap 范围后,只为消费前缀构造 holders,tail holding IDs 进入现有 holder-ACK 合批队列;`OwnerRpc` 分支在同一 transfer handler 内 drop tail items,只等待或取得消费前缀的 prefetch 结果。两个分支最终都生成持有 holder 引用的 readable `plan_ptr`,随后 SGLang native kernel 使用 `restore_*_from_fluxon_values(...)` 把 Fluxon value memory 拷回 GPU KV cache。 读取阶段拆成 prefetch 和 restore 两步,主要是为了保证: @@ -513,14 +513,17 @@ sequenceDiagram B-->>U: transferable_len / prefix_hit_groups / first_miss_index U->>U: allocate GPU KV pages for transferable prefix alt transferable_len > 0 and caller chooses restore - U->>B: get_transfer(handle) - B->>F: get_transfer(handle) - F->>E: batch_get_transfer(handle, transferable keys) + U->>B: get_transfer(handle, consume_prefix_len) + B->>F: get_transfer(handle, consume_prefix_len) + F->>E: batch_get_transfer(handle, consumed prefix) alt InlineLocal - E->>E: validate generation and mmap range, construct holders + E->>E: validate generation and mmap range + E->>E: enqueue tail holding IDs to batched ACK + E->>E: construct consumed-prefix holders else OwnerRpc - E->>O: ExternalBatchGetTransferReq - O-->>E: prefetched holders / transfer results + E->>O: ExternalBatchGetTransferReq(consume_prefix_len) + O->>O: validate atomic boundary and drop tail items + O-->>E: consumed-prefix holders / transfer results end E-->>F: plan_ptr(value_ptrs, holders kept alive) F-->>B: plan_ptr @@ -547,7 +550,7 @@ sequenceDiagram | 字段 | 含义 | | --- | --- | | `raw_prefix_hit_len` | 按 key 顺序连续命中的 page 数,未按 atomic group 收敛。 | -| `transferable_len` | 可以交给 `get_transfer` 的 page 数;它不会切开 atomic group。 | +| `transferable_len` | `get_transfer` 最多可消费的 page 数;它不会切开 atomic group。 | | `prefix_hit_groups` | 完整命中的 atomic group 数。 | | `first_miss_index` | 第一个 miss page 的 index;全部命中时为 `None`。 | | `first_miss_group_index` | 第一个 miss 所在 atomic group;全部命中时为 `None`。 | @@ -556,9 +559,10 @@ sequenceDiagram 生命周期规则: - `get_start` 成功后,调用方必须二选一:`get_transfer(handle)` 或 `cancel_get_transfer(handle)`;放弃 restore 时必须取消 handle,释放可能已经启动的 prefetch 资源。 -- `get_transfer(handle)` 成功后,handle 已被消费;后续由 returned `plan_ptr` 和 `release_views(plan_ptr)` 管理。 +- `get_transfer(handle, consume_prefix_len=...)` 的值必须大于 0、不超过 `transferable_len`,并精确落在 atomic-group 边界;参数校验失败时 handle 仍可 cancel 或用合法长度重试。 +- `get_transfer` 成功后,handle 已被消费;tail 资源同时移交给 owner 直接 drop 或 external holder-ACK 合批队列,后续只由 returned `plan_ptr` 和 `release_views(plan_ptr)` 管理消费前缀。 - `release_views(plan_ptr)` 必须在 native restore 完成后执行,即使 native restore 失败也要释放。 -- `InlineLocal` holding 从 owner 返回 start response 前已经安装;`get_transfer` 把它移交给 returned plan,`cancel_get_transfer` 则携带 holding IDs 精确释放。owner 重启或 generation 不匹配时不能继续使用旧 inline plan。 +- `InlineLocal` holding 从 owner 返回 start response 前已经安装;全量 `get_transfer` 把它们移交给 returned plan,部分前缀 `get_transfer` 只移交前缀并将 tail holding IDs 无等待送入 holder-ACK 合批队列,`cancel_get_transfer` 则携带全部 holding IDs 精确释放。owner 重启或 generation 不匹配时不能继续使用旧 inline plan。 - `get_start` 只命中部分前缀时,SGLang 只能恢复 `transferable_len` 覆盖的完整 atomic groups,不能构造半个 atomic group 的 GPU KV 状态。 - `get_transfer` 返回 miss / KeyNotFound 时,SGLang 必须放弃本次 restore 并执行 rollback。 - owner 必须为未被 `get_transfer/cancel_get_transfer` 消费的 handle 设置有界 TTL;TTL 回收与 diff --git a/fluxon_py/config.py b/fluxon_py/config.py index 74f8746..4eff497 100644 --- a/fluxon_py/config.py +++ b/fluxon_py/config.py @@ -93,7 +93,7 @@ def _yaml_template(): tcp_thread_bulk_lane_count: # tcp_thread bulk lane count, 1..8 (int(optional)) tcp_thread_control_lane_count: # tcp_thread control lane count, 1..8 (int(optional)) user_rpc_sync_handler_thread_count: # Owner-dedicated sync user-RPC worker thread count, >0 (int(optional)) - replica_task_max_inflight: # Concurrent replica append pipelines, 1..64; per-key order stays serialized (int(optional)) + replica_task_max_inflight: # Deprecated compatibility field, still validated as 1..64; direct remote-Put singleflight does not use a global actor queue (int(optional)) require_transfer_rpc_fast_path_ready_timeout_seconds: # Require owner-owner transfer-rpc fast path before owner ready/shared.json publication (int(optional)) rdma_device_names: # Explicit RDMA devices for benchmark/test fast-path fanout (['{str}'](optional)) enable_side_transfer: false # Enable TCP side-transfer fast-path (bool(optional)) diff --git a/fluxon_py/kvclient/fluxon.py b/fluxon_py/kvclient/fluxon.py index c794c63..ef17660 100644 --- a/fluxon_py/kvclient/fluxon.py +++ b/fluxon_py/kvclient/fluxon.py @@ -1713,6 +1713,8 @@ def get_transfer( self, handle: GetStartHandle, concurrency: Optional[int] = None, + *, + consume_prefix_len: Optional[int] = None, ) -> int: if not isinstance(handle, GetStartHandle): raise TypeError(f"get_transfer requires GetStartHandle, got {type(handle)}") @@ -1729,12 +1731,48 @@ def get_transfer( f"first_miss_index={result.first_miss_index} " f"first_miss_group_index={result.first_miss_group_index}" ) + if consume_prefix_len is None: + normalized_consume_prefix_len = result.transferable_len + else: + if isinstance(consume_prefix_len, bool) or not isinstance( + consume_prefix_len, int + ): + raise TypeError( + "get_transfer consume_prefix_len must be an int or None, got " + f"{type(consume_prefix_len)}" + ) + normalized_consume_prefix_len = int(consume_prefix_len) + if ( + normalized_consume_prefix_len <= 0 + or normalized_consume_prefix_len > result.transferable_len + ): + raise ValueError( + "get_transfer consume_prefix_len must be within the live " + "transferable prefix: " + f"consume={normalized_consume_prefix_len} " + f"transferable={result.transferable_len}" + ) + group_lens = result.atomic_group_lens or (len(result.keys),) + group_end = 0 + for group_len in group_lens: + group_end += int(group_len) + if group_end >= normalized_consume_prefix_len: + break + if group_end != normalized_consume_prefix_len: + raise ValueError( + "get_transfer consume_prefix_len must end at an atomic-group " + "boundary: " + f"consume={normalized_consume_prefix_len} " + f"atomic_group_lens={group_lens}" + ) if self._client is None: raise RuntimeError( "Store not initialized when get_transfer(). Call setup() first." ) _ = concurrency - inner_res = self._client.get_transfer(handle.backend_handle) + inner_res = self._client.get_transfer( + handle.backend_handle, normalized_consume_prefix_len + ) if not inner_res.is_ok(): handle.closed = True raise RuntimeError(f"get_transfer backend error: {inner_res.unwrap_error()}") diff --git a/fluxon_py/kvclient/kvclient_interface.py b/fluxon_py/kvclient/kvclient_interface.py index bb248da..ead8e4e 100644 --- a/fluxon_py/kvclient/kvclient_interface.py +++ b/fluxon_py/kvclient/kvclient_interface.py @@ -30,7 +30,8 @@ class GetStartResult: - ``keys`` is the caller-provided ordered page-key sequence. - ``raw_prefix_hit_len`` is the page-level continuous hit prefix. - ``transferable_len`` is rounded down to complete atomic groups and is the - only prefix that can be consumed by get_transfer(). + maximum prefix that can be consumed by get_transfer(). A caller may + consume a shorter prefix only at an atomic-group boundary. """ keys: Tuple[str, ...] @@ -301,9 +302,12 @@ def get_transfer( self, handle: GetStartHandle, concurrency: Optional[int] = None, + *, + consume_prefix_len: Optional[int] = None, ) -> int: _ = handle _ = concurrency + _ = consume_prefix_len raise NotImplementedError( "get_transfer is only implemented by backends with native prefix get support" ) diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs index 09f5e0f..22b4882 100755 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs @@ -20,7 +20,7 @@ use crate::client_kv_api::{ ExternalGetStartSharedItemResult, ExternalGetStartTransferOutput, ExternalLocalFirstPutKeyReservation, ExternalPendingPutCtx, ExternalPutKeyOutcome, OwnerLocalPublishItem, OwnerLocalPublishJob, OwnerLocalReserveSlotLease, - OwnerLocalReserveSlotRef, ReplicaTaskTarget, + OwnerLocalReserveSlotRef, }; use crate::client_seg_pool::{ResolveSideTransferLaneReq, parse_side_transfer_worker_lane_idx}; use crate::cluster_manager::NodeIDString; @@ -29,7 +29,7 @@ use crate::cluster_manager::{ }; use crate::master_kv_router::msg_pack::{ BatchGetStartItemResp, BatchGetStartResp, BatchPutDoneItemReq, BatchPutRevokeItemReq, - BatchPutStartItemReq, GetPreparedLocalReserveTarget, PutAtomicGroup, PutDoneCommittedSlot, + GetPreparedLocalReserveTarget, PutAtomicGroup, PutDoneCommittedSlot, build_put_atomic_group_assignments, }; use crate::memholder::MemholderManagerTrait; @@ -570,6 +570,42 @@ pub(crate) fn compute_external_get_start_transfer_prefix( } } +pub(crate) fn validate_external_get_consume_prefix( + consume_prefix_len: usize, + transferable_len: usize, + group_lens: &[usize], +) -> KvResult<()> { + if consume_prefix_len == 0 || consume_prefix_len > transferable_len { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "external get_transfer consume_prefix_len must be within the live prefix: consume={} transferable={}", + consume_prefix_len, transferable_len + ), + })); + } + + let mut group_end = 0usize; + for group_len in group_lens.iter().copied() { + group_end = group_end.checked_add(group_len).ok_or_else(|| { + KvError::Api(ApiError::InvalidArgument { + detail: "external get_transfer atomic-group boundary overflowed usize".to_string(), + }) + })?; + if group_end >= consume_prefix_len { + break; + } + } + if group_end != consume_prefix_len { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "external get_transfer consume_prefix_len splits an atomic group: consume={} group_lens={:?}", + consume_prefix_len, group_lens + ), + })); + } + Ok(()) +} + fn collect_external_get_start_missing( keys: &[String], item_slots: &[Option], @@ -862,10 +898,12 @@ mod external_get_start_batch_tests { collect_external_get_start_missing, compute_external_get_start_raw_prefix, compute_external_get_start_transfer_prefix, decide_external_get_key_item, external_member_left_departed_epoch, normalize_external_put_start_group_lens, - partition_external_get_finish_leaders, register_external_get_key_under_fence, + observe_external_get_consume_phases, partition_external_get_finish_leaders, + register_external_get_key_under_fence, validate_external_get_consume_prefix, }; use crate::client_kv_api::{ - ExternalGetKeySharedOp, ExternalGetStartEntry, ExternalGetStartOwnerItem, + ExternalGetKeyInterest, ExternalGetKeySharedOp, ExternalGetKeySharedPhase, + ExternalGetStartEntry, ExternalGetStartOwnerItem, ExternalGetStartSharedItemResult, OwnerKeyControlState, }; use crate::master_kv_router::msg_pack::{ @@ -875,7 +913,7 @@ mod external_get_start_batch_tests { use dashmap::DashMap; use std::collections::HashMap; use std::sync::Arc; - use std::time::Instant; + use std::time::{Duration, Instant}; fn abandoned_handle_entry( req_node_id: &str, @@ -886,6 +924,7 @@ mod external_get_start_batch_tests { requester_node_start_time, keys: Vec::new(), items: Vec::new(), + atomic_group_lens: Vec::new(), created_at: Instant::now(), } } @@ -980,6 +1019,51 @@ mod external_get_start_batch_tests { ); } + #[test] + fn get_transfer_consume_prefix_must_be_live_and_end_at_group_boundary() { + let group_lens = [2, 2, 3]; + assert!(validate_external_get_consume_prefix(2, 4, &group_lens).is_ok()); + assert!(validate_external_get_consume_prefix(4, 4, &group_lens).is_ok()); + assert!(validate_external_get_consume_prefix(0, 4, &group_lens).is_err()); + assert!(validate_external_get_consume_prefix(1, 4, &group_lens).is_err()); + assert!(validate_external_get_consume_prefix(3, 4, &group_lens).is_err()); + assert!(validate_external_get_consume_prefix(5, 4, &group_lens).is_err()); + } + + #[test] + fn consume_phase_snapshot_distinguishes_ready_data_from_real_wait() { + let finishing = Arc::new(ExternalGetKeySharedOp::new("finishing".to_string())); + finishing.state.lock().phase = ExternalGetKeySharedPhase::Finishing { + item: BatchGetStartItemResp::default(), + }; + let ready = Arc::new(ExternalGetKeySharedOp::new("ready".to_string())); + let observed_at = Instant::now(); + { + let mut state = ready.state.lock(); + state.phase = ExternalGetKeySharedPhase::Ready { + result: ExternalGetStartSharedItemResult::Miss, + }; + state.terminal_at = Some(observed_at - Duration::from_millis(5)); + } + let items = vec![ + ExternalGetStartOwnerItem::Shared { + interest: ExternalGetKeyInterest::new(finishing, false), + }, + ExternalGetStartOwnerItem::Shared { + interest: ExternalGetKeyInterest::new(ready, false), + }, + ]; + + let snapshot = observe_external_get_consume_phases(&items, observed_at); + assert_eq!(snapshot.finishing, 1); + assert_eq!(snapshot.ready, 1); + assert_eq!(snapshot.pending_before_consume(), 1); + assert_eq!(snapshot.terminal_before_consume(), 1); + assert_eq!(snapshot.terminal_age_count, 1); + assert_eq!(snapshot.terminal_age_mean_us(), 5_000); + assert_eq!(snapshot.terminal_age_max_us, 5_000); + } + #[test] fn put_groups_default_per_item_and_reject_malformed_partitions() { assert_eq!( @@ -1134,9 +1218,11 @@ mod external_get_start_batch_tests { local_puts: 0, external_pending_puts: 0, external_put: None, + remote_put: None, source_eviction_selection: None, reclaim: None, external_get: Some(old.clone()), + local_access_fence: None, }, )]); clear_external_get_key_marker_locked(&mut controls, &old); @@ -1163,9 +1249,11 @@ mod external_get_start_batch_tests { local_puts: 0, external_pending_puts: 0, external_put: None, + remote_put: None, source_eviction_selection: None, reclaim: None, external_get: Some(op.clone()), + local_access_fence: None, }, )]); @@ -1242,6 +1330,92 @@ mod external_get_start_batch_tests { } } +#[derive(Debug, Default)] +struct ExternalGetConsumePhaseSnapshot { + local: usize, + starting: usize, + started: usize, + finishing: usize, + revoking: usize, + ready: usize, + failed: usize, + terminal_age_count: usize, + terminal_age_sum_us: u64, + terminal_age_max_us: u64, +} + +impl ExternalGetConsumePhaseSnapshot { + fn terminal_before_consume(&self) -> usize { + self.local + .saturating_add(self.ready) + .saturating_add(self.failed) + } + + fn pending_before_consume(&self) -> usize { + self.starting + .saturating_add(self.started) + .saturating_add(self.finishing) + .saturating_add(self.revoking) + } + + fn terminal_age_mean_us(&self) -> u64 { + if self.terminal_age_count == 0 { + 0 + } else { + self.terminal_age_sum_us / self.terminal_age_count as u64 + } + } +} + +fn observe_external_get_consume_phases( + items: &[ExternalGetStartOwnerItem], + observed_at: Instant, +) -> ExternalGetConsumePhaseSnapshot { + let mut snapshot = ExternalGetConsumePhaseSnapshot::default(); + for item in items { + let ExternalGetStartOwnerItem::Shared { interest } = item else { + snapshot.local = snapshot.local.saturating_add(1); + continue; + }; + let state = interest.op().state.lock(); + match &state.phase { + ExternalGetKeySharedPhase::Starting => { + snapshot.starting = snapshot.starting.saturating_add(1) + } + ExternalGetKeySharedPhase::Started { .. } => { + snapshot.started = snapshot.started.saturating_add(1) + } + ExternalGetKeySharedPhase::Finishing { .. } => { + snapshot.finishing = snapshot.finishing.saturating_add(1) + } + ExternalGetKeySharedPhase::Revoking { .. } => { + snapshot.revoking = snapshot.revoking.saturating_add(1) + } + ExternalGetKeySharedPhase::Ready { .. } => { + snapshot.ready = snapshot.ready.saturating_add(1) + } + ExternalGetKeySharedPhase::Failed { .. } => { + snapshot.failed = snapshot.failed.saturating_add(1) + } + } + if matches!( + &state.phase, + ExternalGetKeySharedPhase::Ready { .. } | ExternalGetKeySharedPhase::Failed { .. } + ) { + if let Some(age) = state + .terminal_at + .and_then(|terminal_at| observed_at.checked_duration_since(terminal_at)) + { + let age_us = age.as_micros().min(u64::MAX as u128) as u64; + snapshot.terminal_age_count = snapshot.terminal_age_count.saturating_add(1); + snapshot.terminal_age_sum_us = snapshot.terminal_age_sum_us.saturating_add(age_us); + snapshot.terminal_age_max_us = snapshot.terminal_age_max_us.max(age_us); + } + } + } + snapshot +} + async fn finish_external_get_start_transfer( view: crate::client_kv_api::ClientKvApiView, transfer_items: Vec, @@ -1526,6 +1700,7 @@ fn abandon_unstarted_external_get_key_locked( state.phase = ExternalGetKeySharedPhase::Ready { result: ExternalGetStartSharedItemResult::Miss, }; + state.terminal_at = Some(Instant::now()); clear_external_get_key_marker_locked(controls, op); true } @@ -1537,7 +1712,9 @@ fn publish_external_get_key_terminal( ) { { let mut controls = inner.owner_key_control.lock_key(&op.key); - op.state.lock().phase = phase; + let mut state = op.state.lock(); + state.phase = phase; + state.terminal_at = Some(Instant::now()); clear_external_get_key_marker_locked(&mut controls, op); } inner.untrack_external_get_flight(op); @@ -1804,6 +1981,7 @@ async fn classify_external_get_key_leader( item.error_json, ), }; + state.terminal_at = Some(Instant::now()); clear_external_get_key_marker_locked(&mut controls, &op); notify_terminal = true; Some(ExternalGetKeyLeaderAction::Terminal) @@ -2061,14 +2239,17 @@ async fn prepare_external_get_batch_plan( let (mut items, leaders) = plan_external_get_key_items(inner, &req.keys).await; if !leaders.is_empty() { let leader_keys = leaders.iter().map(|op| op.key.clone()).collect::>(); + let leader_count = leaders.len(); let spawn_view = inner.view.clone_view(); let worker_view = spawn_view.clone(); let transfer_concurrency = req.transfer_concurrency; spawn_view.spawn("external_get_key_singleflight", async move { + let batch_start_started_at = Instant::now(); let start_result = { let worker_inner = worker_view.client_kv_api().inner(); batch_get_start_with_local_reserve_targets(worker_inner, &leader_keys).await }; + let batch_start_us = duration_to_i64_us(batch_start_started_at.elapsed()); match start_result { Ok(start_resp) => { assert_eq!( @@ -2076,6 +2257,29 @@ async fn prepare_external_get_batch_plan( leaders.len(), "validated BatchGetStart response must match leader count" ); + let start_hits = start_resp + .items + .iter() + .filter(|item| item.error_code == OK) + .count(); + let start_misses = start_resp + .items + .iter() + .filter(|item| item.error_code == codes_api::API_KEY_NOT_FOUND) + .count(); + let start_errors = start_resp + .items + .len() + .saturating_sub(start_hits) + .saturating_sub(start_misses); + tracing::info!( + "external Get leader start lifecycle: leaders={} hits={} misses={} errors={} batch_get_start_us={} outcome=ok", + leader_count, + start_hits, + start_misses, + start_errors, + batch_start_us, + ); for (op, item) in leaders.iter().zip(start_resp.items) { publish_external_get_key_started(op, item); } @@ -2083,6 +2287,12 @@ async fn prepare_external_get_batch_plan( .await; } Err(err) => { + tracing::info!( + "external Get leader start lifecycle: leaders={} hits=0 misses=0 errors={} batch_get_start_us={} outcome=error", + leader_count, + leader_count, + batch_start_us, + ); let worker_inner = worker_view.client_kv_api().inner(); for op in &leaders { publish_external_get_key_failed(worker_inner, op, &err); @@ -2567,11 +2777,14 @@ impl HandlerForExternalClient for ClientKvApi { } let inner = self.inner(); self.validate_requester_owner_status_updated(req.started_time)?; + let observe_started_at = Instant::now(); + let requested_len = req.keys.len(); let group_lens = normalize_external_get_start_group_lens(req.keys.len(), req.atomic_group_lens.clone())?; let (prefix, transfer_keys, transfer_items) = prepare_external_get_batch_plan(inner, &req, &group_lens).await?; + let phase_snapshot = observe_external_get_consume_phases(&transfer_items, Instant::now()); let handle = inner .next_external_get_start_handle .fetch_add(1, Ordering::Relaxed); @@ -2607,11 +2820,36 @@ impl HandlerForExternalClient for ClientKvApi { .map(|member| member.node_start_time), keys: transfer_keys, items: transfer_items, + atomic_group_lens: group_lens, created_at: Instant::now(), }, ); ExternalBatchGetStartTransferPlan::OwnerRpc }; + let inline_local = matches!( + &transfer_plan, + ExternalBatchGetStartTransferPlan::InlineLocal { .. } + ); + tracing::info!( + "external Get start lifecycle: handle={} requested={} raw_prefix={} transferable={} inline_local={} local={} starting={} started={} finishing={} revoking={} ready={} failed={} terminal_before_return={} pending_before_return={} terminal_age_mean_us={} terminal_age_max_us={} total_us={}", + handle, + requested_len, + prefix.raw_prefix_hit_len, + prefix.transferable_len, + inline_local, + phase_snapshot.local, + phase_snapshot.starting, + phase_snapshot.started, + phase_snapshot.finishing, + phase_snapshot.revoking, + phase_snapshot.ready, + phase_snapshot.failed, + phase_snapshot.terminal_before_consume(), + phase_snapshot.pending_before_consume(), + phase_snapshot.terminal_age_mean_us(), + phase_snapshot.terminal_age_max_us, + duration_to_i64_us(observe_started_at.elapsed()), + ); Ok(ExternalBatchGetStartResp { error_code: OK, @@ -2633,8 +2871,10 @@ impl HandlerForExternalClient for ClientKvApi { } let inner = self.inner(); self.validate_requester_owner_status_updated(req.started_time)?; + let consume_started_at = Instant::now(); - let Some((_handle, entry)) = inner.external_get_start_registry.remove(&req.handle) else { + let Some((_handle, mut entry)) = inner.external_get_start_registry.remove(&req.handle) + else { return Err(KvError::Api(ApiError::KeyNotFound { key: format!("external_get_start_handle:{}", req.handle), })); @@ -2647,9 +2887,70 @@ impl HandlerForExternalClient for ClientKvApi { req.req_node_id ); } + if let Err(err) = validate_external_get_consume_prefix( + req.consume_prefix_len, + entry.keys.len(), + &entry.atomic_group_lens, + ) { + inner.external_get_start_registry.insert(req.handle, entry); + return Err(err); + } + assert_eq!( + entry.keys.len(), + entry.items.len(), + "external get-start registry keys and items must stay aligned" + ); + let available_prefix_len = entry.keys.len(); + let handle_age_us = duration_to_i64_us(entry.created_at.elapsed()); + let phase_snapshot = observe_external_get_consume_phases( + &entry.items[..req.consume_prefix_len], + Instant::now(), + ); + let tail_items = entry.items.split_off(req.consume_prefix_len); + entry.keys.truncate(req.consume_prefix_len); + if !tail_items.is_empty() { + tracing::info!( + "external_batch_get_transfer consumed prefix and released owner tail: handle={} available={} consumed={} released_tail={}", + req.handle, + available_prefix_len, + req.consume_prefix_len, + tail_items.len() + ); + } + drop(tail_items); let keys = entry.keys; - let transfer_results = - finish_external_get_start_transfer(inner.view.clone_view(), entry.items, 0).await?; + let finish_wait_started_at = Instant::now(); + let transfer_results_result = + finish_external_get_start_transfer(inner.view.clone_view(), entry.items, 0).await; + let finish_wait_us = duration_to_i64_us(finish_wait_started_at.elapsed()); + let transfer_results = match transfer_results_result { + Ok(results) => results, + Err(err) => { + tracing::info!( + "external Get consume lifecycle: handle={} available={} consumed={} released_tail={} handle_age_us={} local_before={} starting_before={} started_before={} finishing_before={} revoking_before={} ready_before={} failed_before={} terminal_before={} pending_before={} terminal_age_mean_us={} terminal_age_max_us={} finish_wait_us={} hits=0 misses=0 errors={} install_us=0 total_us={} outcome=error", + req.handle, + available_prefix_len, + req.consume_prefix_len, + available_prefix_len.saturating_sub(req.consume_prefix_len), + handle_age_us, + phase_snapshot.local, + phase_snapshot.starting, + phase_snapshot.started, + phase_snapshot.finishing, + phase_snapshot.revoking, + phase_snapshot.ready, + phase_snapshot.failed, + phase_snapshot.terminal_before_consume(), + phase_snapshot.pending_before_consume(), + phase_snapshot.terminal_age_mean_us(), + phase_snapshot.terminal_age_max_us, + finish_wait_us, + req.consume_prefix_len, + duration_to_i64_us(consume_started_at.elapsed()), + ); + return Err(err); + } + }; if transfer_results.len() != keys.len() { return Err(KvError::Api(ApiError::Unknown { detail: format!( @@ -2659,10 +2960,15 @@ impl HandlerForExternalClient for ClientKvApi { ), })); } + let install_started_at = Instant::now(); let mut items = Vec::with_capacity(transfer_results.len()); + let mut hits = 0usize; + let mut misses = 0usize; + let mut errors = 0usize; for (key, item_result) in keys.iter().zip(transfer_results) { match item_result { Ok(Some((memholder, _))) => { + hits = hits.saturating_add(1); let external_memholder_info = inner .install_external_get_holding(&req.req_node_id, memholder.memory_info()); items.push(ExternalBatchGetItemResp { @@ -2671,17 +2977,49 @@ impl HandlerForExternalClient for ClientKvApi { external_memholder_info: Some(external_memholder_info), }); } - Ok(None) => items.push(ExternalBatchGetItemResp { - error_code: codes_api::API_KEY_NOT_FOUND, - error_json: format!("Key not found: {}", key), - external_memholder_info: None, - }), - Err(err) => items.push(ExternalBatchGetItemResp { - external_memholder_info: None, - ..ExternalBatchGetItemResp::from_error(&err) - }), + Ok(None) => { + misses = misses.saturating_add(1); + items.push(ExternalBatchGetItemResp { + error_code: codes_api::API_KEY_NOT_FOUND, + error_json: format!("Key not found: {}", key), + external_memholder_info: None, + }); + } + Err(err) => { + errors = errors.saturating_add(1); + items.push(ExternalBatchGetItemResp { + external_memholder_info: None, + ..ExternalBatchGetItemResp::from_error(&err) + }); + } } } + let install_us = duration_to_i64_us(install_started_at.elapsed()); + tracing::info!( + "external Get consume lifecycle: handle={} available={} consumed={} released_tail={} handle_age_us={} local_before={} starting_before={} started_before={} finishing_before={} revoking_before={} ready_before={} failed_before={} terminal_before={} pending_before={} terminal_age_mean_us={} terminal_age_max_us={} finish_wait_us={} hits={} misses={} errors={} install_us={} total_us={} outcome=ok", + req.handle, + available_prefix_len, + req.consume_prefix_len, + available_prefix_len.saturating_sub(req.consume_prefix_len), + handle_age_us, + phase_snapshot.local, + phase_snapshot.starting, + phase_snapshot.started, + phase_snapshot.finishing, + phase_snapshot.revoking, + phase_snapshot.ready, + phase_snapshot.failed, + phase_snapshot.terminal_before_consume(), + phase_snapshot.pending_before_consume(), + phase_snapshot.terminal_age_mean_us(), + phase_snapshot.terminal_age_max_us, + finish_wait_us, + hits, + misses, + errors, + install_us, + duration_to_i64_us(consume_started_at.elapsed()), + ); Ok(ExternalBatchGetTransferResp { items, error_code: OK, @@ -2795,16 +3133,7 @@ impl HandlerForExternalClient for ClientKvApi { src_offset }; let remote_offset = put_start_resp.target_addr - put_start_resp.target_base_addr; - let replica_target = - put_start_resp - .replica_target - .as_ref() - .map(|target| ReplicaTaskTarget { - node_id: target.node_id.clone(), - target_offset: target.target_addr - target.target_base_addr, - target_base_addr: target.target_base_addr, - len: target.len, - }); + let replica_admitted = put_start_resp.replica_target.is_some(); inner.external_pending_puts.insert( ( req.key.clone(), @@ -2825,9 +3154,8 @@ impl HandlerForExternalClient for ClientKvApi { remote_offset }, len: req.len, - make_replica_task: req.make_replica_task && replica_target.is_some(), + make_replica_task: req.make_replica_task && replica_admitted, preferred_sub_cluster: req.preferred_sub_cluster.clone(), - replica_target, local_reserve_slot: None, local_reserve_slot_size: None, atomic_group: None, @@ -2915,6 +3243,7 @@ impl HandlerForExternalClient for ClientKvApi { let pending_fences = loop { let mut pending_fences = Vec::with_capacity(req.items.len()); let mut wait_for = None; + let mut wait_for_local_access = None; for item in &req.items { match inner.reserve_external_local_first_put_key( &item.key, @@ -2942,6 +3271,10 @@ impl HandlerForExternalClient for ClientKvApi { wait_for = Some((item.key.clone(), op)); break; } + Ok(ExternalLocalFirstPutKeyReservation::WaitForLocalAccess(completion)) => { + wait_for_local_access = Some((item.key.clone(), completion)); + break; + } Err(err) => { let items = req .items @@ -2956,6 +3289,37 @@ impl HandlerForExternalClient for ClientKvApi { } } } + if let Some((fenced_key, mut completion)) = wait_for_local_access { + // A partial atomic_batch must not hold local-put fences while + // the precise source-eviction/reclaim generation drains. The + // watch receiver was subscribed under the per-key lock, so a + // rollback/finalize between this drop and changed().await is + // observed without polling or a lost wakeup. + drop(pending_fences); + let wait_started_at = Instant::now(); + tracing::info!( + fenced_key, + items = req.items.len(), + "external local-first Put waiting for owner source/reclaim fence" + ); + loop { + if *completion.borrow_and_update() { + break; + } + if completion.changed().await.is_err() { + // The state owner disappeared; re-evaluate under the + // key lock instead of treating channel close as success. + break; + } + } + tracing::info!( + fenced_key, + items = req.items.len(), + wait_us = duration_to_i64_us(wait_started_at.elapsed()), + "external local-first Put resumed after owner source/reclaim fence" + ); + continue; + } let Some((joined_key, op)) = wait_for else { break pending_fences; }; @@ -3043,7 +3407,6 @@ impl HandlerForExternalClient for ClientKvApi { len: req_item.len, make_replica_task: req_item.make_replica_task, preferred_sub_cluster: req_item.preferred_sub_cluster.clone(), - replica_target: None, local_reserve_slot: Some(slot_ref.clone()), local_reserve_slot_size: Some(slot_size), atomic_group: atomic_groups[idx].clone(), @@ -3121,7 +3484,6 @@ impl HandlerForExternalClient for ClientKvApi { return Ok(ExternalPutTransferEndResp::from_error(&err)); } }; - let replica_target = pending_ctx.replica_target.clone(); let admitted_replica_task = pending_ctx.make_replica_task; let self_node_id = inner.view.cluster_manager().get_self_info().id.clone(); let req_remote_target = req @@ -3259,14 +3621,13 @@ impl HandlerForExternalClient for ClientKvApi { inner .external_pending_puts .invalidate(&(req.key.clone(), put_id.0, put_id.1)); - if admitted_replica_task && replica_target.is_some() { + if admitted_replica_task { if let Err(err) = inner - .make_replica_task( + .ensure_remote_put( &req.key, put_id, - replica_target - .clone() - .expect("make_replica_task requires pre-reserved replica target"), + pending_ctx.preferred_sub_cluster.clone(), + true, ) .await { @@ -3332,7 +3693,6 @@ impl HandlerForExternalClient for ClientKvApi { put_locality: Option<(bool, i64)>, local_cache_publish: LocalCommittedCachePublish, make_replica_task: bool, - replica_target: Option, // Keep the per-key reclaim fence alive until the master's terminal // response has been applied to the owner-local index. _pending_ctx: ExternalPendingPutCtx, @@ -3496,7 +3856,6 @@ impl HandlerForExternalClient for ClientKvApi { put_locality: Some((false, 0)), local_cache_publish, make_replica_task: pending_ctx.make_replica_task, - replica_target: pending_ctx.replica_target.clone(), _pending_ctx: pending_ctx, }); } @@ -3623,12 +3982,13 @@ impl HandlerForExternalClient for ClientKvApi { pending.put_id.1, )); if pending.make_replica_task { - let target = pending - .replica_target - .clone() - .expect("make_replica_task requires pre-reserved replica target"); if let Err(err) = inner - .make_replica_task(&pending.key, pending.put_id, target) + .ensure_remote_put( + &pending.key, + pending.put_id, + pending._pending_ctx.preferred_sub_cluster.clone(), + true, + ) .await { tracing::warn!( @@ -3720,7 +4080,6 @@ impl HandlerForExternalClient for ClientKvApi { } return Ok(ExternalPutCommitResp::from_error(&err)); } - let replica_target = pending_ctx.replica_target.clone(); let admitted_replica_task = pending_ctx.make_replica_task; let end_started_at = Instant::now(); @@ -3796,14 +4155,13 @@ impl HandlerForExternalClient for ClientKvApi { inner .external_pending_puts .invalidate(&(req.key.clone(), put_id.0, put_id.1)); - if admitted_replica_task && replica_target.is_some() { + if admitted_replica_task { if let Err(err) = inner - .make_replica_task( + .ensure_remote_put( &req.key, put_id, - replica_target - .clone() - .expect("make_replica_task requires pre-reserved replica target"), + pending_ctx.preferred_sub_cluster.clone(), + true, ) .await { @@ -3860,7 +4218,6 @@ impl HandlerForExternalClient for ClientKvApi { lease_id: Option, local_cache_publish: LocalCommittedCachePublish, make_replica_task: bool, - replica_target: Option, _pending_ctx: ExternalPendingPutCtx, } @@ -4015,7 +4372,6 @@ impl HandlerForExternalClient for ClientKvApi { lease_id: item.lease_id, local_cache_publish, make_replica_task: pending_ctx.make_replica_task, - replica_target: pending_ctx.replica_target.clone(), _pending_ctx: pending_ctx, }); } @@ -4136,12 +4492,13 @@ impl HandlerForExternalClient for ClientKvApi { pending.put_id.1, )); if pending.make_replica_task { - let target = pending - .replica_target - .clone() - .expect("make_replica_task requires pre-reserved replica target"); if let Err(err) = inner - .make_replica_task(&pending.key, pending.put_id, target) + .ensure_remote_put( + &pending.key, + pending.put_id, + pending._pending_ctx.preferred_sub_cluster.clone(), + true, + ) .await { tracing::warn!( diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs index 57c7164..ddc5803 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs @@ -256,6 +256,8 @@ impl ClientKvApiInner { if keys.is_empty() { return Ok(Vec::new()); } + let lifecycle_started_at = Instant::now(); + let lifecycle_requested_keys = keys.len(); #[derive(Clone)] struct DonePending { @@ -279,6 +281,11 @@ impl ClientKvApiInner { let mut done_pending = Vec::new(); let mut transfer_error_cleanup = Vec::new(); let mut transfer_futures = Vec::new(); + let mut lifecycle_zero_copy_items = 0usize; + let mut lifecycle_transfer_items = 0usize; + let mut lifecycle_remote_transfer_items = 0usize; + let mut lifecycle_transfer_bytes = 0u64; + let mut lifecycle_remote_transfer_bytes = 0u64; for (idx, (key, start_item)) in keys.into_iter().zip(start_items.into_iter()).enumerate() { if start_item.error_code == codes_api::API_KEY_NOT_FOUND { @@ -311,6 +318,7 @@ impl ClientKvApiInner { let len = start_item.len; if peer_id.is_none() && src_addr == target_addr { + lifecycle_zero_copy_items = lifecycle_zero_copy_items.saturating_add(1); done_pending.push(DonePending { idx, key, @@ -322,6 +330,14 @@ impl ClientKvApiInner { continue; } + lifecycle_transfer_items = lifecycle_transfer_items.saturating_add(1); + lifecycle_transfer_bytes = lifecycle_transfer_bytes.saturating_add(len); + if peer_is_remote { + lifecycle_remote_transfer_items = lifecycle_remote_transfer_items.saturating_add(1); + lifecycle_remote_transfer_bytes = + lifecycle_remote_transfer_bytes.saturating_add(len); + } + transfer_futures.push(async move { let transfer_started_at = Instant::now(); let transfer_result = self @@ -353,11 +369,22 @@ impl ClientKvApiInner { }); } + let lifecycle_plan_us = lifecycle_started_at + .elapsed() + .as_micros() + .min(i64::MAX as u128) as i64; + let transfer_wall_started_at = Instant::now(); + let mut lifecycle_transfer_sum_us = 0u64; + let mut lifecycle_transfer_max_us = 0u64; let mut transfer_stream = stream::iter(transfer_futures).buffer_unordered(transfer_concurrency); while let Some(joined) = transfer_stream.next().await { match joined { (idx, key, start_item, peer_is_remote, _get_id, transfer_us, Ok(_breakdown)) => { + let transfer_us_u64 = transfer_us.max(0) as u64; + lifecycle_transfer_sum_us = + lifecycle_transfer_sum_us.saturating_add(transfer_us_u64); + lifecycle_transfer_max_us = lifecycle_transfer_max_us.max(transfer_us_u64); done_pending.push(DonePending { idx, key, @@ -376,14 +403,24 @@ impl ClientKvApiInner { } } } + let lifecycle_transfer_wall_us = transfer_wall_started_at + .elapsed() + .as_micros() + .min(i64::MAX as u128) as i64; + let transfer_cleanup_started_at = Instant::now(); finish_started_get_revoke_cleanup( self, transfer_error_cleanup, "batch_get transfer failure", ) .await; + let lifecycle_transfer_cleanup_us = transfer_cleanup_started_at + .elapsed() + .as_micros() + .min(i64::MAX as u128) as i64; + let install_started_at = Instant::now(); let mut ready_done_pending = Vec::with_capacity(done_pending.len()); let mut install_failed_cleanup = Vec::new(); for mut pending in done_pending { @@ -434,14 +471,20 @@ impl ClientKvApiInner { "batch_get pending install failure", ) .await; + let lifecycle_install_us = install_started_at + .elapsed() + .as_micros() + .min(i64::MAX as u128) as i64; let done_get_ids = done_pending .iter() .map(|pending| pending.start_item.get_id) .collect::>(); + let lifecycle_done_items = done_get_ids.len(); let done_first_get_id = done_get_ids.first().copied(); let done_last_get_id = done_get_ids.last().copied(); let mut done_attempt = 1u32; + let done_started_at = Instant::now(); let done_resp = loop { match self.batch_get_done(done_get_ids.clone()).await { Ok(resp) if batch_get_done_response_matches(&done_get_ids, &resp) => break resp, @@ -477,6 +520,8 @@ impl ClientKvApiInner { .await; done_attempt = done_attempt.saturating_add(1); }; + let lifecycle_done_us = done_started_at.elapsed().as_micros().min(i64::MAX as u128) as i64; + let publish_started_at = Instant::now(); let master_node_id: NodeID = self .view .cluster_manager() @@ -622,11 +667,12 @@ impl ClientKvApiInner { // Publish every local index before Moka admission starts selecting // individual capacity victims. + let lifecycle_local_hot_admissions = local_hot_admissions.len(); for (key, put_id, memory_info, _atomic_group) in local_hot_admissions { self.owner_hot_track_committed(&key, put_id, &memory_info); } - Ok(results + let output = results .into_iter() .map(|item| { item.unwrap_or_else(|| { @@ -636,7 +682,50 @@ impl ClientKvApiInner { })) }) }) - .collect()) + .collect::>(); + let lifecycle_hits = output + .iter() + .filter(|item| matches!(item, Ok(Some(_)))) + .count(); + let lifecycle_misses = output + .iter() + .filter(|item| matches!(item, Ok(None))) + .count(); + let lifecycle_errors = output.iter().filter(|item| matches!(item, Err(_))).count(); + let lifecycle_publish_us = publish_started_at + .elapsed() + .as_micros() + .min(i64::MAX as u128) as i64; + let lifecycle_total_us = lifecycle_started_at + .elapsed() + .as_micros() + .min(i64::MAX as u128) as i64; + tracing::info!( + "external Get finish lifecycle: requested={} transfer_concurrency={} zero_copy_items={} transfer_items={} remote_transfer_items={} transfer_bytes={} remote_transfer_bytes={} plan_us={} transfer_wall_us={} transfer_sum_us={} transfer_max_us={} transfer_cleanup_us={} install_us={} done_items={} done_attempts={} done_us={} local_hot_admissions={} publish_us={} hits={} misses={} errors={} total_us={}", + lifecycle_requested_keys, + transfer_concurrency, + lifecycle_zero_copy_items, + lifecycle_transfer_items, + lifecycle_remote_transfer_items, + lifecycle_transfer_bytes, + lifecycle_remote_transfer_bytes, + lifecycle_plan_us, + lifecycle_transfer_wall_us, + lifecycle_transfer_sum_us, + lifecycle_transfer_max_us, + lifecycle_transfer_cleanup_us, + lifecycle_install_us, + lifecycle_done_items, + done_attempt, + lifecycle_done_us, + lifecycle_local_hot_admissions, + lifecycle_publish_us, + lifecycle_hits, + lifecycle_misses, + lifecycle_errors, + lifecycle_total_us, + ); + Ok(output) } pub async fn batch_get( diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs index fe309a7..fd5a06e 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs @@ -3,17 +3,18 @@ use crate::client_kv_api::local_reserve_rebalance::{ spawn_owner_local_reserve_rebalance_actor, spawn_owner_slot_pressure_actor, }; use crate::client_kv_api::msg_pack::{ - ExternalBatchGetCancelReq, ExternalBatchGetCancelResp, ExternalBatchGetReq, - ExternalBatchGetResp, ExternalBatchGetStartReq, ExternalBatchGetStartResp, - ExternalBatchGetTransferReq, ExternalBatchGetTransferResp, ExternalBatchIsExistReq, - ExternalBatchIsExistResp, ExternalBatchPutCommitReq, ExternalBatchPutCommitResp, - ExternalBatchPutStartReq, ExternalBatchPutStartResp, ExternalBatchPutTransferEndReq, - ExternalBatchPutTransferEndResp, ExternalDeleteAckReq, ExternalDeleteAckResp, - ExternalDeleteReq, ExternalDeleteResp, ExternalGetReq, ExternalGetResp, ExternalIsExistReq, - ExternalIsExistResp, ExternalObservabilitySnapshotReq, ExternalObservabilitySnapshotResp, - ExternalPutCommitReq, ExternalPutCommitResp, ExternalPutRevokeReq, ExternalPutRevokeResp, - ExternalPutStartReq, ExternalPutStartResp, ExternalPutTransferEndReq, - ExternalPutTransferEndResp, SyncKvToFileReq, SyncKvToFileResp, TestPutPhaseTrace, + ExternalBatchDeleteAckReq, ExternalBatchDeleteAckResp, ExternalBatchGetCancelReq, + ExternalBatchGetCancelResp, ExternalBatchGetReq, ExternalBatchGetResp, + ExternalBatchGetStartReq, ExternalBatchGetStartResp, ExternalBatchGetTransferReq, + ExternalBatchGetTransferResp, ExternalBatchIsExistReq, ExternalBatchIsExistResp, + ExternalBatchPutCommitReq, ExternalBatchPutCommitResp, ExternalBatchPutStartReq, + ExternalBatchPutStartResp, ExternalBatchPutTransferEndReq, ExternalBatchPutTransferEndResp, + ExternalDeleteAckReq, ExternalDeleteAckResp, ExternalDeleteReq, ExternalDeleteResp, + ExternalGetReq, ExternalGetResp, ExternalIsExistReq, ExternalIsExistResp, + ExternalObservabilitySnapshotReq, ExternalObservabilitySnapshotResp, ExternalPutCommitReq, + ExternalPutCommitResp, ExternalPutRevokeReq, ExternalPutRevokeResp, ExternalPutStartReq, + ExternalPutStartResp, ExternalPutTransferEndReq, ExternalPutTransferEndResp, SyncKvToFileReq, + SyncKvToFileResp, TestPutPhaseTrace, }; use crate::client_kv_api::reclaim::handle_batch_owner_reclaim; use crate::cluster_manager::{NodeID, NodeIDString}; @@ -59,18 +60,14 @@ use limit_thirdparty::tokio; use moka::notification::RemovalCause; use parking_lot::Mutex; use std::collections::BTreeSet; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::hash::{Hash, Hasher}; use std::sync::Weak; -use std::sync::atomic::{AtomicU32, AtomicU64, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering}; use std::sync::{Arc, OnceLock}; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; use tracing::warn; -const REPLICA_TASK_QUEUE_CAPACITY: usize = 128; -// Queue only weak source references. This preserves a deep policy backlog without turning queued -// write-back work into non-reclaimable owner memory; the dispatcher pins a still-current source -// immediately before handing it to the bounded replica-task actor. const OWNER_LOCAL_PUBLISH_QUEUE_CAPACITY: usize = 4096; const OWNER_LOCAL_PUBLISH_MAX_INFLIGHT: usize = 64; @@ -99,6 +96,18 @@ pub struct OwnerRuntimeObserveSnapshot { pub external_get_undecided_interests: u64, pub external_get_retained_interests: u64, pub external_pending_put_entries: u64, + pub remote_put_flights_active: u64, + pub remote_put_flight_leaders: u64, + pub remote_put_flight_followers: u64, + pub remote_put_source_unavailable: u64, + pub remote_put_source_fenced: u64, + pub remote_put_source_missing: u64, + pub remote_put_source_version_mismatch: u64, + pub remote_put_transfers: u64, + pub remote_put_published: u64, + pub remote_put_already_satisfied: u64, + pub remote_put_obsolete: u64, + pub remote_put_failed: u64, pub local_reserve_slots_free: u64, pub local_reserve_slots_prepared: u64, pub local_reserve_slots_pending_visible: u64, @@ -242,6 +251,10 @@ pub struct ExternalGetKeySharedState { /// Number of those operations whose transferable prefix retained the key. pub retained: usize, pub phase: ExternalGetKeySharedPhase, + /// Monotonic publication time for Ready/Failed. Observation-only users + /// compare this with the later handle-consume time to distinguish data + /// that was already ready from time actually spent waiting in Transfer. + pub terminal_at: Option, } pub struct ExternalGetKeySharedOp { @@ -258,6 +271,7 @@ impl ExternalGetKeySharedOp { undecided: 1, retained: 0, phase: ExternalGetKeySharedPhase::Starting, + terminal_at: None, }), notify: Arc::new(limit_thirdparty::tokio::sync::Notify::new()), } @@ -292,6 +306,7 @@ pub struct ExternalGetStartEntry { pub requester_node_start_time: Option, pub keys: Vec, pub items: Vec, + pub atomic_group_lens: Vec, pub created_at: Instant, } @@ -924,6 +939,89 @@ async fn handle_external_delete_ack( raw_bytes: Vec::new(), } } + +fn release_external_holder_ids_with( + holder_ids: Vec, + mut remove: impl FnMut(u64) -> bool, +) -> (u32, u32) { + let mut seen = HashSet::with_capacity(holder_ids.len()); + let mut released = 0u32; + let mut missing = 0u32; + for holder_id in holder_ids { + if !seen.insert(holder_id) { + continue; + } + if remove(holder_id) { + released = released.saturating_add(1); + } else { + missing = missing.saturating_add(1); + } + } + (released, missing) +} + +async fn handle_external_batch_delete_ack( + view: &ClientKvApiView, + msg: &MsgPack, +) -> MsgPack { + let req = msg.serialize_part.clone(); + let expected = view.cluster_manager().get_self_info().node_start_time; + if req.started_time != 0 && req.started_time != expected { + let err = crate::rpcresp_kvresult_convert::msg_and_error::KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::OwnerStartTimeMismatch { + expected, + got: req.started_time, + }, + ); + return MsgPack { + serialize_part: ExternalBatchDeleteAckResp::from_error(&err), + raw_bytes: Vec::new(), + }; + } + + let inner = view.client_kv_api().inner(); + let external_client_id = req.external_client_id; + let requested_count = req.holder_ids.len(); + let (released_count, missing_count) = + release_external_holder_ids_with(req.holder_ids, |holder_id| { + inner + .external_get_holding + .remove(&NodeHolderKey::new(external_client_id.clone(), holder_id)) + .is_some() + }); + tracing::debug!( + external_client_id, + requested_count, + released_count, + missing_count, + "processed external holder ACK batch" + ); + MsgPack { + serialize_part: ExternalBatchDeleteAckResp { + released_count, + missing_count, + error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, + error_json: String::new(), + }, + raw_bytes: Vec::new(), + } +} + +#[cfg(test)] +mod external_delete_ack_batch_tests { + use super::release_external_holder_ids_with; + use std::collections::HashSet; + + #[test] + fn duplicate_and_missing_holder_ids_are_idempotent() { + let mut live = HashSet::from([3u64, 5u64]); + let (released, missing) = + release_external_holder_ids_with(vec![3, 3, 4, 5], |holder_id| live.remove(&holder_id)); + assert_eq!((released, missing), (2, 1)); + assert!(live.is_empty()); + } +} + async fn handle_external_delete( view: &ClientKvApiView, msg: &MsgPack, @@ -1285,6 +1383,22 @@ struct OwnerHotCacheCounters { legacy_put_done_items: AtomicU64, } +#[derive(Default)] +struct OwnerRemotePutCounters { + active: AtomicU64, + leaders: AtomicU64, + followers: AtomicU64, + source_unavailable: AtomicU64, + source_fenced: AtomicU64, + source_missing: AtomicU64, + source_version_mismatch: AtomicU64, + transfers: AtomicU64, + published: AtomicU64, + already_satisfied: AtomicU64, + obsolete: AtomicU64, + failed: AtomicU64, +} + struct OwnerHotSelectionDebt { weight_bytes: u64, outstanding_bytes: Arc, @@ -1568,6 +1682,110 @@ pub(crate) struct ExternalPutKeySharedOp { outcome: watch::Sender, } +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(crate) enum OwnerRemotePutOutcome { + InFlight, + Published, + AlreadySatisfied, + Obsolete, + Failed, +} + +#[derive(Clone, Debug)] +pub(crate) struct OwnerRemotePutRequest { + pub preferred_sub_cluster: Option, + pub protect_source_on_remote_complete: bool, +} + +/// One owner-initiated remote write for an exact local generation. +/// +/// Every trigger (normal Put, pre-reserved replica, proactive write-back, and +/// tier1) joins this same operation. The trigger is deliberately absent from +/// the identity so policy labels cannot create a second payload transfer. +pub(crate) struct OwnerRemotePutSharedOp { + pub key: String, + pub put_id: crate::master_kv_router::put::PutIDForAKey, + request: Mutex, + outcome: watch::Sender, + completed: AtomicBool, +} + +impl OwnerRemotePutSharedOp { + fn new( + key: &str, + put_id: crate::master_kv_router::put::PutIDForAKey, + preferred_sub_cluster: Option, + protect_source_on_remote_complete: bool, + ) -> Arc { + let (outcome, _receiver) = watch::channel(OwnerRemotePutOutcome::InFlight); + Arc::new(Self { + key: key.to_string(), + put_id, + request: Mutex::new(OwnerRemotePutRequest { + preferred_sub_cluster, + protect_source_on_remote_complete, + }), + outcome, + completed: AtomicBool::new(false), + }) + } + + fn merge_request( + &self, + preferred_sub_cluster: Option, + protect_source_on_remote_complete: bool, + ) { + let mut request = self.request.lock(); + if request.preferred_sub_cluster.is_none() { + request.preferred_sub_cluster = preferred_sub_cluster; + } + request.protect_source_on_remote_complete |= protect_source_on_remote_complete; + } + + pub(crate) fn request(&self) -> OwnerRemotePutRequest { + self.request.lock().clone() + } + + pub(crate) fn outcome(&self) -> OwnerRemotePutOutcome { + *self.outcome.borrow() + } + + fn complete(&self, outcome: OwnerRemotePutOutcome) -> bool { + debug_assert_ne!(outcome, OwnerRemotePutOutcome::InFlight); + if self + .completed + .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire) + .is_err() + { + return false; + } + self.outcome.send_replace(outcome); + true + } + + pub(crate) async fn wait(&self) -> OwnerRemotePutOutcome { + let mut outcome = self.outcome.subscribe(); + loop { + let current = *outcome.borrow_and_update(); + if current != OwnerRemotePutOutcome::InFlight { + return current; + } + if outcome.changed().await.is_err() { + return OwnerRemotePutOutcome::Failed; + } + } + } +} + +pub(crate) enum OwnerRemotePutReservation { + Leader { + op: Arc, + memory_info: Arc, + }, + Follower(Arc), + SourceUnavailable, +} + impl ExternalPutKeySharedOp { fn new() -> Arc { let (outcome, _receiver) = watch::channel(ExternalPutKeyOutcome::InFlight); @@ -1598,6 +1816,11 @@ impl ExternalPutKeySharedOp { pub(crate) enum ExternalLocalFirstPutKeyReservation { Leader(Arc), Wait(Arc), + /// A committed owner-local source is between precise source selection and + /// reclaim completion/rollback. The caller owns only a watch receiver: + /// it holds no key fence or physical slot while asynchronously waiting to + /// re-evaluate the complete atomic_batch. + WaitForLocalAccess(watch::Receiver), } #[derive(Default)] @@ -1611,6 +1834,10 @@ pub(crate) struct OwnerKeyControlState { /// The reject-on-inflight local-first Put leader for this key. Followers /// subscribe to its terminal result without claiming another slot. external_put: Option>, + /// Exact-generation owner-side remote Put singleflight. Unlike + /// `external_put`, this remains active after local publication until the + /// remote Start/transfer/Done state machine reaches a terminal outcome. + remote_put: Option>, /// Owner-local pre-Prepare fence installed by the Moka source-eviction /// dispatcher. The matching committed index is moved into this record, /// so a new local Get cannot acquire the source between victim selection @@ -1621,6 +1848,10 @@ pub(crate) struct OwnerKeyControlState { /// the same fence as local visibility and reclaim so `R ∩ local`, /// `R ∩ inflight`, and new leaders are classified atomically. external_get: Option>, + /// Completion channel for the exact source-selection/reclaim fence. A + /// receiver subscribed under the key-shard lock cannot miss completion, + /// even if the fence clears before the waiter is first polled. + local_access_fence: Option>, } impl OwnerKeyControlState { @@ -1632,9 +1863,50 @@ impl OwnerKeyControlState { self.local_puts == 0 && self.external_pending_puts == 0 && self.external_put.is_none() + && self.remote_put.is_none() && self.source_eviction_selection.is_none() && self.reclaim.is_none() && self.external_get.is_none() + && self.local_access_fence.is_none() + } + + fn begin_local_access_fence(&mut self) { + assert!( + self.local_access_fence.is_none(), + "one key cannot install two owner local-access fence generations" + ); + let (completion, _receiver) = watch::channel(false); + self.local_access_fence = Some(completion); + } + + fn subscribe_local_access_fence(&self) -> watch::Receiver { + assert!( + self.local_access_fenced(), + "local-access waiter requires an active source/reclaim fence" + ); + self.local_access_fence + .as_ref() + .expect("active source/reclaim fence must own a completion channel") + .subscribe() + } + + fn finish_local_access_fence(&mut self) { + assert!( + !self.local_access_fenced(), + "local-access completion cannot publish before the source/reclaim fence clears" + ); + if let Some(completion) = self.local_access_fence.take() { + completion.send_replace(true); + } + } + + fn install_remote_put_leader(&mut self, op: Arc) { + if let Some(displaced) = self.remote_put.replace(op.clone()) { + assert_ne!( + displaced.put_id, op.put_id, + "a matching remote Put generation must join instead of being replaced" + ); + } } } @@ -2109,6 +2381,7 @@ pub struct ClientKvApiInner { owner_source_eviction_selected: Arc>>, owner_hot_counters: Arc, + owner_remote_put_counters: Arc, owner_hot_retry_queue: Arc, owner_hot_eviction_tx: tokio::sync::ampsc::UnboundedSender, owner_hot_eviction_rx: @@ -2185,8 +2458,6 @@ pub struct ClientKvApiInner { external_pending_puts: moka::sync::SegmentedCache<(String, u64, u32), ExternalPendingPutCtx>, owner_local_publish_tx: tokio::sync::ampsc::Sender, owner_local_publish_rx: Mutex>>, - replica_task_tx: tokio::sync::ampsc::Sender, - replica_task_rx: Mutex>>, } impl ClientKvApiInner { @@ -2287,6 +2558,7 @@ impl ClientKvApiInner { replaced.is_none(), "rolling back an owner source selection must restore an empty local index" ); + state.finish_local_access_fence(); if state.is_idle() { controls.remove(&identity.key); } @@ -2331,6 +2603,7 @@ impl ClientKvApiInner { let control_busy = controls.get(&identity.key).is_some_and(|state| { state.local_puts != 0 || state.external_pending_puts != 0 + || state.remote_put.is_some() || state.external_get.is_some() || state.local_access_fenced() }); @@ -2357,6 +2630,8 @@ impl ClientKvApiInner { let state = controls.entry(identity.key.clone()).or_default(); assert!(state.source_eviction_selection.is_none()); + assert!(state.reclaim.is_none()); + state.begin_local_access_fence(); state.source_eviction_selection = Some(OwnerSourceEvictionSelection { put_id: (identity.put_time_ms, identity.put_version), cached_info, @@ -2552,13 +2827,19 @@ impl ClientKvApiInner { reject_if_exist_same_key: bool, ) -> KvResult { let mut controls = self.owner_key_control.lock_key(key); - if controls - .get(key) - .is_some_and(|state| state.local_access_fenced()) + let reusable_singleflight = reject_if_inflight_same_key && reject_if_exist_same_key; + if let Some(state) = controls.get(key) + && state.local_access_fenced() { - return Err(KvError::Api(ApiError::KeyBeingWritten { - key: key.to_string(), - })); + return if reusable_singleflight { + Ok(ExternalLocalFirstPutKeyReservation::WaitForLocalAccess( + state.subscribe_local_access_fence(), + )) + } else { + Err(KvError::Api(ApiError::KeyBeingWritten { + key: key.to_string(), + })) + }; } if reject_if_exist_same_key && (self.precommit_local_visible_info.contains_key(key) @@ -2571,7 +2852,6 @@ impl ClientKvApiInner { })); } let state = controls.entry(key.to_string()).or_default(); - let reusable_singleflight = reject_if_inflight_same_key && reject_if_exist_same_key; if reject_if_inflight_same_key && state.local_puts > 0 { return (reusable_singleflight) .then(|| state.external_put.clone()) @@ -2709,6 +2989,144 @@ impl ClientKvApiInner { }) } + pub(crate) fn begin_owner_remote_put( + &self, + key: &str, + put_id: crate::master_kv_router::put::PutIDForAKey, + preferred_sub_cluster: Option, + protect_source_on_remote_complete: bool, + ) -> OwnerRemotePutReservation { + let mut controls = self.owner_key_control.lock_key(key); + + if let Some(existing) = controls.get(key).and_then(|state| state.remote_put.clone()) { + if existing.put_id == put_id && existing.outcome() == OwnerRemotePutOutcome::InFlight { + existing.merge_request(preferred_sub_cluster, protect_source_on_remote_complete); + self.owner_remote_put_counters + .followers + .fetch_add(1, Ordering::Relaxed); + return OwnerRemotePutReservation::Follower(existing); + } + if existing.outcome() != OwnerRemotePutOutcome::InFlight { + let state = controls + .get_mut(key) + .expect("terminal remote Put flight control state disappeared"); + if state + .remote_put + .as_ref() + .is_some_and(|current| Arc::ptr_eq(current, &existing)) + { + state.remote_put = None; + } + } + // A newer local generation may publish before the old remote task + // observes Obsolete. The new generation may replace the visible + // per-key flight slot after its exact source is verified below; + // the displaced task keeps its own holder and its pointer-checked + // completion cannot clear the replacement. + } + + if controls + .get(key) + .is_some_and(|state| state.local_access_fenced()) + { + self.owner_remote_put_counters + .source_unavailable + .fetch_add(1, Ordering::Relaxed); + self.owner_remote_put_counters + .source_fenced + .fetch_add(1, Ordering::Relaxed); + return OwnerRemotePutReservation::SourceUnavailable; + } + let memory_info = match self.get_cached_info.get(key) { + Some(info) if (info.put_time_ms, info.put_version) == put_id => info.mem_holder.clone(), + Some(_) => { + self.owner_remote_put_counters + .source_unavailable + .fetch_add(1, Ordering::Relaxed); + self.owner_remote_put_counters + .source_version_mismatch + .fetch_add(1, Ordering::Relaxed); + return OwnerRemotePutReservation::SourceUnavailable; + } + None => { + self.owner_remote_put_counters + .source_unavailable + .fetch_add(1, Ordering::Relaxed); + self.owner_remote_put_counters + .source_missing + .fetch_add(1, Ordering::Relaxed); + return OwnerRemotePutReservation::SourceUnavailable; + } + }; + + let op = OwnerRemotePutSharedOp::new( + key, + put_id, + preferred_sub_cluster, + protect_source_on_remote_complete, + ); + let state = controls.entry(key.to_string()).or_default(); + state.install_remote_put_leader(op.clone()); + self.owner_remote_put_counters + .active + .fetch_add(1, Ordering::Relaxed); + self.owner_remote_put_counters + .leaders + .fetch_add(1, Ordering::Relaxed); + OwnerRemotePutReservation::Leader { op, memory_info } + } + + pub(crate) fn finish_owner_remote_put( + &self, + op: &Arc, + outcome: OwnerRemotePutOutcome, + ) -> bool { + if !op.complete(outcome) { + return false; + } + + let mut controls = self.owner_key_control.lock_key(&op.key); + let remove_control = if let Some(state) = controls.get_mut(&op.key) { + if state + .remote_put + .as_ref() + .is_some_and(|current| Arc::ptr_eq(current, op)) + { + state.remote_put = None; + } + state.is_idle() + } else { + false + }; + if remove_control { + controls.remove(&op.key); + } + drop(controls); + + self.owner_remote_put_counters + .active + .fetch_sub(1, Ordering::Relaxed); + let terminal_counter = match outcome { + OwnerRemotePutOutcome::InFlight => { + unreachable!("remote Put cannot finish with an inflight outcome") + } + OwnerRemotePutOutcome::Published => &self.owner_remote_put_counters.published, + OwnerRemotePutOutcome::AlreadySatisfied => { + &self.owner_remote_put_counters.already_satisfied + } + OwnerRemotePutOutcome::Obsolete => &self.owner_remote_put_counters.obsolete, + OwnerRemotePutOutcome::Failed => &self.owner_remote_put_counters.failed, + }; + terminal_counter.fetch_add(1, Ordering::Relaxed); + true + } + + pub(crate) fn record_owner_remote_put_transfer(&self) { + self.owner_remote_put_counters + .transfers + .fetch_add(1, Ordering::Relaxed); + } + fn local_visible_mem_holder_unfenced(&self, key: &str) -> Option> { if let Some(info) = self.precommit_local_visible_info.get(key) { return Some(info.mem_holder.clone()); @@ -3189,7 +3607,6 @@ pub struct ExternalPendingPutCtx { pub len: u64, pub make_replica_task: bool, pub preferred_sub_cluster: Option, - pub replica_target: Option, pub local_reserve_slot: Option, pub local_reserve_slot_size: Option, pub atomic_group: Option, @@ -3198,26 +3615,6 @@ pub struct ExternalPendingPutCtx { pub(crate) _pending_fence: Arc, } -#[derive(Debug, Clone)] -pub(crate) struct ReplicaTaskTarget { - pub node_id: String, - pub target_offset: u64, - pub target_base_addr: u64, - pub len: u64, -} - -pub(crate) struct ReplicaTaskJob { - pub key: String, - pub put_id: crate::master_kv_router::put::PutIDForAKey, - /// Replica tasks are independent hit-rate work and keep their transfer - /// source alive until the transfer finishes. Capacity eviction never enters - /// this queue. - pub holder: Option>, - pub target: Option, - pub preferred_sub_cluster: Option, - pub protect_source_on_remote_complete: bool, -} - #[derive(Debug, Clone, Eq, PartialEq)] pub(crate) enum OwnerLocalReserveSlotState { Free, @@ -3835,16 +4232,19 @@ impl OwnerLocalReserveClassState { #[cfg(test)] mod owner_reclaim_slot_tests { use super::{ - ExternalLocalFirstPutKeyReservation, ExternalPendingPutCtx, ExternalPendingPutFenceGuard, - ExternalPutKeyOutcome, ExternalPutKeySharedOp, OwnerHotCacheCounters, OwnerHotCacheEntry, + ApiError, ClientKvApi, ClientKvApiNewArg, ExternalLocalFirstPutKeyReservation, + ExternalPendingPutCtx, ExternalPendingPutFenceGuard, ExternalPutKeyOutcome, + ExternalPutKeySharedOp, KvError, OwnerHotCacheCounters, OwnerHotCacheEntry, OwnerHotEvictionDispatch, OwnerHotEvictionEvent, OwnerHotPinAlias, OwnerHotReplicaIdentity, OwnerHotRetryQueue, OwnerHotSelectionDebt, OwnerHotSelectionFenceOutcome, OwnerKeyControlState, OwnerKeyControlTable, OwnerLocalReserveGrantState, OwnerLocalReserveSlotLease, OwnerLocalReserveSlotRef, OwnerLocalReserveSlotState, - OwnerReclaimRecord, acquire_external_pending_put_fence_for_key, + OwnerReclaimRecord, OwnerRemotePutOutcome, OwnerRemotePutReservation, + OwnerRemotePutSharedOp, acquire_external_pending_put_fence_for_key, allocate_external_holding_id, build_owner_hot_cache, clone_if_owner_hot_entry_matches, owner_hot_source_has_active_holders, pin_current_owner_hot_source_from_index, }; + use crate::config::TestSpecConfig; use crate::master_kv_router::msg_pack::{ BatchOwnerReclaimReq, OwnerReclaimBacking, OwnerReclaimItem, OwnerReclaimItemState, OwnerReclaimPhase, OwnerReclaimReason, OwnerSourceEvictionVictim, @@ -3905,9 +4305,11 @@ mod owner_reclaim_slot_tests { local_puts: 1, external_pending_puts: 1, external_put: None, + remote_put: None, source_eviction_selection: None, reclaim: None, external_get: None, + local_access_fence: None, }, ); let guard = Arc::new(ExternalPendingPutFenceGuard { @@ -3935,9 +4337,11 @@ mod owner_reclaim_slot_tests { local_puts: 1, external_pending_puts: 1, external_put: Some(op.clone()), + remote_put: None, source_eviction_selection: None, reclaim: None, external_get: None, + local_access_fence: None, }, ); let leader = Arc::new(ExternalPendingPutFenceGuard { @@ -3972,9 +4376,11 @@ mod owner_reclaim_slot_tests { local_puts: 1, external_pending_puts: 1, external_put: Some(op.clone()), + remote_put: None, source_eviction_selection: None, reclaim: None, external_get: None, + local_access_fence: None, }, ); let leader = Arc::new(ExternalPendingPutFenceGuard { @@ -3998,6 +4404,182 @@ mod owner_reclaim_slot_tests { assert!(controls.lock_key(key).get(key).is_none()); } + #[limit_thirdparty::tokio::test] + async fn every_remote_put_trigger_joins_one_owner_generation_flight() { + let key = "remote-put-singleflight"; + let put_id = (77, 3); + let api = ClientKvApi::construct(ClientKvApiNewArg { + test_spec_config: TestSpecConfig::default(), + owner_hot_cache_capacity_bytes: None, + }) + .await + .expect("construct test ClientKvApi"); + let op = OwnerRemotePutSharedOp::new(key, put_id, None, false); + api.inner().owner_key_control.lock_key(key).insert( + key.to_string(), + OwnerKeyControlState { + remote_put: Some(op.clone()), + ..Default::default() + }, + ); + api.inner() + .owner_remote_put_counters + .active + .store(1, Ordering::Relaxed); + api.inner() + .owner_remote_put_counters + .leaders + .store(1, Ordering::Relaxed); + + for follower in 0..64 { + let preferred = (follower == 0).then(|| "tier1".to_string()); + let protect_source = follower == 63; + match api + .inner() + .begin_owner_remote_put(key, put_id, preferred, protect_source) + { + OwnerRemotePutReservation::Follower(joined) => { + assert!(Arc::ptr_eq(&joined, &op)); + } + OwnerRemotePutReservation::Leader { .. } => { + panic!("a follower created a second remote Put leader") + } + OwnerRemotePutReservation::SourceUnavailable => { + panic!("a matching active remote Put flight was not reusable") + } + } + } + + let request = op.request(); + assert_eq!(request.preferred_sub_cluster.as_deref(), Some("tier1")); + assert!(request.protect_source_on_remote_complete); + assert_eq!( + api.inner() + .owner_remote_put_counters + .followers + .load(Ordering::Relaxed), + 64 + ); + assert!(matches!( + api.inner() + .begin_owner_remote_put(key, (78, 0), None, false), + OwnerRemotePutReservation::SourceUnavailable + )); + + assert!( + api.inner() + .finish_owner_remote_put(&op, OwnerRemotePutOutcome::Published) + ); + assert!( + !api.inner() + .finish_owner_remote_put(&op, OwnerRemotePutOutcome::Failed) + ); + assert_eq!( + ::tokio::time::timeout(Duration::from_secs(1), op.wait()) + .await + .expect("remote Put followers must observe the terminal result"), + OwnerRemotePutOutcome::Published + ); + assert!( + api.inner() + .owner_key_control + .lock_key(key) + .get(key) + .is_none() + ); + assert_eq!( + api.inner() + .owner_remote_put_counters + .active + .load(Ordering::Relaxed), + 0 + ); + } + + #[limit_thirdparty::tokio::test] + async fn new_remote_put_generation_replaces_old_without_aba_cleanup() { + let key = "remote-put-generation-aba"; + let api = ClientKvApi::construct(ClientKvApiNewArg { + test_spec_config: TestSpecConfig::default(), + owner_hot_cache_capacity_bytes: None, + }) + .await + .expect("construct test ClientKvApi"); + let old = OwnerRemotePutSharedOp::new(key, (80, 0), None, false); + let new = OwnerRemotePutSharedOp::new(key, (81, 0), None, false); + api.inner().owner_key_control.lock_key(key).insert( + key.to_string(), + OwnerKeyControlState { + remote_put: Some(old.clone()), + ..Default::default() + }, + ); + api.inner() + .owner_remote_put_counters + .active + .store(2, Ordering::Relaxed); + api.inner() + .owner_key_control + .lock_key(key) + .get_mut(key) + .expect("old generation control state") + .install_remote_put_leader(new.clone()); + let current = api + .inner() + .owner_key_control + .lock_key(key) + .get(key) + .and_then(|state| state.remote_put.clone()) + .expect("new generation must own the visible flight slot"); + assert!(Arc::ptr_eq(¤t, &new)); + assert_eq!( + api.inner() + .owner_remote_put_counters + .active + .load(Ordering::Relaxed), + 2 + ); + + assert!( + api.inner() + .finish_owner_remote_put(&old, OwnerRemotePutOutcome::Obsolete) + ); + let current = api + .inner() + .owner_key_control + .lock_key(key) + .get(key) + .and_then(|state| state.remote_put.clone()) + .expect("old completion must retain the new generation flight"); + assert!(Arc::ptr_eq(¤t, &new)); + assert_eq!( + api.inner() + .owner_remote_put_counters + .active + .load(Ordering::Relaxed), + 1 + ); + + assert!( + api.inner() + .finish_owner_remote_put(&new, OwnerRemotePutOutcome::Published) + ); + assert!( + api.inner() + .owner_key_control + .lock_key(key) + .get(key) + .is_none() + ); + assert_eq!( + api.inner() + .owner_remote_put_counters + .active + .load(Ordering::Relaxed), + 0 + ); + } + #[test] fn failed_local_slot_release_keeps_key_fence_closed() { let controls = controls_with_state( @@ -4006,9 +4588,11 @@ mod owner_reclaim_slot_tests { local_puts: 1, external_pending_puts: 1, external_put: None, + remote_put: None, source_eviction_selection: None, reclaim: None, external_get: None, + local_access_fence: None, }, ); let guard = Arc::new(ExternalPendingPutFenceGuard { @@ -4036,9 +4620,11 @@ mod owner_reclaim_slot_tests { local_puts: 1, external_pending_puts: 1, external_put: None, + remote_put: None, source_eviction_selection: None, reclaim: None, external_get: None, + local_access_fence: None, }, ); let guard = Arc::new(ExternalPendingPutFenceGuard { @@ -4089,7 +4675,6 @@ mod owner_reclaim_slot_tests { len: 1, make_replica_task: false, preferred_sub_cluster: None, - replica_target: None, local_reserve_slot: None, local_reserve_slot_size: None, atomic_group: None, @@ -4177,6 +4762,9 @@ mod owner_reclaim_slot_tests { ExternalLocalFirstPutKeyReservation::Wait(_) => { panic!("the first same-key Put cannot be a follower") } + ExternalLocalFirstPutKeyReservation::WaitForLocalAccess(_) => { + panic!("an unfenced key cannot wait for local access") + } }; let join_probe_waiter = match inner .reserve_external_local_first_put_key("put-join-probe", true, true) @@ -4186,6 +4774,9 @@ mod owner_reclaim_slot_tests { ExternalLocalFirstPutKeyReservation::Leader(_) => { panic!("the second same-key Put must not claim a second leader fence") } + ExternalLocalFirstPutKeyReservation::WaitForLocalAccess(_) => { + panic!("a local-Put follower must wait on the leader result") + } }; join_probe_leader.mark_local_put_succeeded(); assert_eq!( @@ -4252,6 +4843,40 @@ mod owner_reclaim_slot_tests { acquire_external_pending_put_fence_for_key(&inner.owner_key_control, key).is_err(), "a new local Put must not cross a source-selection fence" ); + let rollback_waiter = match inner + .reserve_external_local_first_put_key(key, true, true) + .expect("idempotent local-first Put must asynchronously wait for source selection") + { + ExternalLocalFirstPutKeyReservation::WaitForLocalAccess(waiter) => waiter, + ExternalLocalFirstPutKeyReservation::Leader(_) => { + panic!("a source-fenced key cannot claim a local-Put leader") + } + ExternalLocalFirstPutKeyReservation::Wait(_) => { + panic!("a source-fenced key has no local-Put leader to join") + } + }; + let second_rollback_waiter = match inner + .reserve_external_local_first_put_key(key, true, true) + .expect("all idempotent local-first Puts must share the fence completion") + { + ExternalLocalFirstPutKeyReservation::WaitForLocalAccess(waiter) => waiter, + _ => panic!("a second source-fence waiter must not claim a Put fence"), + }; + let cancelled_rollback_waiter = match inner + .reserve_external_local_first_put_key(key, true, true) + .expect("a cancellable Put may subscribe to the same fence completion") + { + ExternalLocalFirstPutKeyReservation::WaitForLocalAccess(waiter) => waiter, + _ => panic!("a cancellable source-fence waiter must not claim a Put fence"), + }; + // Simulate an external RPC being cancelled before reclaim completes. + // Dropping one receiver must neither retain the physical source nor + // prevent the shared generation from waking the remaining waiters. + drop(cancelled_rollback_waiter); + assert!(matches!( + inner.reserve_external_local_first_put_key(key, true, false), + Err(KvError::Api(ApiError::KeyBeingWritten { .. })) + )); drop(source); let master_id = master .cluster_manager_view() @@ -4333,6 +4958,25 @@ mod owner_reclaim_slot_tests { inner.local_visible_mem_holder(key).is_some(), "Abort must restore the exact committed local index" ); + for mut waiter in [rollback_waiter, second_rollback_waiter] { + ::tokio::time::timeout(Duration::from_secs(1), async { + loop { + if *waiter.borrow_and_update() { + break; + } + waiter + .changed() + .await + .expect("rollback completion sender must remain live"); + } + }) + .await + .expect("Abort must wake every live source-fence Put waiter"); + } + assert!(matches!( + inner.reserve_external_local_first_put_key(key, true, true), + Err(KvError::Api(ApiError::KeyAlreadyExists { .. })) + )); let trigger_weak = { let cached = inner @@ -4382,6 +5026,13 @@ mod owner_reclaim_slot_tests { ), ) ); + let mut direct_delete_waiter = match inner + .reserve_external_local_first_put_key(key, true, true) + .expect("direct-delete source fence must expose an async waiter") + { + ExternalLocalFirstPutKeyReservation::WaitForLocalAccess(waiter) => waiter, + _ => panic!("direct-delete source fence must not admit a local Put"), + }; super::reclaim::complete_owner_source_eviction( inner, &OwnerSourceEvictionVictim { @@ -4398,6 +5049,27 @@ mod owner_reclaim_slot_tests { inner.owner_key_control.lock_key(key).get(key).is_none(), "direct local completion must clear the source fence in one call" ); + ::tokio::time::timeout(Duration::from_secs(1), async { + loop { + if *direct_delete_waiter.borrow_and_update() { + break; + } + direct_delete_waiter + .changed() + .await + .expect("finalize completion sender must remain live"); + } + }) + .await + .expect("direct-delete Finalize must wake the source-fence Put waiter"); + let post_delete_leader = match inner + .reserve_external_local_first_put_key(key, true, true) + .expect("a physically reclaimed key must be eligible for a new local Put") + { + ExternalLocalFirstPutKeyReservation::Leader(leader) => leader, + _ => panic!("a reclaimed key must re-evaluate to a fresh leader"), + }; + drop(post_delete_leader); stop_master_and_client(master, client).await; } @@ -4611,12 +5283,14 @@ mod owner_reclaim_slot_tests { local_puts: 0, external_pending_puts: 0, external_put: None, + remote_put: None, source_eviction_selection: None, reclaim: Some(OwnerReclaimRecord::Committed(OwnerReclaimItem { key: "fenced".to_string(), ..OwnerReclaimItem::default() })), external_get: None, + local_access_fence: Some(::tokio::sync::watch::channel(false).0), }, ); let mut resolved_keys = Vec::new(); @@ -5016,6 +5690,54 @@ impl ClientKvApiInner { external_get_undecided_interests, external_get_retained_interests, external_pending_put_entries: self.external_pending_puts.entry_count(), + remote_put_flights_active: self + .owner_remote_put_counters + .active + .load(Ordering::Relaxed), + remote_put_flight_leaders: self + .owner_remote_put_counters + .leaders + .load(Ordering::Relaxed), + remote_put_flight_followers: self + .owner_remote_put_counters + .followers + .load(Ordering::Relaxed), + remote_put_source_unavailable: self + .owner_remote_put_counters + .source_unavailable + .load(Ordering::Relaxed), + remote_put_source_fenced: self + .owner_remote_put_counters + .source_fenced + .load(Ordering::Relaxed), + remote_put_source_missing: self + .owner_remote_put_counters + .source_missing + .load(Ordering::Relaxed), + remote_put_source_version_mismatch: self + .owner_remote_put_counters + .source_version_mismatch + .load(Ordering::Relaxed), + remote_put_transfers: self + .owner_remote_put_counters + .transfers + .load(Ordering::Relaxed), + remote_put_published: self + .owner_remote_put_counters + .published + .load(Ordering::Relaxed), + remote_put_already_satisfied: self + .owner_remote_put_counters + .already_satisfied + .load(Ordering::Relaxed), + remote_put_obsolete: self + .owner_remote_put_counters + .obsolete + .load(Ordering::Relaxed), + remote_put_failed: self + .owner_remote_put_counters + .failed + .load(Ordering::Relaxed), local_reserve_slots_free, local_reserve_slots_prepared, local_reserve_slots_pending_visible, @@ -5625,6 +6347,21 @@ impl ClientKvApi { reserve_committed = snapshot.local_reserve_slots_committed, "owner Get lifecycle snapshot" ); + tracing::info!( + active = snapshot.remote_put_flights_active, + leaders = snapshot.remote_put_flight_leaders, + followers = snapshot.remote_put_flight_followers, + source_unavailable = snapshot.remote_put_source_unavailable, + source_fenced = snapshot.remote_put_source_fenced, + source_missing = snapshot.remote_put_source_missing, + source_version_mismatch = snapshot.remote_put_source_version_mismatch, + transfers = snapshot.remote_put_transfers, + published = snapshot.remote_put_published, + already_satisfied = snapshot.remote_put_already_satisfied, + obsolete = snapshot.remote_put_obsolete, + failed = snapshot.remote_put_failed, + "owner unified remote Put flight snapshot" + ); if snapshot.hot_cache_capacity_bytes > 0 { tracing::info!( capacity_bytes = snapshot.hot_cache_capacity_bytes, @@ -5670,8 +6407,6 @@ impl ClientKvApi { test_spec_config, owner_hot_cache_capacity_bytes, } = arg; - let (replica_task_tx, replica_task_rx) = - tokio::sync::ampsc::channel(REPLICA_TASK_QUEUE_CAPACITY); let (owner_local_publish_tx, owner_local_publish_rx) = tokio::sync::ampsc::channel(OWNER_LOCAL_PUBLISH_QUEUE_CAPACITY); // The Moka eviction listener is synchronous and must never block while @@ -5685,6 +6420,7 @@ impl ClientKvApi { let owner_key_control = Arc::new(OwnerKeyControlTable::default()); let owner_source_eviction_selected = Arc::new(DashMap::new()); let owner_hot_counters = Arc::new(OwnerHotCacheCounters::default()); + let owner_remote_put_counters = Arc::new(OwnerRemotePutCounters::default()); let owner_hot_retry_queue = Arc::new(OwnerHotRetryQueue::new(owner_hot_counters.clone())); let owner_hot_cache = owner_hot_cache_capacity_bytes.map(|capacity_bytes| { build_owner_hot_cache( @@ -5716,6 +6452,7 @@ impl ClientKvApi { owner_hot_cache, owner_source_eviction_selected, owner_hot_counters, + owner_remote_put_counters, owner_hot_retry_queue, owner_hot_eviction_tx, owner_hot_eviction_rx: Mutex::new(Some(owner_hot_eviction_rx)), @@ -5772,8 +6509,6 @@ impl ClientKvApi { default_lease_id: parking_lot::RwLock::new(None), owner_local_publish_tx, owner_local_publish_rx: Mutex::new(Some(owner_local_publish_rx)), - replica_task_tx, - replica_task_rx: Mutex::new(Some(replica_task_rx)), }; Ok(Self(inner)) } @@ -6129,6 +6864,20 @@ impl ClientKvApi { }, ); + let view_ext = inner.view.clone_view(); + RPCHandler::::new().regist( + inner.view.p2p_module(), + move |resp, msg| { + let view = view_ext.clone(); + let view_task = view.clone(); + view.spawn("rpc_external_batch_delete_ack", async move { + let result = handle_external_batch_delete_ack(&view_task, &msg).await; + let _ = resp.send_resp(result).await; + }); + Ok(()) + }, + ); + // KV->file sync RPC (bytes field -> file@offset) RPCCaller::::new().regist(inner.view.p2p_module()); let view_ext = inner.view.clone_view(); @@ -6210,18 +6959,6 @@ impl ClientKvApi { .expect("delete_ack_batch rx already taken, that's impossible"); delete::spawn_owner_delete_ack_batch(inner.view.clone_view(), delete_ack_batch_rx); - if let Some(replica_task_rx) = inner.replica_task_rx.lock().take() { - put::spawn_replica_task_actor( - inner.view.clone_view(), - replica_task_rx, - inner - .test_spec_config - .replica_task_max_inflight - .unwrap_or(1) as usize, - ); - } else { - tracing::warn!("replica_task_rx already taken for ClientKvApi"); - } if inner.owner_hot_cache.is_some() { if let Some(owner_hot_eviction_rx) = inner.owner_hot_eviction_rx.lock().take() { put::spawn_owner_source_eviction_dispatcher( diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs index fe83d34..b0077c7 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs @@ -173,6 +173,9 @@ pub struct ExternalBatchGetTransferReq { pub req_node_id: String, /// Owner node_start_time observed by external when request starts pub started_time: i64, + /// Complete atomic-group prefix selected by the consumer from the live + /// get-start handle. + pub consume_prefix_len: usize, } impl MsgPackSerializePart for ExternalBatchGetTransferReq { fn msg_id(&self) -> u32 { @@ -236,7 +239,7 @@ impl MsgPackSerializePart for ExternalBatchGetCancelResp { mod external_batch_get_plan_wire_tests { use super::{ ExternalBatchGetCancelPlan, ExternalBatchGetCancelReq, ExternalBatchGetItemResp, - ExternalBatchGetStartResp, ExternalBatchGetStartTransferPlan, + ExternalBatchGetStartResp, ExternalBatchGetStartTransferPlan, ExternalBatchGetTransferReq, }; use crate::memholder::ExternalMemHolderInfo; use crate::rpcresp_kvresult_convert::msg_and_error::OK; @@ -273,6 +276,16 @@ mod external_batch_get_plan_wire_tests { .is_some_and(|info| info.holder_id == 23) )); + let transfer = ExternalBatchGetTransferReq { + handle: 19, + req_node_id: "external-a".to_string(), + started_time: 29, + consume_prefix_len: 1, + }; + let decoded_transfer: ExternalBatchGetTransferReq = + bitcode::decode(&bitcode::encode(&transfer)).expect("decode transfer request"); + assert_eq!(decoded_transfer.consume_prefix_len, 1); + let cancel = ExternalBatchGetCancelReq { handle: 19, req_node_id: "external-a".to_string(), @@ -802,6 +815,54 @@ impl MsgPackSerializePart for ExternalDeleteAckResp { } } +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchDeleteAckReq { + pub external_client_id: String, + pub holder_ids: Vec, + /// Owner node_start_time observed when these holders were created. + pub started_time: i64, +} +impl MsgPackSerializePart for ExternalBatchDeleteAckReq { + fn msg_id(&self) -> u32 { + 4036 + } +} +impl RPCReq for ExternalBatchDeleteAckReq { + type Resp = ExternalBatchDeleteAckResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchDeleteAckResp { + pub released_count: u32, + pub missing_count: u32, + pub error_code: ErrorCode, + pub error_json: String, +} +impl MsgPackSerializePart for ExternalBatchDeleteAckResp { + fn msg_id(&self) -> u32 { + 4037 + } +} + +#[cfg(test)] +mod external_batch_delete_ack_wire_tests { + use super::ExternalBatchDeleteAckReq; + + #[test] + fn compact_holder_id_batch_round_trips() { + let request = ExternalBatchDeleteAckReq { + external_client_id: "external-a".to_string(), + holder_ids: vec![3, 5, 8], + started_time: 17, + }; + let decoded: ExternalBatchDeleteAckReq = + bitcode::decode(&bitcode::encode(&request)).expect("decode holder ACK batch"); + assert_eq!(decoded.external_client_id, "external-a"); + assert_eq!(decoded.holder_ids, vec![3, 5, 8]); + assert_eq!(decoded.started_time, 17); + } +} + // --- RPC: Owner -> External to invalidate weak-index cache for keys --- #[derive(Default, Debug, Clone, Encode, Decode)] pub struct ExternalInvalidateWeakIndexItem { diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs index 8c70d68..d8bcc0a 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs @@ -2,7 +2,7 @@ use super::{ ClientKvApiInner, OwnerHotEvictionEvent, OwnerHotEvictionPreparation, OwnerHotSelectionFenceOutcome, OwnerLocalReserveClassState, OwnerLocalReserveGrantState, OwnerLocalReservePoolState, OwnerLocalReserveSlotLease, OwnerLocalReserveSlotRef, - ReplicaTaskJob, ReplicaTaskTarget, + OwnerRemotePutOutcome, OwnerRemotePutReservation, OwnerRemotePutSharedOp, local_reserve_rebalance::{owner_local_reserve_timeout_config, wait_owner_local_reserve_ready}, }; use crate::OWNER_LOCAL_RESERVE_GRANT_QUANTUM_BYTES; @@ -40,7 +40,6 @@ use crate::{ }; use chrono::Utc; use fluxon_commu::TransferBreakdown; -use futures::future::join_all; use limit_thirdparty::tokio; use std::sync::{Arc, atomic::Ordering}; use std::time::{Duration, Instant}; @@ -632,7 +631,7 @@ pub struct OwnerReservedPutItem { pub peer_node_id: Option, pub remember_local_snapshot: bool, pub make_replica_task: bool, - pub replica_target: Option, + pub preferred_sub_cluster: Option, } #[derive(Debug, Clone)] @@ -1078,16 +1077,7 @@ impl ClientKvApiInner { } else { Some(start_item.node_id.clone()) }; - let replica_target = - start_item - .replica_target - .as_ref() - .map(|target| ReplicaTaskTarget { - node_id: target.node_id.clone(), - target_offset: target.target_addr - target.target_base_addr, - target_base_addr: target.target_base_addr, - len: target.len, - }); + let replica_admitted = start_item.replica_target.is_some(); revoke_items.push(BatchPutRevokeItemReq { key: start_req.key.clone(), put_id: start_item.put_id, @@ -1103,8 +1093,8 @@ impl ClientKvApiInner { lease_id, peer_node_id: peer_node_id.clone(), remember_local_snapshot: true, - make_replica_task: start_req.make_replica_task && replica_target.is_some(), - replica_target, + make_replica_task: start_req.make_replica_task && replica_admitted, + preferred_sub_cluster: start_req.preferred_sub_cluster, }); } @@ -1198,13 +1188,13 @@ impl ClientKvApiInner { self.remember_local_snapshot(&pending.item.key, pending.item.put_id); } if pending.item.make_replica_task { - let target = pending - .item - .replica_target - .clone() - .expect("make_replica_task requires pre-reserved replica target"); if let Err(err) = self - .make_replica_task(&pending.item.key, pending.item.put_id, target) + .ensure_remote_put( + &pending.item.key, + pending.item.put_id, + pending.item.preferred_sub_cluster.clone(), + true, + ) .await { tracing::warn!( @@ -1315,7 +1305,7 @@ impl ClientKvApiInner { lease_id: Option, remember_local_snapshot: bool, make_replica_task: bool, - replica_target: Option, + preferred_sub_cluster: Option, } let mut results: Vec>> = (0..keys.len()).map(|_| None).collect(); @@ -1323,7 +1313,7 @@ impl ClientKvApiInner { let short_circuit_payload = self.short_circuit_put_payload_path_enabled(); let skip_put_end_commit = self.skip_put_end_commit_enabled(); - for (idx, (((key, ptrs), payload_len), start_item)) in keys + for (idx, (((key, ptrs), _payload_len), start_item)) in keys .into_iter() .zip(ptrs_groups.into_iter()) .zip(payload_lens.into_iter()) @@ -1340,16 +1330,7 @@ impl ClientKvApiInner { let put_id = start_item.put_id; let remember_local_snapshot = true; - let replica_target = - start_item - .replica_target - .as_ref() - .map(|target| ReplicaTaskTarget { - node_id: target.node_id.clone(), - target_offset: target.target_addr - target.target_base_addr, - target_base_addr: target.target_base_addr, - len: target.len, - }); + let replica_admitted = start_item.replica_target.is_some(); if !short_circuit_payload { unsafe { @@ -1363,8 +1344,8 @@ impl ClientKvApiInner { put_id, lease_id, remember_local_snapshot, - make_replica_task: make_replica_task && replica_target.is_some(), - replica_target, + make_replica_task: make_replica_task && replica_admitted, + preferred_sub_cluster: preferred_sub_cluster.clone(), }); } @@ -1417,12 +1398,13 @@ impl ClientKvApiInner { self.remember_local_snapshot(&pending.key, pending.put_id); } if pending.make_replica_task { - let target = pending - .replica_target - .clone() - .expect("make_replica_task requires pre-reserved replica target"); if let Err(err) = self - .make_replica_task(&pending.key, pending.put_id, target) + .ensure_remote_put( + &pending.key, + pending.put_id, + pending.preferred_sub_cluster.clone(), + true, + ) .await { tracing::warn!( @@ -1449,102 +1431,71 @@ impl ClientKvApiInner { .collect()) } - pub async fn make_replica_task( - &self, - key: &str, - put_id: PutIDForAKey, - target: ReplicaTaskTarget, - ) -> KvResult<()> { - let Some(memory_info) = self.local_committed_mem_holder_for_put_id(key, put_id) else { - tracing::warn!( - "replica task source holder is unavailable or version-mismatched after local commit; dropping replica task: key={} put_id=({},{})", - key, - put_id.0, - put_id.1 - ); - return Ok(()); - }; - - let holder = Arc::new(UserMemHolder::new( - memory_info, - self.get_or_init_all_memholder_refcount(), - UserMemHolderExposeKind::SegPtr, - )); - - // A full queue must apply backpressure. Dropping a promised replica task leaves a - // local-only committed slot that reserve reclaim cannot safely release. - match self - .replica_task_tx - .send(ReplicaTaskJob { - key: key.to_string(), - put_id, - holder: Some(holder), - target: Some(target), - preferred_sub_cluster: None, - protect_source_on_remote_complete: true, - }) - .await - { - Ok(()) => Ok(()), - Err(err) => { - tracing::warn!( - "replica task actor queue closed; local-only commit remains valid: key={} put_id=({},{}) err={}", - key, - put_id.0, - put_id.1, - err - ); - Ok(()) - } - } - } - - pub async fn make_replica_append_task( + /// Ensure one remote backing exists for an exact owner-local generation. + /// + /// Normal Put, pre-reserved replica, proactive write-back, and tier1 all + /// enter here. Only the flight leader pins the source and immediately + /// launches Start/transfer/Done in its own async task; there is no actor or + /// intermediate work queue. Followers wait for and reuse that terminal + /// result instead of acquiring their own holder. + pub async fn ensure_remote_put( &self, key: &str, put_id: PutIDForAKey, preferred_sub_cluster: Option, protect_source_on_remote_complete: bool, ) -> KvResult { - let Some(memory_info) = self.local_committed_mem_holder_for_put_id(key, put_id) else { - tracing::warn!( - "replica append task source holder is unavailable or version-mismatched after local publish; dropping replica task: key={} put_id=({},{})", + let mut follower_takeover_attempted = false; + loop { + match self.begin_owner_remote_put( key, - put_id.0, - put_id.1 - ); - return Ok(false); - }; - - let holder = Arc::new(UserMemHolder::new( - memory_info, - self.get_or_init_all_memholder_refcount(), - UserMemHolderExposeKind::SegPtr, - )); - - // Preserve append tasks under burst load for the same reclaim-safety reason above. - match self - .replica_task_tx - .send(ReplicaTaskJob { - key: key.to_string(), put_id, - holder: Some(holder), - target: None, - preferred_sub_cluster, + preferred_sub_cluster.clone(), protect_source_on_remote_complete, - }) - .await - { - Ok(()) => Ok(true), - Err(err) => { - tracing::warn!( - "replica append task actor queue closed; local-only commit remains valid: key={} put_id=({},{}) err={}", - key, - put_id.0, - put_id.1, - err - ); - Ok(false) + ) { + OwnerRemotePutReservation::Leader { op, memory_info } => { + let holder = Arc::new(UserMemHolder::new( + memory_info, + self.get_or_init_all_memholder_refcount(), + UserMemHolderExposeKind::SegPtr, + )); + let spawn_view = self.view.clone_view(); + let task_view = spawn_view.clone(); + let _ = spawn_view.spawn("owner_remote_put_leader", async move { + run_owner_remote_put(task_view, op, holder).await; + }); + return Ok(true); + } + OwnerRemotePutReservation::Follower(op) => { + tracing::debug!( + "owner remote Put joined existing flight: key={} put_id=({},{})", + op.key, + op.put_id.0, + op.put_id.1 + ); + match op.wait().await { + OwnerRemotePutOutcome::Published + | OwnerRemotePutOutcome::AlreadySatisfied => return Ok(true), + OwnerRemotePutOutcome::Obsolete => return Ok(false), + OwnerRemotePutOutcome::Failed if !follower_takeover_attempted => { + follower_takeover_attempted = true; + continue; + } + OwnerRemotePutOutcome::Failed => return Ok(false), + OwnerRemotePutOutcome::InFlight => { + unreachable!("remote Put wait must return a terminal outcome") + } + } + } + OwnerRemotePutReservation::SourceUnavailable => { + tracing::warn!( + "owner remote Put source is unavailable, fenced, or version-mismatched: key={} put_id=({},{})", + key, + put_id.0, + put_id.1 + ); + return Ok(false); + } } } } @@ -1609,15 +1560,7 @@ impl ClientKvApiInner { }; let abs_src = resp.src_addr; let abs_target = resp.target_addr; - let replica_target = resp - .replica_target - .as_ref() - .map(|target| ReplicaTaskTarget { - node_id: target.node_id.clone(), - target_offset: target.target_addr - target.target_base_addr, - target_base_addr: target.target_base_addr, - len: target.len, - }); + let replica_admitted = resp.replica_target.is_some(); #[cfg(test)] { @@ -1662,15 +1605,9 @@ impl ClientKvApiInner { ); self.put_end(key, put_id, lease_id).await?; self.remember_local_snapshot(key, put_id); - if make_replica_task && replica_target.is_some() { + if make_replica_task && replica_admitted { if let Err(err) = self - .make_replica_task( - key, - put_id, - replica_target - .clone() - .expect("make_replica_task requires pre-reserved replica target"), - ) + .ensure_remote_put(key, put_id, preferred_sub_cluster.map(str::to_string), true) .await { tracing::warn!( @@ -1739,15 +1676,9 @@ impl ClientKvApiInner { self.put_end(key, put_id, lease_id).await?; self.remember_local_snapshot(key, put_id); - if make_replica_task && replica_target.is_some() { + if make_replica_task && replica_admitted { if let Err(err) = self - .make_replica_task( - key, - put_id, - replica_target - .clone() - .expect("make_replica_task requires pre-reserved replica target"), - ) + .ensure_remote_put(key, put_id, preferred_sub_cluster.map(str::to_string), true) .await { tracing::warn!( @@ -2284,7 +2215,12 @@ impl ClientKvApiInner { Ok(resp.serialize_part) } - pub async fn put_append_revoke(&self, key: &str, put_id: PutIDForAKey) -> KvResult<()> { + pub async fn put_append_revoke( + &self, + key: &str, + put_id: PutIDForAKey, + operation_id: u64, + ) -> KvResult<()> { if !self.view.register_shutdown_poller().is_running() { return Err(KvError::Api(ApiError::SystemShutdown { detail: "ClientKvApi is shutting down; rejecting put_append_revoke".to_string(), @@ -2294,6 +2230,7 @@ impl ClientKvApiInner { serialize_part: PutAppendRevokeReq { key: key.to_string(), put_id, + operation_id, }, raw_bytes: Vec::new(), }; @@ -2320,6 +2257,7 @@ impl ClientKvApiInner { &self, key: &str, put_id: PutIDForAKey, + operation_id: u64, ) -> KvResult { if !self.view.register_shutdown_poller().is_running() { return Err(KvError::Api(ApiError::SystemShutdown { @@ -2330,6 +2268,7 @@ impl ClientKvApiInner { serialize_part: PutAppendDoneReq { key: key.to_string(), put_id, + operation_id, }, raw_bytes: Vec::new(), }; @@ -2840,7 +2779,6 @@ impl ClientKvApiInner { } } -const REPLICA_TASK_BATCH_MERGE_WINDOW: Duration = Duration::from_millis(2); const OWNER_LOCAL_PUBLISH_RETRY_INITIAL: Duration = Duration::from_millis(25); const OWNER_LOCAL_PUBLISH_RETRY_MAX: Duration = Duration::from_secs(1); @@ -2945,20 +2883,29 @@ mod owner_hot_replica_policy_tests { async fn start_replica_append_with_retry( inner: &ClientKvApiInner, - job: &ReplicaTaskJob, + op: &OwnerRemotePutSharedOp, len: u32, ) -> KvResult { + let request = op.request(); inner .put_append_start( - &job.key, - job.put_id, + &op.key, + op.put_id, len, - job.preferred_sub_cluster.as_deref(), - job.protect_source_on_remote_complete, + request.preferred_sub_cluster.as_deref(), + request.protect_source_on_remote_complete, ) .await } +struct RemotePutTarget { + operation_id: u64, + node_id: String, + target_offset: u64, + target_base_addr: u64, + len: u64, +} + fn owner_source_eviction_identity( victim: &OwnerSourceEvictionVictim, ) -> super::OwnerHotReplicaIdentity { @@ -3205,6 +3152,38 @@ async fn process_owner_source_eviction_events( return; } + let retryable = response + .victims + .iter() + .filter(|result| { + matches!( + result.outcome, + OwnerSourceEvictionOutcome::RetryableBusy | OwnerSourceEvictionOutcome::Unspecified + ) + }) + .count(); + if retryable != 0 + && let Some((index, result)) = response.victims.iter().enumerate().find(|(_, result)| { + matches!( + result.outcome, + OwnerSourceEvictionOutcome::RetryableBusy | OwnerSourceEvictionOutcome::Unspecified + ) + }) + { + let victim = &prepared[index].1; + tracing::warn!( + operation_id = response.operation_id, + victims = response.victims.len(), + retryable, + first_victim_index = result.victim_index, + key = %victim.key, + put_time_ms = victim.put_id.0, + put_version = victim.put_id.1, + detail = %result.detail, + "owner source direct-delete batch has retryable victims" + ); + } + for (index, ((event, victim), result)) in prepared .into_iter() .zip(response.victims.into_iter()) @@ -3427,512 +3406,177 @@ pub fn spawn_owner_hot_retry_actor(view: ClientKvApiView) { }); } -async fn process_replica_task(view_task: ClientKvApiView, mut job: ReplicaTaskJob) { - let inner = view_task.client_kv_api().inner(); - let holder = job - .holder - .as_ref() - .expect("replica task source must be pinned before transfer"); - let src_offset = holder.memory_info().offset; - let len = holder.get_length() as u64; - let target = if let Some(target) = job.target.clone() { - target - } else { - let len_u32 = match u32::try_from(len) { - Ok(len_u32) => len_u32, - Err(_) => { - tracing::warn!( - "replica append task length does not fit u32: key={} put_id=({},{}) len={}", - job.key, - job.put_id.0, - job.put_id.1, - len - ); - return; - } - }; - let append_start = match start_replica_append_with_retry(inner, &job, len_u32).await { - Ok(resp) => resp, - Err(err) => { - tracing::warn!( - "replica append task start failed: key={} put_id=({},{}) err={}", - job.key, - job.put_id.0, - job.put_id.1, - err - ); - return; - } - }; - match append_start.outcome { - PutAppendStartOutcome::Scheduled => {} - PutAppendStartOutcome::AlreadySatisfied | PutAppendStartOutcome::Obsolete => return, - PutAppendStartOutcome::RetryableNoSpace | PutAppendStartOutcome::Unspecified => { - tracing::debug!( - outcome = ?append_start.outcome, - "replica append task deferred: key={} put_id=({},{})", - job.key, - job.put_id.0, - job.put_id.1 - ); - return; - } - } - ReplicaTaskTarget { - node_id: append_start.node_id, - target_offset: append_start.target_addr - append_start.target_base_addr, - target_base_addr: append_start.target_base_addr, - len: append_start.len, - } - }; - if len != target.len { - tracing::warn!( - "replica task length mismatch: key={} put_id=({},{}) src_len={} target_len={}", - job.key, - job.put_id.0, - job.put_id.1, - len, - target.len - ); - spawn_replica_task_revoke(view_task.clone(), job.key, job.put_id, "length mismatch"); - return; - } - if let Err(err) = inner - .put_transfer( - &job.key, - job.put_id, - src_offset, - target.target_offset, - len, - Some(target.node_id.clone()), - Some(target.target_base_addr), - ) - .await - { - tracing::warn!( - "replica task transfer failed: key={} put_id=({},{}) err={}", - job.key, - job.put_id.0, - job.put_id.1, - err - ); - spawn_replica_task_revoke(view_task.clone(), job.key, job.put_id, "transfer error"); - return; - } - // Append-done may reclaim the source synchronously. Release the transfer-only holder first so - // this task does not make its own reclaim look busy. - drop(job.holder.take()); - match inner.put_append_done(&job.key, job.put_id).await { - Ok(resp) => { - tracing::debug!( - "replica task append done: key={} put_id=({},{}) appended={}", - job.key, - job.put_id.0, - job.put_id.1, - resp.appended - ); - } - Err(err) => { +async fn fail_owner_remote_put( + view: &ClientKvApiView, + op: Arc, + operation_id: Option, + reason: &'static str, +) { + let inner = view.client_kv_api().inner(); + if let Some(operation_id) = operation_id { + if let Err(revoke_err) = inner + .put_append_revoke(&op.key, op.put_id, operation_id) + .await + { tracing::warn!( - "replica task append done failed: key={} put_id=({},{}) err={}", - job.key, - job.put_id.0, - job.put_id.1, - err + "owner remote Put revoke failed after {}: key={} put_id=({},{}) operation_id={} err={}", + reason, + op.key, + op.put_id.0, + op.put_id.1, + operation_id, + revoke_err ); } } + inner.finish_owner_remote_put(&op, OwnerRemotePutOutcome::Failed); } -struct ReplicaAppendDoneJob { - key: String, - put_id: PutIDForAKey, -} - -async fn finish_replica_append_jobs_individually( - inner: &ClientKvApiInner, - jobs: Vec, +async fn run_owner_remote_put( + view: ClientKvApiView, + op: Arc, + holder: Arc, ) { - let results = join_all(jobs.into_iter().map(|job| async move { - let result = inner.put_append_done(&job.key, job.put_id).await; - (job, result) - })) - .await; - for (job, result) in results { - match result { - Ok(_resp) => {} - Err(err) => { - tracing::warn!( - "replica task append done fallback failed: key={} put_id=({},{}) err={}", - job.key, - job.put_id.0, - job.put_id.1, - err - ); - } - } - } -} - -async fn process_replica_append_batch(view_task: ClientKvApiView, jobs: Vec) { - if jobs.is_empty() { - return; - } - let inner = view_task.client_kv_api().inner(); - let mut valid_jobs = Vec::with_capacity(jobs.len()); - let mut start_items = Vec::with_capacity(jobs.len()); - for job in jobs { - let len = job - .holder - .as_ref() - .expect("batch replica source must be pinned") - .get_length() as u64; - if u32::try_from(len).is_err() { + let inner = view.client_kv_api().inner(); + let src_offset = holder.memory_info().offset; + let len = holder.get_length() as u64; + let len_u32 = match u32::try_from(len) { + Ok(len_u32) => len_u32, + Err(_) => { tracing::warn!( - "replica append task length does not fit u32: key={} put_id=({},{}) len={}", - job.key, - job.put_id.0, - job.put_id.1, + "owner remote Put length does not fit u32: key={} put_id=({},{}) len={}", + op.key, + op.put_id.0, + op.put_id.1, len ); - continue; - } - start_items.push(BatchPutAppendStartItemReq { - key: job.key.clone(), - put_id: job.put_id, - len, - preferred_sub_cluster: job.preferred_sub_cluster.clone(), - protect_source_on_remote_complete: job.protect_source_on_remote_complete, - }); - valid_jobs.push(job); - } - if valid_jobs.is_empty() { - return; - } - - let requested = valid_jobs.len(); - let start_time = Instant::now(); - let start_resp = match inner.batch_put_append_start(start_items).await { - Ok(resp) if resp.items.len() == requested => resp, - Ok(resp) => { - tracing::warn!( - "batch replica append start response length mismatch: expected={} got={}", - requested, - resp.items.len() - ); - for job in valid_jobs { - spawn_replica_task_revoke( - view_task.clone(), - job.key, - job.put_id, - "batch start response mismatch", - ); - } + drop(holder); + fail_owner_remote_put(&view, op, None, "length does not fit u32").await; return; } + }; + + let append_start = match start_replica_append_with_retry(inner, &op, len_u32).await { + Ok(resp) => resp, Err(err) => { tracing::warn!( - "batch replica append start RPC failed; falling back per item: items={} err={}", - requested, + "owner remote Put start failed: key={} put_id=({},{}) err={}", + op.key, + op.put_id.0, + op.put_id.1, err ); - join_all( - valid_jobs - .into_iter() - .map(|job| process_replica_task(view_task.clone(), job)), - ) - .await; + drop(holder); + fail_owner_remote_put(&view, op, None, "start error").await; return; } }; - - let mut scheduled = Vec::new(); - let mut already_satisfied = 0usize; - let mut start_failed = 0usize; - for (job, item) in valid_jobs.into_iter().zip(start_resp.items.into_iter()) { - if item.key != job.key || item.put_id != job.put_id { - tracing::warn!( - "batch replica append start identity mismatch: request_key={} request_put_id=({},{}) response_key={} response_put_id=({},{})", - job.key, - job.put_id.0, - job.put_id.1, - item.key, - item.put_id.0, - item.put_id.1 - ); - spawn_replica_task_revoke( - view_task.clone(), - job.key, - job.put_id, - "batch start identity mismatch", - ); - start_failed += 1; - continue; - } - if let Err(err) = - crate::rpcresp_kvresult_convert::try_from_code(item.error_code, item.error_json.clone()) - { - tracing::warn!( - "batch replica append start item failed: key={} put_id=({},{}) err={}", - job.key, - job.put_id.0, - job.put_id.1, - err - ); - start_failed += 1; - continue; + match append_start.outcome { + PutAppendStartOutcome::Scheduled => {} + PutAppendStartOutcome::AlreadySatisfied => { + drop(holder); + inner.finish_owner_remote_put(&op, OwnerRemotePutOutcome::AlreadySatisfied); + return; } - match item.outcome { - PutAppendStartOutcome::Scheduled => {} - PutAppendStartOutcome::AlreadySatisfied => { - already_satisfied += 1; - continue; - } - PutAppendStartOutcome::Obsolete => continue, - PutAppendStartOutcome::RetryableNoSpace | PutAppendStartOutcome::Unspecified => { - start_failed += 1; - continue; - } + PutAppendStartOutcome::Obsolete => { + drop(holder); + inner.finish_owner_remote_put(&op, OwnerRemotePutOutcome::Obsolete); + return; } - let target = ReplicaTaskTarget { - node_id: item.node_id, - target_offset: item.target_addr - item.target_base_addr, - target_base_addr: item.target_base_addr, - len: item.len, - }; - let source_len = job - .holder - .as_ref() - .expect("scheduled batch replica source must remain pinned") - .get_length() as u64; - if source_len != target.len { - tracing::warn!( - "batch replica task length mismatch: key={} put_id=({},{}) src_len={} target_len={}", - job.key, - job.put_id.0, - job.put_id.1, - source_len, - target.len - ); - spawn_replica_task_revoke( - view_task.clone(), - job.key, - job.put_id, - "batch length mismatch", + PutAppendStartOutcome::RetryableNoSpace | PutAppendStartOutcome::Unspecified => { + tracing::debug!( + outcome = ?append_start.outcome, + "owner remote Put deferred: key={} put_id=({},{})", + op.key, + op.put_id.0, + op.put_id.1 ); - start_failed += 1; - continue; + drop(holder); + inner.finish_owner_remote_put(&op, OwnerRemotePutOutcome::Failed); + return; } - scheduled.push((job, target)); } - tracing::info!( - requested, - scheduled = scheduled.len(), - already_satisfied, - failed = start_failed, - rpc_us = duration_to_i64_us(start_time.elapsed()), - "replica writeback batch start complete" - ); - let transfer_results = join_all(scheduled.into_iter().map(|(job, target)| { - let transfer_view = view_task.clone(); - async move { - let inner = transfer_view.client_kv_api().inner(); - let src_offset = job - .holder - .as_ref() - .expect("scheduled batch replica source must remain pinned") - .memory_info() - .offset; - let result = inner - .put_transfer( - &job.key, - job.put_id, - src_offset, - target.target_offset, - target.len, - Some(target.node_id), - Some(target.target_base_addr), - ) - .await; - (job, result) - } - })) - .await; - - let mut done_jobs = Vec::new(); - for (job, result) in transfer_results { - match result { - Ok(_) => { - let ReplicaTaskJob { - key, - put_id, - holder, - .. - } = job; - drop(holder); - done_jobs.push(ReplicaAppendDoneJob { key, put_id }); - } - Err(err) => { - tracing::warn!( - "batch replica task transfer failed: key={} put_id=({},{}) err={}", - job.key, - job.put_id.0, - job.put_id.1, - err - ); - spawn_replica_task_revoke( - view_task.clone(), - job.key, - job.put_id, - "batch transfer error", - ); - } - } + let target = RemotePutTarget { + operation_id: append_start.operation_id, + node_id: append_start.node_id, + target_offset: append_start.target_addr - append_start.target_base_addr, + target_base_addr: append_start.target_base_addr, + len: append_start.len, + }; + if len != target.len { + tracing::warn!( + "owner remote Put length mismatch: key={} put_id=({},{}) src_len={} target_len={}", + op.key, + op.put_id.0, + op.put_id.1, + len, + target.len + ); + drop(holder); + fail_owner_remote_put(&view, op, Some(target.operation_id), "length mismatch").await; + return; } - if done_jobs.is_empty() { + + inner.record_owner_remote_put_transfer(); + if let Err(err) = inner + .put_transfer( + &op.key, + op.put_id, + src_offset, + target.target_offset, + len, + Some(target.node_id), + Some(target.target_base_addr), + ) + .await + { + tracing::warn!( + "owner remote Put transfer failed: key={} put_id=({},{}) err={}", + op.key, + op.put_id.0, + op.put_id.1, + err + ); + drop(holder); + fail_owner_remote_put(&view, op, Some(target.operation_id), "transfer error").await; return; } - let done_requested = done_jobs.len(); - let done_items = done_jobs - .iter() - .map(|job| BatchPutAppendDoneItemReq { - key: job.key.clone(), - put_id: job.put_id, - }) - .collect(); - let done_time = Instant::now(); - let done_resp = match inner.batch_put_append_done(done_items).await { - Ok(resp) if resp.items.len() == done_requested => resp, + // The payload is no longer read after transfer. Keep the generation + // flight installed through Done so eviction cannot cross the completion + // protocol even though the physical source holder is now releasable. + drop(holder); + match inner + .put_append_done(&op.key, op.put_id, target.operation_id) + .await + { Ok(resp) => { - tracing::warn!( - "batch replica append done response length mismatch: expected={} got={}; falling back per item", - done_requested, - resp.items.len() + let outcome = if resp.appended { + OwnerRemotePutOutcome::Published + } else { + OwnerRemotePutOutcome::AlreadySatisfied + }; + tracing::debug!( + "owner remote Put done: key={} put_id=({},{}) appended={}", + op.key, + op.put_id.0, + op.put_id.1, + resp.appended ); - finish_replica_append_jobs_individually(inner, done_jobs).await; - return; + inner.finish_owner_remote_put(&op, outcome); } Err(err) => { tracing::warn!( - "batch replica append done RPC failed; falling back per item: items={} err={}", - done_requested, + "owner remote Put done failed: key={} put_id=({},{}) err={}", + op.key, + op.put_id.0, + op.put_id.1, err ); - finish_replica_append_jobs_individually(inner, done_jobs).await; - return; - } - }; - - let mut appended = 0usize; - let mut already_done = 0usize; - let mut done_failed = 0usize; - for (job, item) in done_jobs.into_iter().zip(done_resp.items.into_iter()) { - let identity_matches = item.key == job.key && item.put_id == job.put_id; - let item_result = crate::rpcresp_kvresult_convert::try_from_code( - item.error_code, - item.error_json.clone(), - ); - if !identity_matches || item_result.is_err() { - tracing::warn!( - "batch replica append done item failed: key={} put_id=({},{}) identity_matches={} err={:?}", - job.key, - job.put_id.0, - job.put_id.1, - identity_matches, - item_result.err() - ); - spawn_replica_task_revoke( - view_task.clone(), - job.key, - job.put_id, - "batch done item error", - ); - done_failed += 1; - continue; - } - if item.appended { - appended += 1; - } else { - already_done += 1; + fail_owner_remote_put(&view, op, Some(target.operation_id), "done error").await; } } - tracing::info!( - requested = done_requested, - appended, - already_satisfied = already_done, - failed = done_failed, - rpc_us = duration_to_i64_us(done_time.elapsed()), - "replica writeback batch done complete" - ); -} - -async fn process_replica_task_batch(view_task: ClientKvApiView, jobs: Vec) { - let mut append_jobs = Vec::new(); - let mut reserved_target_jobs = Vec::new(); - for job in jobs { - if job.target.is_some() { - reserved_target_jobs.push(job); - } else { - append_jobs.push(job); - } - } - let append = process_replica_append_batch(view_task.clone(), append_jobs); - let reserved = join_all( - reserved_target_jobs - .into_iter() - .map(|job| process_replica_task(view_task.clone(), job)), - ); - let (_, _) = futures::join!(append, reserved); -} - -pub fn spawn_replica_task_actor( - view: ClientKvApiView, - mut rx: tokio::sync::ampsc::Receiver, - max_inflight: usize, -) { - let view_task = view.clone(); - let _ = view.spawn("replica_task_actor", async move { - let max_inflight = max_inflight.max(1); - tracing::info!( - max_inflight, - merge_window_ms = REPLICA_TASK_BATCH_MERGE_WINDOW.as_millis(), - "replica task actor started with time-window batching" - ); - let mut shutdown_waiter = view_task.register_shutdown_waiter(); - loop { - let first = tokio::select! { - _ = shutdown_waiter.wait() => { - tracing::info!("replica_task_actor stopping due to shutdown signal"); - break; - } - job = rx.recv() => { - match job { - Some(job) => job, - None => break, - } - } - }; - let mut batch = Vec::with_capacity(max_inflight); - batch.push(first); - let merge_window = tokio::time::sleep(REPLICA_TASK_BATCH_MERGE_WINDOW); - tokio::pin!(merge_window); - while batch.len() < max_inflight { - tokio::select! { - _ = &mut merge_window => break, - job = rx.recv() => { - match job { - Some(job) => batch.push(job), - None => break, - } - } - } - } - tracing::info!(items = batch.len(), "replica writeback batch flushed"); - process_replica_task_batch(view_task.clone(), batch).await; - } - }); } pub async fn handle_batch_enqueue_replica_tasks( @@ -3943,7 +3587,7 @@ pub async fn handle_batch_enqueue_replica_tasks( let mut items = Vec::with_capacity(req.serialize_part.items.len()); for item in req.serialize_part.items { let accepted = match inner - .make_replica_append_task(&item.key, item.put_id, None, false) + .ensure_remote_put(&item.key, item.put_id, None, false) .await { Ok(accepted) => accepted, @@ -4256,7 +3900,7 @@ pub(crate) async fn publish_owner_local_job(view: ClientKvApiView, job: OwnerLoc for item in promoted_items { if item.make_replica_task { if let Err(err) = inner - .make_replica_append_task( + .ensure_remote_put( &item.key, item.put_id, item.preferred_sub_cluster.clone(), @@ -4297,24 +3941,3 @@ async fn release_owner_local_publish_reservations( ); } } - -fn spawn_replica_task_revoke( - view: ClientKvApiView, - key: String, - put_id: PutIDForAKey, - reason: &'static str, -) { - let _ = view.clone().spawn("replica_task_revoke", async move { - let inner = view.client_kv_api().inner(); - if let Err(revoke_err) = inner.put_append_revoke(&key, put_id).await { - tracing::warn!( - "replica task append revoke failed after {}: key={} put_id=({},{}) err={}", - reason, - key, - put_id.0, - put_id.1, - revoke_err - ); - } - }); -} diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs index 97b36a0..1eb0a5a 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs @@ -56,6 +56,8 @@ fn reclaim_key_control_busy_detail(state: &super::OwnerKeyControlState) -> Optio Some("owner local put is inflight") } else if state.external_pending_puts != 0 { Some("owner external put context is still pending") + } else if state.remote_put.is_some() { + Some("owner remote put transfer is inflight") } else if state.source_eviction_selection.is_some() { Some("owner source eviction selection fence is active") } else if state.external_get.is_some() { @@ -91,7 +93,7 @@ fn prepare_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclai "another owner source selection owns the key fence", ); } - if state.local_puts != 0 || state.external_pending_puts != 0 { + if state.local_puts != 0 || state.external_pending_puts != 0 || state.remote_put.is_some() { return item_resp( item, OwnerReclaimItemState::Busy, @@ -126,6 +128,10 @@ fn prepare_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclai }) .map(|(_, snapshot)| snapshot); assert!(state.reclaim.is_none()); + assert!( + state.local_access_fence.is_some(), + "source-selection promotion must retain its local-access completion generation" + ); state.reclaim = Some(OwnerReclaimRecord::Prepared(OwnerPreparedReclaim { item: item.clone(), cached_info: selection.cached_info, @@ -214,6 +220,7 @@ fn prepare_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclai && state.external_pending_puts == 0 && state.external_get.is_none() ); + state.begin_local_access_fence(); state.reclaim = Some(OwnerReclaimRecord::Prepared(OwnerPreparedReclaim { item: item.clone(), cached_info, @@ -279,7 +286,9 @@ fn reclaim_release_fence_is_intact( Some(OwnerReclaimRecord::Releasing(releasing)) if releasing == item ) && state.local_puts == 0 && state.external_pending_puts == 0 + && state.remote_put.is_none() && state.source_eviction_selection.is_none() + && state.local_access_fence.is_some() } fn commit_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclaimItemResp { @@ -389,26 +398,23 @@ mod tests { }, reason: OwnerReclaimReason::OwnerCapacityEviction, }; - let state = OwnerKeyControlState { - local_puts: 0, - external_pending_puts: 0, - external_put: None, - source_eviction_selection: None, - reclaim: Some(OwnerReclaimRecord::Releasing(item.clone())), + let mut state = OwnerKeyControlState { external_get: Some(Arc::new(ExternalGetKeySharedOp::new( "remote-during-reclaim".to_string(), ))), + ..Default::default() }; + state.reclaim = Some(OwnerReclaimRecord::Releasing(item.clone())); + state.begin_local_access_fence(); assert!(reclaim_release_fence_is_intact(&state, &item)); - let local_put_state = OwnerKeyControlState { + let mut local_put_state = OwnerKeyControlState { local_puts: 1, - external_pending_puts: 0, - external_put: None, - source_eviction_selection: None, - reclaim: Some(OwnerReclaimRecord::Releasing(item.clone())), external_get: state.external_get, + ..Default::default() }; + local_put_state.reclaim = Some(OwnerReclaimRecord::Releasing(item.clone())); + local_put_state.begin_local_access_fence(); assert!(!reclaim_release_fence_is_intact(&local_put_state, &item)); } } @@ -445,6 +451,7 @@ fn abort_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclaimI "owner reclaim abort must restore an empty local snapshot slot" ); } + state.finish_local_access_fence(); if state.is_idle() { controls.remove(&item.key); } @@ -492,6 +499,7 @@ fn finalize_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerRecla }; match state.reclaim.take() { Some(OwnerReclaimRecord::Committed(committed)) if committed == *item => { + state.finish_local_access_fence(); if state.is_idle() { controls.remove(&item.key); } diff --git a/fluxon_rs/fluxon_kv/src/config.rs b/fluxon_rs/fluxon_kv/src/config.rs index 8e88dc5..0e12327 100644 --- a/fluxon_rs/fluxon_kv/src/config.rs +++ b/fluxon_rs/fluxon_kv/src/config.rs @@ -158,8 +158,10 @@ pub struct TestSpecConfig { pub tcp_thread_control_lane_count: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub user_rpc_sync_handler_thread_count: Option, - /// Maximum number of replica append pipelines in flight on an owner. Different keys may run - /// concurrently; each key remains strictly serialized by the replica dispatcher. + /// Deprecated compatibility field. Remote Put now uses direct per-generation singleflight: + /// the elected leader starts immediately and followers await its terminal result, without a + /// replica dispatcher or a global inflight queue. The value is still parsed and validated so + /// existing configurations remain loadable, but it no longer throttles remote Put execution. #[serde(default, skip_serializing_if = "Option::is_none")] pub replica_task_max_inflight: Option, #[serde(default, skip_serializing_if = "Option::is_none")] diff --git a/fluxon_rs/fluxon_kv/src/external_client_api/delete_ack_batch.rs b/fluxon_rs/fluxon_kv/src/external_client_api/delete_ack_batch.rs new file mode 100644 index 0000000..6ed9528 --- /dev/null +++ b/fluxon_rs/fluxon_kv/src/external_client_api/delete_ack_batch.rs @@ -0,0 +1,366 @@ +use super::ExternalClientApiView; +use ::tokio::sync::mpsc; +use limit_thirdparty::tokio; +use parking_lot::Mutex; +use std::collections::{BTreeMap, BTreeSet}; +use std::sync::atomic::{AtomicU64, Ordering}; +use std::time::Duration; + +pub(crate) const EXTERNAL_DELETE_ACK_BATCH_MAX_ITEMS: usize = 1024; +const EXTERNAL_DELETE_ACK_BATCH_MERGE_WINDOW: Duration = Duration::from_millis(1); +const EXTERNAL_DELETE_ACK_BATCH_RPC_TIMEOUT: Duration = Duration::from_secs(5); +const EXTERNAL_DELETE_ACK_BATCH_LOG_EVERY: u64 = 512; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub(crate) struct ExternalDeleteAckItem { + pub external_client_id: String, + pub holder_id: u64, + pub owner_start_time: i64, +} + +#[derive(Debug, Eq, PartialEq)] +struct ExternalDeleteAckBatch { + external_client_id: String, + owner_start_time: i64, + holder_ids: Vec, +} + +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] +pub(crate) struct ExternalDeleteAckBatchSnapshot { + pub enqueued_items: u64, + pub enqueue_failures: u64, + pub rpc_batches: u64, + pub rpc_items: u64, + pub released_items: u64, + pub missing_items: u64, + pub generation_mismatch_items: u64, + pub rpc_failures: u64, + pub max_batch_items: u64, +} + +#[derive(Default)] +struct ExternalDeleteAckBatchCounters { + enqueued_items: AtomicU64, + enqueue_failures: AtomicU64, + rpc_batches: AtomicU64, + rpc_items: AtomicU64, + released_items: AtomicU64, + missing_items: AtomicU64, + generation_mismatch_items: AtomicU64, + rpc_failures: AtomicU64, + max_batch_items: AtomicU64, +} + +impl ExternalDeleteAckBatchCounters { + fn snapshot(&self) -> ExternalDeleteAckBatchSnapshot { + ExternalDeleteAckBatchSnapshot { + enqueued_items: self.enqueued_items.load(Ordering::Relaxed), + enqueue_failures: self.enqueue_failures.load(Ordering::Relaxed), + rpc_batches: self.rpc_batches.load(Ordering::Relaxed), + rpc_items: self.rpc_items.load(Ordering::Relaxed), + released_items: self.released_items.load(Ordering::Relaxed), + missing_items: self.missing_items.load(Ordering::Relaxed), + generation_mismatch_items: self.generation_mismatch_items.load(Ordering::Relaxed), + rpc_failures: self.rpc_failures.load(Ordering::Relaxed), + max_batch_items: self.max_batch_items.load(Ordering::Relaxed), + } + } +} + +pub(crate) struct ExternalDeleteAckBatchHandle { + tx: mpsc::UnboundedSender, + rx: Mutex>>, + counters: ExternalDeleteAckBatchCounters, +} + +impl ExternalDeleteAckBatchHandle { + pub(crate) fn new() -> Self { + let (tx, rx) = mpsc::unbounded_channel(); + Self { + tx, + rx: Mutex::new(Some(rx)), + counters: ExternalDeleteAckBatchCounters::default(), + } + } + + pub(crate) fn enqueue(&self, item: ExternalDeleteAckItem) -> Result<(), String> { + match self.tx.send(item) { + Ok(()) => { + self.counters.enqueued_items.fetch_add(1, Ordering::Relaxed); + Ok(()) + } + Err(err) => { + self.counters + .enqueue_failures + .fetch_add(1, Ordering::Relaxed); + Err(format!( + "external holder ACK batch worker is unavailable for holder_id={}", + err.0.holder_id + )) + } + } + } + + pub(crate) fn take_rx(&self) -> Option> { + self.rx.lock().take() + } + + pub(crate) fn snapshot(&self) -> ExternalDeleteAckBatchSnapshot { + self.counters.snapshot() + } + + fn record_batch(&self, item_count: usize) -> u64 { + let item_count = u64::try_from(item_count).unwrap_or(u64::MAX); + self.counters + .max_batch_items + .fetch_max(item_count, Ordering::Relaxed); + self.counters + .rpc_items + .fetch_add(item_count, Ordering::Relaxed); + self.counters.rpc_batches.fetch_add(1, Ordering::Relaxed) + 1 + } + + fn record_result(&self, result: super::ExternalDeleteAckBatchSendResult) { + match result { + super::ExternalDeleteAckBatchSendResult::Applied { released, missing } => { + self.counters + .released_items + .fetch_add(u64::from(released), Ordering::Relaxed); + self.counters + .missing_items + .fetch_add(u64::from(missing), Ordering::Relaxed); + } + super::ExternalDeleteAckBatchSendResult::OwnerGenerationChanged { items } => { + self.counters + .generation_mismatch_items + .fetch_add(items, Ordering::Relaxed); + } + } + } + + fn record_rpc_failure(&self) { + self.counters.rpc_failures.fetch_add(1, Ordering::Relaxed); + } +} + +fn build_external_delete_ack_batches( + items: Vec, +) -> Vec { + let mut groups: BTreeMap<(String, i64), BTreeSet> = BTreeMap::new(); + for item in items { + groups + .entry((item.external_client_id, item.owner_start_time)) + .or_default() + .insert(item.holder_id); + } + let mut batches = Vec::new(); + for ((external_client_id, owner_start_time), holder_ids) in groups { + let holder_ids: Vec<_> = holder_ids.into_iter().collect(); + for chunk in holder_ids.chunks(EXTERNAL_DELETE_ACK_BATCH_MAX_ITEMS) { + batches.push(ExternalDeleteAckBatch { + external_client_id: external_client_id.clone(), + owner_start_time, + holder_ids: chunk.to_vec(), + }); + } + } + batches +} + +fn log_external_delete_ack_batch_snapshot(view: &ExternalClientApiView, reason: &'static str) { + let snapshot = view + .external_client_api() + .inner() + .external_delete_ack_batch_snapshot(); + tracing::info!( + reason, + enqueued_items = snapshot.enqueued_items, + enqueue_failures = snapshot.enqueue_failures, + rpc_batches = snapshot.rpc_batches, + rpc_items = snapshot.rpc_items, + released_items = snapshot.released_items, + missing_items = snapshot.missing_items, + generation_mismatch_items = snapshot.generation_mismatch_items, + rpc_failures = snapshot.rpc_failures, + max_batch_items = snapshot.max_batch_items, + "external holder ACK batch snapshot" + ); +} + +pub(crate) fn spawn_external_delete_ack_batch( + view: ExternalClientApiView, + mut rx: mpsc::UnboundedReceiver, +) { + let spawn_view = view.clone(); + let worker_view = view.clone(); + spawn_view.spawn("external_delete_ack_batch", async move { + tracing::info!( + max_items = EXTERNAL_DELETE_ACK_BATCH_MAX_ITEMS, + merge_window_us = EXTERNAL_DELETE_ACK_BATCH_MERGE_WINDOW.as_micros(), + "external holder ACK batch worker started" + ); + let mut shutdown_waiter = worker_view.register_shutdown_waiter(); + loop { + let first = tokio::select! { + biased; + _ = shutdown_waiter.wait() => { + log_external_delete_ack_batch_snapshot(&worker_view, "shutdown"); + return; + } + item = rx.recv() => { + let Some(item) = item else { + log_external_delete_ack_batch_snapshot(&worker_view, "channel_closed"); + return; + }; + item + } + }; + + let mut pending = Vec::with_capacity(EXTERNAL_DELETE_ACK_BATCH_MAX_ITEMS); + pending.push(first); + let merge_window = tokio::time::sleep(EXTERNAL_DELETE_ACK_BATCH_MERGE_WINDOW); + tokio::pin!(merge_window); + let mut shutting_down = false; + while pending.len() < EXTERNAL_DELETE_ACK_BATCH_MAX_ITEMS { + tokio::select! { + biased; + _ = shutdown_waiter.wait() => { + shutting_down = true; + break; + } + item = rx.recv() => { + match item { + Some(item) => pending.push(item), + None => break, + } + } + _ = &mut merge_window => break, + } + } + if shutting_down { + tracing::info!( + dropped_pending_items = pending.len(), + "external holder ACK batch worker skipped pending items during shutdown" + ); + log_external_delete_ack_batch_snapshot(&worker_view, "shutdown_with_pending"); + return; + } + + for batch in build_external_delete_ack_batches(pending) { + let item_count = batch.holder_ids.len(); + let batch_number = worker_view + .external_client_api() + .inner() + .external_delete_ack_batch + .record_batch(item_count); + let send_result = tokio::time::timeout( + EXTERNAL_DELETE_ACK_BATCH_RPC_TIMEOUT, + worker_view + .external_client_api() + .inner() + .send_external_delete_ack_batch( + &batch.external_client_id, + batch.owner_start_time, + batch.holder_ids, + ), + ) + .await; + match send_result { + Ok(Ok(result)) => worker_view + .external_client_api() + .inner() + .external_delete_ack_batch + .record_result(result), + Ok(Err(err)) => { + worker_view + .external_client_api() + .inner() + .external_delete_ack_batch + .record_rpc_failure(); + tracing::warn!( + external_client_id = %batch.external_client_id, + owner_start_time = batch.owner_start_time, + items = item_count, + error = %err, + "external holder ACK batch RPC failed" + ); + } + Err(_) => { + worker_view + .external_client_api() + .inner() + .external_delete_ack_batch + .record_rpc_failure(); + tracing::warn!( + external_client_id = %batch.external_client_id, + owner_start_time = batch.owner_start_time, + items = item_count, + timeout_secs = EXTERNAL_DELETE_ACK_BATCH_RPC_TIMEOUT.as_secs(), + "external holder ACK batch RPC timed out" + ); + } + } + if batch_number % EXTERNAL_DELETE_ACK_BATCH_LOG_EVERY == 0 { + log_external_delete_ack_batch_snapshot(&worker_view, "periodic"); + } + } + } + }); +} + +#[cfg(test)] +mod tests { + use super::{ + EXTERNAL_DELETE_ACK_BATCH_MAX_ITEMS, ExternalDeleteAckItem, + build_external_delete_ack_batches, + }; + + fn item(client: &str, generation: i64, holder_id: u64) -> ExternalDeleteAckItem { + ExternalDeleteAckItem { + external_client_id: client.to_string(), + holder_id, + owner_start_time: generation, + } + } + + #[test] + fn grouping_is_generation_safe_and_deduplicates_holder_ids() { + let batches = build_external_delete_ack_batches(vec![ + item("client-a", 11, 3), + item("client-a", 11, 3), + item("client-a", 11, 2), + item("client-a", 12, 4), + item("client-b", 11, 5), + ]); + assert_eq!(batches.len(), 3); + assert_eq!(batches[0].external_client_id, "client-a"); + assert_eq!(batches[0].owner_start_time, 11); + assert_eq!(batches[0].holder_ids, vec![2, 3]); + assert_eq!(batches[1].owner_start_time, 12); + assert_eq!(batches[1].holder_ids, vec![4]); + assert_eq!(batches[2].external_client_id, "client-b"); + assert_eq!(batches[2].holder_ids, vec![5]); + } + + #[test] + fn batches_never_exceed_wire_batch_limit() { + let item_count = EXTERNAL_DELETE_ACK_BATCH_MAX_ITEMS * 2 + 1; + let items = (0..item_count) + .map(|holder_id| item("client-a", 11, holder_id as u64)) + .collect(); + let batches = build_external_delete_ack_batches(items); + assert_eq!(batches.len(), 3); + assert!( + batches + .iter() + .all(|batch| batch.holder_ids.len() <= EXTERNAL_DELETE_ACK_BATCH_MAX_ITEMS) + ); + assert_eq!( + batches + .iter() + .map(|batch| batch.holder_ids.len()) + .sum::(), + item_count + ); + } +} diff --git a/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs b/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs index fed6a1a..2008f1b 100644 --- a/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs +++ b/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs @@ -1,9 +1,10 @@ use crate::SharedJsonMeta; use crate::client_kv_api::external_api::{ compute_external_get_start_transfer_prefix, normalize_external_get_start_group_lens, + validate_external_get_consume_prefix, }; use crate::client_kv_api::msg_pack::{ - ExternalInvalidateWeakIndexItem, ExternalInvalidateWeakIndexReq, + ExternalBatchDeleteAckReq, ExternalInvalidateWeakIndexItem, ExternalInvalidateWeakIndexReq, ExternalInvalidateWeakIndexResp, }; use crate::client_seg_pool::{ClientSegPool, SideTransferPeerFileMeta}; @@ -64,6 +65,12 @@ pub mod external_client_test; type SharedMetaSignature = fluxon_util::fs_watch::FileSignature; +mod delete_ack_batch; +pub(crate) use delete_ack_batch::{ + ExternalDeleteAckBatchHandle, ExternalDeleteAckBatchSnapshot, ExternalDeleteAckItem, + spawn_external_delete_ack_batch, +}; + // External->Owner staged put consists of multiple potentially slow components: // - ExternalPutStartReq triggers owner->master PutStart RPC (60s timeout). // - ExternalPutTransferEndReq executes transfer (can be slow) and then owner->master PutEnd RPC (60s timeout). @@ -73,6 +80,12 @@ const EXTERNAL_PUT_TRANSFER_END_RPC_TIMEOUT_SECS: u64 = 30; const EXTERNAL_RPC_P2P_RECOVER_MAX_ATTEMPTS: usize = 3; const EXTERNAL_PUT_TRACE_LOG_WINDOW_SECS: u64 = 10; +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(crate) enum ExternalDeleteAckBatchSendResult { + Applied { released: u32, missing: u32 }, + OwnerGenerationChanged { items: u64 }, +} + #[derive(Debug, Clone)] pub struct ExternalClientGetStartResp { pub handle: u64, @@ -82,6 +95,7 @@ pub struct ExternalClientGetStartResp { struct PendingExternalGetStart { keys: Vec, transferable_len: usize, + atomic_group_lens: Vec, first_miss_index: Option, } @@ -133,10 +147,43 @@ fn validate_inline_external_get_owner_generation( })) } +fn inline_external_get_tail_holder_ids( + items: &[ExternalBatchGetItemResp], + consume_prefix_len: usize, +) -> KvResult> { + if consume_prefix_len == 0 || consume_prefix_len > items.len() { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "inline get_transfer consume prefix is out of range: consume={} items={}", + consume_prefix_len, + items.len() + ), + })); + } + items[consume_prefix_len..] + .iter() + .enumerate() + .map(|(tail_idx, item)| { + item.external_memholder_info + .as_ref() + .map(|info| info.holder_id) + .ok_or_else(|| { + KvError::Api(ApiError::Unknown { + detail: format!( + "inline get_transfer tail item has no holder: index={}", + consume_prefix_len + tail_idx + ), + }) + }) + }) + .collect() +} + #[cfg(test)] mod inline_external_get_start_tests { use super::{ - validate_inline_external_get_owner_generation, validate_inline_external_get_start_plan, + inline_external_get_tail_holder_ids, validate_inline_external_get_owner_generation, + validate_inline_external_get_start_plan, }; use crate::client_kv_api::msg_pack::ExternalBatchGetItemResp; use crate::memholder::ExternalMemHolderInfo; @@ -178,6 +225,22 @@ mod inline_external_get_start_tests { }) )); } + + #[test] + fn inline_partial_consume_returns_only_tail_holder_ids() { + let items = vec![inline_hit(11), inline_hit(12), inline_hit(13)]; + assert_eq!( + inline_external_get_tail_holder_ids(&items, 2).unwrap(), + vec![13] + ); + assert!( + inline_external_get_tail_holder_ids(&items, 3) + .unwrap() + .is_empty() + ); + assert!(inline_external_get_tail_holder_ids(&items, 0).is_err()); + assert!(inline_external_get_tail_holder_ids(&items, 4).is_err()); + } } fn duration_to_i64_us(duration: std::time::Duration) -> i64 { @@ -446,6 +509,7 @@ pub struct ExternalInner { rpc_caller_external_batch_is_exist: RPCCaller, rpc_caller_external_observability_snapshot: RPCCaller, rpc_caller_external_delete_ack: RPCCaller, + rpc_caller_external_batch_delete_ack: RPCCaller, rpc_caller_external_put_revoke: RPCCaller, /// Lease RPC callers for external mode rpc_caller_allocate_client_lease: RPCCaller, @@ -458,6 +522,7 @@ pub struct ExternalInner { /// per-key semaphore (permits=1) to ensure single inflight per key inflight1_per_key: SemaphoreMap, put_trace_log_window: Mutex, + pub(crate) external_delete_ack_batch: ExternalDeleteAckBatchHandle, } pub struct ExternalClientApi(ExternalInner); @@ -515,6 +580,7 @@ impl ExternalClientApi { rpc_caller_external_observability_snapshot: RPCCaller::::new(), rpc_caller_external_delete_ack: RPCCaller::::new(), + rpc_caller_external_batch_delete_ack: RPCCaller::::new(), rpc_caller_external_put_revoke: RPCCaller::::new(), rpc_caller_allocate_client_lease: RPCCaller::::new(), rpc_caller_client_lease_keepalive: RPCCaller::::new(), @@ -523,6 +589,7 @@ impl ExternalClientApi { pending_inline_external_get_start: DashMap::new(), inflight1_per_key: SemaphoreMap::new(1, std::time::Duration::from_secs(120)), put_trace_log_window: Mutex::new(ExternalPutTraceLogWindow::new()), + external_delete_ack_batch: ExternalDeleteAckBatchHandle::new(), })) } @@ -620,12 +687,20 @@ impl ExternalClientApi { .regist(ext.view.p2p_module()); ext.rpc_caller_external_delete_ack .regist(ext.view.p2p_module()); + ext.rpc_caller_external_batch_delete_ack + .regist(ext.view.p2p_module()); ext.rpc_caller_external_put_revoke .regist(ext.view.p2p_module()); crate::key_prefix::init_for_p2p_owner(ext.view.p2p_module()); crate::kvlease::init_for_p2p_owner(ext.view.p2p_module()); crate::metrics::client::init_for_p2p_owner(ext.view.p2p_module()); + let external_delete_ack_rx = ext + .external_delete_ack_batch + .take_rx() + .expect("external holder ACK batch worker initialized twice"); + spawn_external_delete_ack_batch(ext.view.clone_view(), external_delete_ack_rx); + let view_ext = ext.view.clone_view(); RPCHandler::::new().regist( ext.view.p2p_module(), @@ -2086,22 +2161,35 @@ impl ExternalInner { &self, handle: u64, keys: Vec, + consume_prefix_len: usize, ) -> KvResult>>>> { tracing::debug!( - "External batch_get_transfer request: handle={}, batch_len={}", + "External batch_get_transfer request: handle={}, batch_len={}, consume_prefix_len={}", handle, - keys.len() + keys.len(), + consume_prefix_len ); + if consume_prefix_len == 0 || keys.len() != consume_prefix_len { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "batch_get_transfer keys must equal the non-empty consumed prefix: keys={} consume_prefix_len={}", + keys.len(), + consume_prefix_len + ), + })); + } if let Some((_handle, inline_plan)) = self.pending_inline_external_get_start.remove(&handle) { - if keys != inline_plan.keys { + if consume_prefix_len > inline_plan.keys.len() + || keys.as_slice() != &inline_plan.keys[..consume_prefix_len] + { let expected_keys = inline_plan.keys.clone(); self.pending_inline_external_get_start .insert(handle, inline_plan); return Err(KvError::Api(ApiError::InvalidArgument { detail: format!( - "inline external batch_get_transfer keys mismatch: handle={} expected={:?} got={:?}", - handle, expected_keys, keys + "inline external batch_get_transfer prefix mismatch: handle={} consume_prefix_len={} available_keys={:?} got={:?}", + handle, consume_prefix_len, expected_keys, keys ), })); } @@ -2115,32 +2203,78 @@ impl ExternalInner { } }; let (_, current_owner_start_time, _, base_ptr_ro, mapped_len) = owner_snapshot; - validate_inline_external_get_owner_generation( + if let Err(err) = validate_inline_external_get_owner_generation( inline_plan.owner_start_time, current_owner_start_time, - )?; - validate_inline_external_get_start_plan(keys.len(), &inline_plan.items)?; - for (idx, item) in inline_plan.items.iter().enumerate() { - let info = item - .external_memholder_info - .as_ref() - .expect("inline plan was validated above"); - let end = info.offset.checked_add(u64::from(info.len)).ok_or_else(|| { - KvError::Api(ApiError::Unknown { - detail: format!( - "inline external get_start item range overflow: index={} offset={} len={}", - idx, info.offset, info.len - ), - }) - })?; - if end > mapped_len { - return Err(KvError::Api(ApiError::Unknown { - detail: format!( - "inline external get_start item exceeds owner mapping: index={} end={} mapped_len={}", - idx, end, mapped_len - ), - })); + ) { + return Err(err); + } + if let Err(err) = + validate_inline_external_get_start_plan(inline_plan.keys.len(), &inline_plan.items) + { + self.pending_inline_external_get_start + .insert(handle, inline_plan); + return Err(err); + } + let range_validation = inline_plan.items.iter().enumerate().try_for_each( + |(idx, item)| -> KvResult<()> { + let info = item + .external_memholder_info + .as_ref() + .expect("inline plan was validated above"); + let end = info.offset.checked_add(u64::from(info.len)).ok_or_else(|| { + KvError::Api(ApiError::Unknown { + detail: format!( + "inline external get_start item range overflow: index={} offset={} len={}", + idx, info.offset, info.len + ), + }) + })?; + if end > mapped_len { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "inline external get_start item exceeds owner mapping: index={} end={} mapped_len={}", + idx, end, mapped_len + ), + })); + } + Ok(()) + }, + ); + if let Err(err) = range_validation { + self.pending_inline_external_get_start + .insert(handle, inline_plan); + return Err(err); + } + + let tail_holder_ids = + inline_external_get_tail_holder_ids(&inline_plan.items, consume_prefix_len) + .expect("validated inline plan must yield tail holder ids"); + if !tail_holder_ids.is_empty() { + let external_client_id = self.view.cluster_manager().get_self_info().id.clone(); + let mut enqueue_failures = 0usize; + for holder_id in tail_holder_ids.iter().copied() { + if let Err(err) = self.enqueue_external_delete_ack( + external_client_id.clone(), + holder_id, + inline_plan.owner_start_time, + ) { + enqueue_failures += 1; + tracing::warn!( + "External inline get_transfer could not enqueue tail holder release: handle={} holder_id={} error={}", + handle, + holder_id, + err + ); + } } + tracing::info!( + "External inline get_transfer enqueued tail release: handle={}, consumed={}, released_tail={}, enqueue_failures={}", + handle, + consume_prefix_len, + tail_holder_ids.len(), + enqueue_failures + ); } let bandwidth_handle = self @@ -2150,7 +2284,10 @@ impl ExternalInner { .expect("ExternalClientApi.batch_get_transfer expects IpcBandwidthAttributor handle to be attached"); let external_client_id = self.view.cluster_manager().get_self_info().id.clone(); let mut results = Vec::with_capacity(keys.len()); - for (key, item) in keys.into_iter().zip(inline_plan.items.into_iter()) { + for (key, item) in keys + .into_iter() + .zip(inline_plan.items.into_iter().take(consume_prefix_len)) + { let info = item .external_memholder_info .expect("inline plan was validated above"); @@ -2202,6 +2339,7 @@ impl ExternalInner { handle, req_node_id: self.view.cluster_manager().get_self_info().id.clone(), started_time, + consume_prefix_len, }, raw_bytes: Vec::new(), }; @@ -2268,6 +2406,51 @@ impl ExternalInner { Ok(results) } + async fn send_batch_get_cancel_plan( + &self, + handle: u64, + started_time: i64, + transfer_plan: ExternalBatchGetCancelPlan, + ) -> KvResult<()> { + let owner = self.shared_storage_node_id().await.ok_or_else(|| { + KvError::SharedMem(SharedMemError::NotConfigured { + node_id: None, + detail: Some("Shared storage node id unavailable".to_string()), + }) + })?; + let req = MsgPack { + serialize_part: ExternalBatchGetCancelReq { + handle, + req_node_id: self.view.cluster_manager().get_self_info().id.clone(), + started_time, + transfer_plan, + }, + raw_bytes: Vec::new(), + }; + let resp = match self + .rpc_caller_external_batch_get_cancel + .call(self.view.p2p_module(), owner.into(), req, None, 0) + .await + { + Ok(resp) => resp, + Err(err) => return Err(KvError::from(err)), + }; + if resp.serialize_part.error_code == OK { + return Ok(()); + } + let err = KvError::from_json( + resp.serialize_part.error_code, + &resp.serialize_part.error_json, + ); + if matches!(&err, KvError::Api(ApiError::OwnerStartTimeMismatch { .. })) { + tracing::info!( + "send_batch_get_cancel_plan: owner start_time mismatch; owner restarted, treating handle as gone" + ); + return Ok(()); + } + Err(err) + } + pub async fn cancel_batch_get_start(&self, handle: u64) -> KvResult<()> { tracing::debug!("External cancel_batch_get_start request: handle={}", handle); let inline_plan = self @@ -2302,57 +2485,15 @@ impl ExternalInner { }, None => ExternalBatchGetCancelPlan::OwnerRpc, }; - let owner = match self.shared_storage_node_id().await { - Some(owner) => owner, - None => { - if let Some(plan) = inline_plan { - self.pending_inline_external_get_start.insert(handle, plan); - } - return Err(KvError::SharedMem(SharedMemError::NotConfigured { - node_id: None, - detail: Some("Shared storage node id unavailable".to_string()), - })); - } - }; - let req = MsgPack { - serialize_part: ExternalBatchGetCancelReq { - handle, - req_node_id: self.view.cluster_manager().get_self_info().id.clone(), - started_time, - transfer_plan, - }, - raw_bytes: Vec::new(), - }; - let resp = match self - .rpc_caller_external_batch_get_cancel - .call(self.view.p2p_module(), owner.into(), req, None, 0) - .await - { - Ok(resp) => resp, - Err(err) => { - if let Some(plan) = inline_plan { - self.pending_inline_external_get_start.insert(handle, plan); - } - return Err(KvError::from(err)); + let cancel_result = self + .send_batch_get_cancel_plan(handle, started_time, transfer_plan) + .await; + if cancel_result.is_err() { + if let Some(plan) = inline_plan { + self.pending_inline_external_get_start.insert(handle, plan); } - }; - if resp.serialize_part.error_code == OK { - return Ok(()); - } - let err = KvError::from_json( - resp.serialize_part.error_code, - &resp.serialize_part.error_json, - ); - if matches!(&err, KvError::Api(ApiError::OwnerStartTimeMismatch { .. })) { - tracing::info!( - "cancel_batch_get_start: owner start_time mismatch; owner restarted, treating handle as gone" - ); - return Ok(()); - } - if let Some(plan) = inline_plan { - self.pending_inline_external_get_start.insert(handle, plan); } - Err(err) + cancel_result } pub async fn get_start( @@ -2401,6 +2542,7 @@ impl ExternalInner { PendingExternalGetStart { keys: keys.clone(), transferable_len, + atomic_group_lens: group_lens, first_miss_index, }, ); @@ -2414,6 +2556,7 @@ impl ExternalInner { pub async fn get_transfer( &self, handle: u64, + consume_prefix_len: Option, ) -> KvResult>>>> { let Some((_handle, entry)) = self.pending_external_get_start.remove(&handle) else { return Err(KvError::Api(ApiError::InvalidArgument { @@ -2437,8 +2580,21 @@ impl ExternalInner { ), })); } - self.batch_get_transfer(handle, entry.keys[..entry.transferable_len].to_vec()) - .await + let consume_prefix_len = consume_prefix_len.unwrap_or(entry.transferable_len); + if let Err(err) = validate_external_get_consume_prefix( + consume_prefix_len, + entry.transferable_len, + &entry.atomic_group_lens, + ) { + self.pending_external_get_start.insert(handle, entry); + return Err(err); + } + self.batch_get_transfer( + handle, + entry.keys[..consume_prefix_len].to_vec(), + consume_prefix_len, + ) + .await } pub async fn cancel_get_transfer(&self, handle: u64) -> KvResult<()> { @@ -3882,6 +4038,72 @@ key={}, attempt={}/{}, err={}", Ok(()) } + pub(crate) fn enqueue_external_delete_ack( + &self, + external_client_id: String, + holder_id: u64, + owner_start_time: i64, + ) -> Result<(), String> { + self.external_delete_ack_batch + .enqueue(ExternalDeleteAckItem { + external_client_id, + holder_id, + owner_start_time, + }) + } + + pub(crate) fn external_delete_ack_batch_snapshot(&self) -> ExternalDeleteAckBatchSnapshot { + self.external_delete_ack_batch.snapshot() + } + + pub(crate) async fn send_external_delete_ack_batch( + &self, + external_client_id: &str, + owner_start_time: i64, + holder_ids: Vec, + ) -> KvResult { + let item_count = u64::try_from(holder_ids.len()).unwrap_or(u64::MAX); + let req = MsgPack { + serialize_part: ExternalBatchDeleteAckReq { + external_client_id: external_client_id.to_string(), + holder_ids, + started_time: owner_start_time, + }, + raw_bytes: Vec::new(), + }; + let owner = self.shared_storage_node_id().await.ok_or_else(|| { + KvError::SharedMem(SharedMemError::NotConfigured { + node_id: None, + detail: Some("Shared storage node id unavailable".to_string()), + }) + })?; + let resp = self + .rpc_caller_external_batch_delete_ack + .call(self.view.p2p_module(), owner.into(), req, None, 0) + .await + .map_err(KvError::from)?; + match resp.serialize_part.to_result() { + Ok(resp) => { + let accounted = u64::from(resp.released_count) + u64::from(resp.missing_count); + if accounted != item_count { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external holder ACK batch accounted for {accounted} of {item_count} items" + ), + })); + } + Ok(ExternalDeleteAckBatchSendResult::Applied { + released: resp.released_count, + missing: resp.missing_count, + }) + } + Err(KvError::Api(ApiError::OwnerStartTimeMismatch { .. })) => { + Ok(ExternalDeleteAckBatchSendResult::OwnerGenerationChanged { items: item_count }) + } + Err(err) => Err(err), + } + } + /// Allocate a client lease (external role): send request to master via P2P. /// /// Semantics: diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs index 3be65fe..3939fb2 100644 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs @@ -153,6 +153,29 @@ pub enum ReservedCapacityReason { LeaseBoundKv, } +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +struct NodeCacheCapacityBoundaries { + ring_b_bytes: u64, + tier1_bytes: Option, +} + +fn node_cache_capacity_boundaries( + node_space_size: u64, + replica_cache_capacity_ratio: f64, + replica_writeback_tier1_capacity_ratio: Option, + reserved_capacity_bytes: u64, +) -> NodeCacheCapacityBoundaries { + let ring_b_base = (node_space_size as f64 * replica_cache_capacity_ratio).floor() as u64; + NodeCacheCapacityBoundaries { + ring_b_bytes: ring_b_base.saturating_sub(reserved_capacity_bytes), + // Tier1 contains only metadata and defines when pre-writeback starts. + // It is inclusive of owner residency, so physical ring-B reservations + // never reduce this logical policy window. + tier1_bytes: replica_writeback_tier1_capacity_ratio + .map(|ratio| (node_space_size as f64 * ratio).floor() as u64), + } +} + #[derive(Debug)] pub struct NodeCacheReservedCapacity { /// Exact node registration generation owning these counters. @@ -375,6 +398,11 @@ pub struct InflightPutInfo { #[derive(Clone)] pub struct InflightReplicaTaskInfo { + /// Distinguishes repeated remote-copy attempts for the same `(key, + /// put_id)` generation. A generation may lose its remote route and need + /// another append while the previous attempt's replayable terminal result + /// is still cached. + pub operation_id: u64, pub node_id: NodeID, /// Exact target registration generation that owns `target_allocation`. pub target_tomb_tag: NodeTombTag, @@ -389,6 +417,11 @@ pub struct InflightReplicaTaskInfo { pub(crate) _activity_lease: Arc, } +#[derive(Clone, Debug)] +pub struct CompletedReplicaTaskInfo { + pub appended: bool, +} + /// Information about a `get` operation that is currently in progress. #[derive(Clone)] pub struct InflightGetInfo { @@ -517,6 +550,18 @@ pub(crate) struct MasterKeyActivitySnapshot { pub reclaim_installed: bool, } +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] +struct MasterKeyActivityObserveSnapshot { + active_keys: u64, + put_keys: u64, + get_keys: u64, + replica_keys: u64, + reclaim_keys: u64, + inflight_puts: u64, + inflight_gets: u64, + inflight_replicas: u64, +} + #[derive(Clone, Copy, Debug)] enum MasterKeyActivityKind { Put, @@ -750,6 +795,26 @@ impl MasterKeyActivityTable { } } + fn observe_snapshot(&self) -> MasterKeyActivityObserveSnapshot { + let states = self.states.lock(); + let mut snapshot = MasterKeyActivityObserveSnapshot { + active_keys: u64::try_from(states.len()).unwrap_or(u64::MAX), + ..Default::default() + }; + for state in states.values() { + snapshot.put_keys += u64::from(state.puts != 0); + snapshot.get_keys += u64::from(state.gets != 0); + snapshot.replica_keys += u64::from(state.replicas != 0); + snapshot.reclaim_keys += u64::from(state.reclaim.is_some()); + snapshot.inflight_puts = snapshot.inflight_puts.saturating_add(u64::from(state.puts)); + snapshot.inflight_gets = snapshot.inflight_gets.saturating_add(u64::from(state.gets)); + snapshot.inflight_replicas = snapshot + .inflight_replicas + .saturating_add(u64::from(state.replicas)); + } + snapshot + } + pub(crate) fn reclaim_matches(&self, item: &OwnerReclaimItem) -> bool { self.states .lock() @@ -1472,6 +1537,61 @@ mod tests { ); } + #[test] + fn master_key_activity_observe_snapshot_counts_keys_and_leases() { + let table = Arc::new(MasterKeyActivityTable::default()); + let put = table + .reserve("shared", MasterKeyActivityKind::Put, false) + .expect("put activity must be admitted"); + let get_a = table + .reserve("shared", MasterKeyActivityKind::Get, false) + .expect("first get activity must be admitted"); + let get_b = table + .reserve("shared", MasterKeyActivityKind::Get, false) + .expect("second get activity must be admitted"); + let replica = table + .reserve("replica", MasterKeyActivityKind::Replica, false) + .expect("replica activity must be admitted"); + let reclaim = OwnerReclaimItem { + key: "reclaim".to_string(), + put_id: (9, 1), + epoch: 17, + backing: OwnerReclaimBacking::CommittedSlot { + grant_id: 19, + slot_index: 23, + slot_size: 8 * 1024 * 1024, + }, + reason: OwnerReclaimReason::OwnerCapacityEviction, + }; + table + .try_install_reclaim(&reclaim) + .expect("idle key must accept reclaim fence"); + + assert_eq!( + table.observe_snapshot(), + MasterKeyActivityObserveSnapshot { + active_keys: 3, + put_keys: 1, + get_keys: 1, + replica_keys: 1, + reclaim_keys: 1, + inflight_puts: 1, + inflight_gets: 2, + inflight_replicas: 1, + } + ); + + drop(put); + drop(get_a); + drop(get_b); + drop(replica); + assert!(table.clear_reclaim(&reclaim)); + assert_eq!( + table.observe_snapshot(), + MasterKeyActivityObserveSnapshot::default() + ); + } + #[test] fn explicit_activity_completion_is_idempotent_with_retired_cache_clones() { let table = Arc::new(MasterKeyActivityTable::default()); @@ -1489,6 +1609,35 @@ mod tests { assert!(table.is_quiescent("retired-clone")); } + #[test] + fn replica_terminal_result_is_scoped_to_one_append_attempt() { + let terminals = moka::sync::Cache::builder() + .time_to_live(Duration::from_secs(120)) + .build(); + let key = "same-kv-generation".to_string(); + let put_id = (17, 3); + let first_operation_id = 41; + let second_operation_id = 42; + + terminals.insert( + (key.clone(), put_id.0, put_id.1, first_operation_id), + CompletedReplicaTaskInfo { appended: true }, + ); + + assert!( + terminals + .get(&(key.clone(), put_id.0, put_id.1, first_operation_id)) + .is_some(), + "a retry of the same append attempt must replay its terminal result" + ); + assert!( + terminals + .get(&(key, put_id.0, put_id.1, second_operation_id)) + .is_none(), + "an old terminal result must not complete a later remote-copy attempt" + ); + } + fn test_route_info_with_tag(node_id: &str, tomb_tag: NodeTombTag) -> KvRouteInfo { KvRouteInfo { node_id: node_id.to_string().into(), @@ -1827,6 +1976,17 @@ mod tests { assert!(!new_tag.is_tomb()); } + #[test] + fn tier1_capacity_is_independent_of_ring_b_reservations() { + let node_space_size = 128 * 1024 * 1024 * 1024; + let boundaries = + node_cache_capacity_boundaries(node_space_size, 0.95, Some(0.75), 124_554_051_584); + + assert_eq!(boundaries.ring_b_bytes, 6_012_954_214); + assert_eq!(boundaries.tier1_bytes, Some(96 * 1024 * 1024 * 1024)); + assert!(boundaries.tier1_bytes.unwrap() > boundaries.ring_b_bytes); + } + #[test] fn delayed_member_left_is_not_forwarded_to_a_live_generation_actor() { assert!(member_left_can_forward_to_registration_actor(None)); @@ -2097,6 +2257,14 @@ pub struct MasterKvRouterInner { /// (key, put_time_ms, put_version) -> inflight_put_info pub inflight_puts: moka::future::Cache<(String, u64, u32), InflightPutInfo>, pub inflight_replica_tasks: moka::future::Cache<(String, u64, u32), InflightReplicaTaskInfo>, + /// Idempotent terminal PutAppendDone results retained across response + /// loss and batch-to-individual fallback. + pub completed_replica_tasks: + moka::future::Cache<(String, u64, u32, u64), CompletedReplicaTaskInfo>, + /// Serializes Start/Done/Revoke for one replica operation identity. The + /// lock is per `(key, put_id)`, so unrelated remote writes never share a + /// queue or actor. + pub replica_operation_locks: AMapLock<(String, u64, u32)>, pub inflight_gets: moka::future::Cache, /// Idempotent terminal GetDone results retained across response loss/retry. pub completed_gets: moka::future::Cache, @@ -2119,6 +2287,11 @@ pub struct MasterKvRouterInner { /// Counter for prepared put-key reservation identifiers. pub next_prepared_put_key_reservation_id: AtomicU64, + /// Counter for concrete replica append attempts. This is separate from + /// `put_id`: one KV generation may legitimately be copied remotely again + /// after its previous remote route is reclaimed. + pub next_replica_operation_id: AtomicU64, + /// Counter for two-sided owner reclaim epochs. pub next_owner_reclaim_epoch: AtomicU64, @@ -2180,6 +2353,9 @@ pub struct MasterKvRouterInner { /// Historical accepted replica task reservations by target node. pub replica_task_target_counts: DashMap>, + /// PutAppendDone responses served from the terminal cache after an RPC + /// replay or batch fallback. + pub replica_done_terminal_replay_count: AtomicU64, /// Historical get source choices by requester->source pair. pub get_requester_source_counts: DashMap>, @@ -2319,6 +2495,9 @@ impl MasterKvRouter { } }) .build(); + let completed_replica_tasks = moka::future::Cache::builder() + .time_to_live(Duration::from_secs(120)) + .build(); // A synchronous Moka listener must perform only constant-size metadata // work and must never block or drop an Allocation reclaim event. The // versioned inflight set deduplicates this unbounded channel. @@ -2336,6 +2515,8 @@ impl MasterKvRouter { replica_writeback_tier1_capacity_ratio: arg.replica_writeback_tier1_capacity_ratio, inflight_puts, inflight_replica_tasks, + completed_replica_tasks, + replica_operation_locks: AMapLock::new(Duration::from_secs(10 * 60)), inflight_gets, completed_gets, get_done_locks: AMapLock::new(Duration::from_secs(10 * 60)), @@ -2346,6 +2527,7 @@ impl MasterKvRouter { next_holder_id: AtomicU64::new(0), next_local_reserve_grant_id: AtomicU64::new(1), next_prepared_put_key_reservation_id: AtomicU64::new(1), + next_replica_operation_id: AtomicU64::new(1), next_owner_reclaim_epoch: AtomicU64::new(1), kv_routes: DashMap::new(), put_atomic_groups: moka::sync::SegmentedCache::builder(8) @@ -2366,6 +2548,7 @@ impl MasterKvRouter { put_requester_target_decision_counts: DashMap::new(), put_placement_mode_counts: DashMap::new(), replica_task_target_counts: DashMap::new(), + replica_done_terminal_replay_count: AtomicU64::new(0), get_requester_source_counts: DashMap::new(), get_requester_source_bytes: DashMap::new(), get_allocation_mode_counts: DashMap::new(), @@ -2440,7 +2623,13 @@ impl MasterKvRouter { } fn replica_cache_base_capacity(&self, node_space_size: u64) -> u64 { - (node_space_size as f64 * self.inner().replica_cache_capacity_ratio).floor() as u64 + node_cache_capacity_boundaries( + node_space_size, + self.inner().replica_cache_capacity_ratio, + self.inner().replica_writeback_tier1_capacity_ratio, + 0, + ) + .ring_b_bytes } fn replica_cache_effective_capacity(&self, node_id: &str, node_space_size: u64) -> u64 { @@ -2451,13 +2640,19 @@ impl MasterKvRouter { .filter(|reserved| !reserved.generation.is_tomb()) .map(|reserved| reserved.total_reserved_bytes()) .unwrap_or(0); - self.replica_cache_base_capacity(node_space_size) - .saturating_sub(reserved_capacity) + node_cache_capacity_boundaries( + node_space_size, + self.inner().replica_cache_capacity_ratio, + self.inner().replica_writeback_tier1_capacity_ratio, + reserved_capacity, + ) + .ring_b_bytes } - /// Refresh an already-created node controller after segment metadata or - /// reservation inputs change. The boundary is derived only from physical - /// node space and generation-scoped reservations, never placement roles. + /// Refresh already-created node controllers after segment metadata or + /// reservation inputs change. Generation-scoped reservations reduce only + /// the physical ring-B allocation boundary. Tier1 is an inclusive metadata + /// policy window and always remains ratio-derived from the owner segment. fn reconcile_node_cache_capacity(&self, node_id: &str) { let node_space_size = self .inner() @@ -2489,8 +2684,7 @@ impl MasterKvRouter { { let tier1_capacity = self .writeback_tier1_base_capacity(node_space_size) - .unwrap_or(0) - .min(capacity); + .unwrap_or(0); if let Err(err) = cache.set_max_capacity(tier1_capacity) { error!( "failed to refresh tier1 cache capacity: node={} capacity={} err={}", @@ -2501,9 +2695,13 @@ impl MasterKvRouter { } fn writeback_tier1_base_capacity(&self, node_space_size: u64) -> Option { - self.inner() - .replica_writeback_tier1_capacity_ratio - .map(|ratio| (node_space_size as f64 * ratio).floor() as u64) + node_cache_capacity_boundaries( + node_space_size, + self.inner().replica_cache_capacity_ratio, + self.inner().replica_writeback_tier1_capacity_ratio, + 0, + ) + .tier1_bytes } pub fn tiered_writeback_enabled(&self) -> bool { @@ -4363,6 +4561,10 @@ impl MasterKvRouter { .map(|entry| (entry.key().clone(), entry.value().load(Ordering::Relaxed))) .collect(); replica_task_target_counts.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(&b.0))); + let replica_done_terminal_replays = router + .inner() + .replica_done_terminal_replay_count + .load(Ordering::Relaxed); let mut get_source_counts: Vec<(String, u64)> = router .inner() @@ -4389,11 +4591,12 @@ impl MasterKvRouter { get_allocation_mode_counts.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(&b.0))); info!( - "placement historical distribution | put_target_counts={:?} | put_mode_counts={:?} | put_requester_target_counts={:?} | replica_task_target_counts={:?} | get_requester_source_counts={:?} | get_requester_source_bytes={:?} | get_allocation_mode_counts={:?}", + "placement historical distribution | put_target_counts={:?} | put_mode_counts={:?} | put_requester_target_counts={:?} | replica_task_target_counts={:?} | replica_done_terminal_replays={} | get_requester_source_counts={:?} | get_requester_source_bytes={:?} | get_allocation_mode_counts={:?}", target_counts, mode_counts, requester_target_counts, replica_task_target_counts, + replica_done_terminal_replays, get_source_counts, get_source_bytes, get_allocation_mode_counts, @@ -4738,8 +4941,13 @@ impl MasterKvRouter { ), ); } - let base_capacity = self.replica_cache_base_capacity(node_space_size); - let new_capacity = base_capacity.saturating_sub(reserved_total); + let boundaries = node_cache_capacity_boundaries( + node_space_size, + self.inner().replica_cache_capacity_ratio, + self.inner().replica_writeback_tier1_capacity_ratio, + reserved_total, + ); + let new_capacity = boundaries.ring_b_bytes; if let Some(cache) = self.get_node_cache_controller(node_id) { if let Some(tier1_cache) = self @@ -4748,10 +4956,10 @@ impl MasterKvRouter { .get(node_id) .map(|entry| entry.value().clone()) { - let tier1_capacity = self - .writeback_tier1_base_capacity(node_space_size) - .unwrap_or(0) - .min(new_capacity); + // Local-reserve and owner-indexed reservations consume the + // physical ring-B allocation domain. They must not collapse + // the independent inclusive tier1 metadata window. + let tier1_capacity = boundaries.tier1_bytes.unwrap_or(0); if let Err(e) = tier1_cache.set_max_capacity(tier1_capacity) { if delta_bytes >= 0 { reserved_capacity.apply_delta(reason, -delta_bytes); @@ -5079,6 +5287,11 @@ impl MasterKvRouter { _ = shutdown_waiter.wait() => break, _ = interval.tick() => { let snapshot = view_task.master_kv_router().runtime_observe_snapshot(); + let activity = view_task + .master_kv_router() + .inner() + .key_activity + .observe_snapshot(); let metrics = view_task.metric_reporter().metrics(); metrics.set_kv_holding_entries( "master_get_holding", @@ -5093,6 +5306,17 @@ impl MasterKvRouter { snapshot.get_holding_entries, snapshot.get_holding_bytes ); + tracing::info!( + active_keys = activity.active_keys, + put_keys = activity.put_keys, + get_keys = activity.get_keys, + replica_keys = activity.replica_keys, + reclaim_keys = activity.reclaim_keys, + inflight_puts = activity.inflight_puts, + inflight_gets = activity.inflight_gets, + inflight_replicas = activity.inflight_replicas, + "master key activity runtime" + ); for node in snapshot.replica_cache_nodes { tracing::info!( "replica cache runtime: owner={} entries={} weighted_bytes={} effective_capacity_bytes={} base_capacity_bytes={} reserved_capacity_bytes={} pending_eviction_reclaim_bytes={} writeback_tier1_entries={} writeback_tier1_weighted_bytes={} writeback_tier1_capacity_bytes={} writeback_tier1_triggered={} writeback_tier1_owner_accepted={} writeback_tier1_failed={} reclaim_master_activity_deferred={} reclaim_owner_holder_deferred={} reclaim_owner_other_deferred={} reclaim_route_changed={} reclaim_retry_queued={} reclaim_retry_completed={} reclaim_retry_restored={} reclaim_completed={} source_evict_rpc_requests={} source_evict_victims={} source_evict_requested_bytes={} source_evict_accepted={} source_evict_in_progress={} source_evict_completed={} source_evict_retryable_busy={} source_evict_stale={} source_evict_rejected={} last_route_removed_members={} last_route_removed_bytes={} capacity_eviction_non_ring_b_entry_total={} capacity_eviction_hit_committed_slot={} eviction_reclaim_deduplicated={}", diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs index da9b0b8..7ba3eb0 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs @@ -1018,6 +1018,13 @@ pub enum PutAppendStartOutcome { #[derive(Default, Debug, Clone, Encode, Decode)] pub struct PutAppendStartResp { pub outcome: PutAppendStartOutcome, + /// Master-issued identity for this concrete replica append attempt. + /// + /// `put_id` identifies the KV generation, but one generation may need to + /// be copied remotely more than once after an earlier remote route is + /// reclaimed. Done/Revoke must echo this value so an old replayable + /// terminal result cannot complete a later reservation. + pub operation_id: u64, pub node_id: NodeIDString, pub target_addr: u64, pub target_base_addr: u64, @@ -1059,6 +1066,7 @@ pub struct BatchPutAppendStartItemResp { pub key: String, pub put_id: PutIDForAKey, pub outcome: PutAppendStartOutcome, + pub operation_id: u64, pub node_id: NodeIDString, pub target_addr: u64, pub target_base_addr: u64, @@ -1087,6 +1095,7 @@ impl RPCReq for BatchPutAppendStartReq { pub struct PutAppendRevokeReq { pub key: String, pub put_id: PutIDForAKey, + pub operation_id: u64, } impl MsgPackSerializePart for PutAppendRevokeReq { fn msg_id(&self) -> u32 { @@ -1111,6 +1120,7 @@ impl RPCReq for PutAppendRevokeReq { pub struct PutAppendDoneReq { pub key: String, pub put_id: PutIDForAKey, + pub operation_id: u64, } impl MsgPackSerializePart for PutAppendDoneReq { fn msg_id(&self) -> u32 { @@ -1137,6 +1147,7 @@ impl RPCReq for PutAppendDoneReq { pub struct BatchPutAppendDoneItemReq { pub key: String, pub put_id: PutIDForAKey, + pub operation_id: u64, } #[derive(Default, Debug, Clone, Encode, Decode)] diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs index 1edc824..f5bdef4 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs @@ -1,6 +1,6 @@ use super::{ - CommittedSlotReplica, InflightPutAllocation, InflightPutCommitInfo, InflightPutInfo, - InflightReplicaTaskInfo, KvReplicaBacking, KvRouteInfo, LocalReserveGrantInfo, + CommittedSlotReplica, CompletedReplicaTaskInfo, InflightPutAllocation, InflightPutCommitInfo, + InflightPutInfo, InflightReplicaTaskInfo, KvReplicaBacking, KvRouteInfo, LocalReserveGrantInfo, MasterKeyActivityCompletionGuard, MasterKvRouterView, NodeCacheCapacityReservation, OwnerHoldingGetInfo, PreparedPutKeyReservationInfo, PutPlacementMode, ReservedCapacityReason, msg_pack::{ @@ -487,6 +487,15 @@ fn reserve_replica_task_excluding( protect_source_on_remote_complete: bool, ) -> msg_and_error::KvResult { let activity_lease = view.master_kv_router().reserve_inflight_replica_key(key)?; + let operation_id = view + .master_kv_router() + .inner() + .next_replica_operation_id + .fetch_add(1, std::sync::atomic::Ordering::Relaxed); + assert_ne!( + operation_id, 0, + "master replica operation identifier overflow" + ); view.master_kv_router() .pin_current_master_cache_identity_for_activity( &activity_lease, @@ -519,16 +528,18 @@ fn reserve_replica_task_excluding( )); }; tracing::debug!( - "replica task reserved: key={} put_id=({},{}) source_node_id={} target_node_id={} preferred_sub_cluster={:?} len={}", + "replica task reserved: key={} put_id=({},{}) operation_id={} source_node_id={} target_node_id={} preferred_sub_cluster={:?} len={}", key, put_id.0, put_id.1, + operation_id, source_node_id, target_node_id, preferred_sub_cluster, len ); Ok(InflightReplicaTaskInfo { + operation_id, node_id: target_node_id, target_tomb_tag, source_node_id: source_node_id.clone(), @@ -2109,6 +2120,13 @@ async fn handle_put_append_start_inner( ) -> MsgPack { let key = req.serialize_part.key.clone(); let put_id = req.serialize_part.put_id; + let append_key = (key.clone(), put_id.0, put_id.1); + let operation_lock = view + .master_kv_router() + .inner() + .replica_operation_locks + .get_lock(append_key.clone()); + let _operation_guard = operation_lock.lock().await; let route_snapshot = view .master_kv_router() .inner() @@ -2140,7 +2158,6 @@ async fn handle_put_append_start_inner( }; } - let append_key = (key.clone(), put_id.0, put_id.1); let inflight = if let Some(existing) = view .master_kv_router() .inner() @@ -2245,6 +2262,7 @@ async fn handle_put_append_start_inner( MsgPack { serialize_part: PutAppendStartResp { outcome: PutAppendStartOutcome::Scheduled, + operation_id: inflight.operation_id, node_id: inflight.node_id.clone().into(), target_addr, target_base_addr, @@ -2294,6 +2312,7 @@ pub async fn handle_batch_put_append_start( key: item.key, put_id: item.put_id, outcome: part.outcome, + operation_id: part.operation_id, node_id: part.node_id, target_addr: part.target_addr, target_base_addr: part.target_base_addr, @@ -2319,14 +2338,50 @@ pub async fn handle_put_append_revoke( ) -> MsgPack { let put_id = req.serialize_part.put_id; let key = req.serialize_part.key; - if let Some(inflight) = view + let operation_id = req.serialize_part.operation_id; + let generation_identity = (key.clone(), put_id.0, put_id.1); + let operation_identity = (key.clone(), put_id.0, put_id.1, operation_id); + let operation_lock = view .master_kv_router() .inner() - .inflight_replica_tasks - .remove(&(key, put_id.0, put_id.1)) + .replica_operation_locks + .get_lock(generation_identity.clone()); + let _operation_guard = operation_lock.lock().await; + if view + .master_kv_router() + .inner() + .completed_replica_tasks + .get(&operation_identity) .await + .is_some() { - inflight._activity_lease.release_now(); + return MsgPack { + serialize_part: PutAppendRevokeResp { + error_code: msg_and_error::OK, + error_json: String::new(), + }, + raw_bytes: Vec::new(), + }; + } + let inflight = view + .master_kv_router() + .inner() + .inflight_replica_tasks + .get(&generation_identity) + .await; + if inflight + .as_ref() + .is_some_and(|inflight| inflight.operation_id == operation_id) + { + if let Some(inflight) = view + .master_kv_router() + .inner() + .inflight_replica_tasks + .remove(&generation_identity) + .await + { + inflight._activity_lease.release_now(); + } } MsgPack { serialize_part: PutAppendRevokeResp { @@ -2343,17 +2398,77 @@ async fn handle_put_append_done_inner( ) -> MsgPack { let put_id = req.serialize_part.put_id; let key = req.serialize_part.key.clone(); + let operation_id = req.serialize_part.operation_id; + let generation_identity = (key.clone(), put_id.0, put_id.1); + let operation_identity = (key.clone(), put_id.0, put_id.1, operation_id); + let operation_lock = view + .master_kv_router() + .inner() + .replica_operation_locks + .get_lock(generation_identity.clone()); + let _operation_guard = operation_lock.lock().await; + if let Some(completed) = view + .master_kv_router() + .inner() + .completed_replica_tasks + .get(&operation_identity) + .await + { + view.master_kv_router() + .inner() + .replica_done_terminal_replay_count + .fetch_add(1, std::sync::atomic::Ordering::Relaxed); + return MsgPack { + serialize_part: PutAppendDoneResp { + appended: completed.appended, + error_code: msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + }, + raw_bytes: Vec::new(), + }; + } + let Some(current) = view + .master_kv_router() + .inner() + .inflight_replica_tasks + .get(&generation_identity) + .await + else { + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "Put append operation not found for completion: key={} put_id=({},{}) operation_id={}", + key, put_id.0, put_id.1, operation_id + ), + }); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), + raw_bytes: Vec::new(), + }; + }; + if current.operation_id != operation_id { + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "Put append operation generation mismatch: key={} put_id=({},{}) requested_operation_id={} current_operation_id={}", + key, put_id.0, put_id.1, operation_id, current.operation_id + ), + }); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), + raw_bytes: Vec::new(), + }; + } let Some(inflight) = view .master_kv_router() .inner() .inflight_replica_tasks - .remove(&(key.clone(), put_id.0, put_id.1)) + .remove(&generation_identity) .await else { let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { detail: format!( - "Put append operation not found for completion: key={} put_id=({},{})", - key, put_id.0, put_id.1 + "Put append operation disappeared during completion: key={} put_id=({},{}) operation_id={}", + key, put_id.0, put_id.1, operation_id ), }); return MsgPack { @@ -2384,6 +2499,11 @@ async fn handle_put_append_done_inner( allocation, ); let appended = published.is_some(); + view.master_kv_router() + .inner() + .completed_replica_tasks + .insert(operation_identity, CompletedReplicaTaskInfo { appended }) + .await; if let Some(event) = published { enqueue_post_route_maintenance(&view, event).await; } @@ -2413,10 +2533,15 @@ pub async fn handle_batch_put_append_done( for item in req.serialize_part.items { let key = item.key.clone(); let put_id = item.put_id; + let operation_id = item.operation_id; let resp = handle_put_append_done_inner( view.clone(), MsgPack { - serialize_part: PutAppendDoneReq { key, put_id }, + serialize_part: PutAppendDoneReq { + key, + put_id, + operation_id, + }, raw_bytes: Vec::new(), }, ) diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs index 22f7df6..f42cd24 100644 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs @@ -363,7 +363,7 @@ mod single_victim_transaction_tests { .expect("busy victim must hold a master Get lease"); let stale_request = source_victim("stale", stale.put_id, 999, 2); let victims = vec![ready.clone(), busy.clone(), stale_request]; - let responses = direct_delete_exact_owner_source_batch_with( + let (responses, busy_summary) = direct_delete_exact_owner_source_batch_with( activity.as_ref(), &owner, 77, @@ -391,6 +391,15 @@ mod single_victim_transaction_tests { vec![0, 1, 2], "one batch response vector must stay aligned with every input victim" ); + assert_eq!( + busy_summary, + DirectDeleteBatchBusySummary { + activity_busy_items: 1, + get_busy_items: 1, + inflight_gets: 1, + ..Default::default() + } + ); assert!(!routes.contains_key(&ready.key)); assert!(routes.contains_key(&busy.key)); assert!(routes.contains_key(&stale.key)); @@ -408,7 +417,8 @@ mod single_victim_transaction_tests { false }, ); - assert_eq!(replay.0, OwnerSourceEvictionOutcome::Completed); + assert_eq!(replay.outcome, OwnerSourceEvictionOutcome::Completed); + assert_eq!(replay.busy_cause, None); assert!(!replay_delete_called.load(Ordering::Relaxed)); } } @@ -904,6 +914,92 @@ fn plan_exact_owner_source_victim_with( OwnerSourceVictimPlan::Ready(planned) } +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum DirectDeleteBusyCause { + MasterActivity(super::MasterKeyActivitySnapshot), + DeleteUnderFence, +} + +struct DirectDeleteResult { + outcome: OwnerSourceEvictionOutcome, + detail: String, + busy_cause: Option, +} + +impl DirectDeleteResult { + fn terminal(outcome: OwnerSourceEvictionOutcome, detail: impl Into) -> Self { + Self { + outcome, + detail: detail.into(), + busy_cause: None, + } + } + + fn activity_busy(snapshot: super::MasterKeyActivitySnapshot) -> Self { + Self { + outcome: OwnerSourceEvictionOutcome::RetryableBusy, + detail: format!( + "master key activity is busy: puts={} gets={} replicas={} reclaim_installed={}", + snapshot.puts, snapshot.gets, snapshot.replicas, snapshot.reclaim_installed + ), + busy_cause: Some(DirectDeleteBusyCause::MasterActivity(snapshot)), + } + } + + fn delete_under_fence_busy() -> Self { + Self { + outcome: OwnerSourceEvictionOutcome::RetryableBusy, + detail: "exact source route could not be deleted under its master fence".to_string(), + busy_cause: Some(DirectDeleteBusyCause::DeleteUnderFence), + } + } +} + +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] +struct DirectDeleteBatchBusySummary { + activity_busy_items: u64, + put_busy_items: u64, + get_busy_items: u64, + replica_busy_items: u64, + reclaim_busy_items: u64, + inflight_puts: u64, + inflight_gets: u64, + inflight_replicas: u64, + delete_under_fence_busy_items: u64, +} + +impl DirectDeleteBatchBusySummary { + fn record(&mut self, cause: Option) { + match cause { + Some(DirectDeleteBusyCause::MasterActivity(snapshot)) => { + self.activity_busy_items = self.activity_busy_items.saturating_add(1); + self.put_busy_items = self + .put_busy_items + .saturating_add(u64::from(snapshot.puts != 0)); + self.get_busy_items = self + .get_busy_items + .saturating_add(u64::from(snapshot.gets != 0)); + self.replica_busy_items = self + .replica_busy_items + .saturating_add(u64::from(snapshot.replicas != 0)); + self.reclaim_busy_items = self + .reclaim_busy_items + .saturating_add(u64::from(snapshot.reclaim_installed)); + self.inflight_puts = self.inflight_puts.saturating_add(u64::from(snapshot.puts)); + self.inflight_gets = self.inflight_gets.saturating_add(u64::from(snapshot.gets)); + self.inflight_replicas = self + .inflight_replicas + .saturating_add(u64::from(snapshot.replicas)); + } + Some(DirectDeleteBusyCause::DeleteUnderFence) => { + self.delete_under_fence_busy_items = + self.delete_under_fence_busy_items.saturating_add(1); + } + None => {} + } + } +} + fn direct_delete_exact_owner_source_with( activity: &super::MasterKeyActivityTable, owner: &NodeID, @@ -911,17 +1007,20 @@ fn direct_delete_exact_owner_source_with( epoch: u64, route_lookup: &dyn Fn(&str) -> Option>, delete: impl FnOnce(&OwnerReclaimItem) -> bool, -) -> (OwnerSourceEvictionOutcome, String) { +) -> DirectDeleteResult { let member = match plan_exact_owner_source_victim_with(owner, victim, route_lookup) { OwnerSourceVictimPlan::Ready(member) => member, OwnerSourceVictimPlan::Completed(detail) => { - return (OwnerSourceEvictionOutcome::Completed, detail.to_string()); + return DirectDeleteResult::terminal(OwnerSourceEvictionOutcome::Completed, detail); } OwnerSourceVictimPlan::Stale(detail) => { - return (OwnerSourceEvictionOutcome::Stale, detail); + return DirectDeleteResult::terminal(OwnerSourceEvictionOutcome::Stale, detail); } OwnerSourceVictimPlan::Rejected(detail) => { - return (OwnerSourceEvictionOutcome::RejectedNotEvictable, detail); + return DirectDeleteResult::terminal( + OwnerSourceEvictionOutcome::RejectedNotEvictable, + detail, + ); } }; let item = OwnerReclaimItem { @@ -934,35 +1033,28 @@ fn direct_delete_exact_owner_source_with( reason: OwnerReclaimReason::OwnerCapacityEviction, }; if let Err(snapshot) = activity.try_install_reclaim(&item) { - return ( - OwnerSourceEvictionOutcome::RetryableBusy, - format!( - "master key activity is busy: puts={} gets={} replicas={} reclaim_installed={}", - snapshot.puts, snapshot.gets, snapshot.replicas, snapshot.reclaim_installed - ), - ); + return DirectDeleteResult::activity_busy(snapshot); } let result = match plan_exact_owner_source_victim_with(owner, victim, route_lookup) { OwnerSourceVictimPlan::Ready(_) => { if delete(&item) { - ( + DirectDeleteResult::terminal( OwnerSourceEvictionOutcome::Completed, - "exact source route deleted by batch handler".to_string(), + "exact source route deleted by batch handler", ) } else { - ( - OwnerSourceEvictionOutcome::RetryableBusy, - "exact source route could not be deleted under its master fence".to_string(), - ) + DirectDeleteResult::delete_under_fence_busy() } } OwnerSourceVictimPlan::Completed(detail) => { - (OwnerSourceEvictionOutcome::Completed, detail.to_string()) + DirectDeleteResult::terminal(OwnerSourceEvictionOutcome::Completed, detail) + } + OwnerSourceVictimPlan::Stale(detail) => { + DirectDeleteResult::terminal(OwnerSourceEvictionOutcome::Stale, detail) } - OwnerSourceVictimPlan::Stale(detail) => (OwnerSourceEvictionOutcome::Stale, detail), OwnerSourceVictimPlan::Rejected(detail) => { - (OwnerSourceEvictionOutcome::RejectedNotEvictable, detail) + DirectDeleteResult::terminal(OwnerSourceEvictionOutcome::RejectedNotEvictable, detail) } }; assert!( @@ -979,26 +1071,29 @@ fn direct_delete_exact_owner_source_batch_with( victims: &[OwnerSourceEvictionVictim], route_lookup: &dyn Fn(&str) -> Option>, delete: impl Fn(&OwnerReclaimItem) -> bool, -) -> Vec { - victims - .iter() - .enumerate() - .map(|(index, victim)| { - let (outcome, detail) = direct_delete_exact_owner_source_with( - activity, - owner, - victim, - owner_source_eviction_epoch(operation_id, index), - route_lookup, - |item| delete(item), - ); - OwnerSourceEvictionVictimResp { - victim_index: u32::try_from(index).unwrap_or(u32::MAX), - outcome, - detail, - } - }) - .collect() +) -> ( + Vec, + DirectDeleteBatchBusySummary, +) { + let mut responses = Vec::with_capacity(victims.len()); + let mut busy = DirectDeleteBatchBusySummary::default(); + for (index, victim) in victims.iter().enumerate() { + let result = direct_delete_exact_owner_source_with( + activity, + owner, + victim, + owner_source_eviction_epoch(operation_id, index), + route_lookup, + |item| delete(item), + ); + busy.record(result.busy_cause); + responses.push(OwnerSourceEvictionVictimResp { + victim_index: u32::try_from(index).unwrap_or(u32::MAX), + outcome: result.outcome, + detail: result.detail, + }); + } + (responses, busy) } pub(crate) async fn handle_batch_evict_owner_source( @@ -1053,7 +1148,7 @@ pub(crate) async fn handle_batch_evict_owner_source( }; } - let responses = direct_delete_exact_owner_source_batch_with( + let (responses, busy) = direct_delete_exact_owner_source_batch_with( &view.master_kv_router().inner().key_activity, &owner, operation_id, @@ -1095,6 +1190,15 @@ pub(crate) async fn handle_batch_evict_owner_source( victims = responses.len(), completed, retryable, + activity_busy_items = busy.activity_busy_items, + put_busy_items = busy.put_busy_items, + get_busy_items = busy.get_busy_items, + replica_busy_items = busy.replica_busy_items, + reclaim_busy_items = busy.reclaim_busy_items, + inflight_puts = busy.inflight_puts, + inflight_gets = busy.inflight_gets, + inflight_replicas = busy.inflight_replicas, + delete_under_fence_busy_items = busy.delete_under_fence_busy_items, "owner source direct-delete batch completed" ); diff --git a/fluxon_rs/fluxon_kv/src/memholder/lifetime.rs b/fluxon_rs/fluxon_kv/src/memholder/lifetime.rs index e070b1d..92a559b 100755 --- a/fluxon_rs/fluxon_kv/src/memholder/lifetime.rs +++ b/fluxon_rs/fluxon_kv/src/memholder/lifetime.rs @@ -20,8 +20,6 @@ use std::collections::HashSet; use std::hash::Hash; use std::time::Duration; -const EXTERNAL_DELETE_ACK_TIMEOUT_SECS: u64 = 5; - pub type OwnerDeleteAckItem = DeleteAckItem; /// Spawn an async task only if the framework/view is still running. @@ -128,7 +126,6 @@ impl MemholderDropAck for OwnerDeleteAckCtx { pub struct ExternalDeleteAckCtx { pub view: ExternalClientApiView, - pub key: String, pub external_client_id: String, pub holder_id: u64, pub started_time: i64, @@ -148,75 +145,25 @@ impl MemholderDropAck for ExternalDeleteAckCtx { } fn ack_future( &self, - guard: Self::Guard, + _guard: Self::Guard, ) -> std::pin::Pin + Send>> { - let v = self.view.clone(); - let key = self.key.clone(); - let external_client_id = self.external_client_id.clone(); - let holder_id = self.holder_id; - let started_time = self.started_time; - Box::pin(async move { - let _keep = guard; - // Best-effort drop ACK must not outlive framework shutdown. - // During step8 teardown, the owner/external peers can already be concurrently exiting, - // and the ACK RPC can otherwise stall long enough to block task_registry shutdown. - match tokio::time::timeout( - Duration::from_secs(EXTERNAL_DELETE_ACK_TIMEOUT_SECS), - v.external_client_api().inner().send_external_delete_ack( - &key, - &external_client_id, - holder_id, - started_time, - ), - ) - .await - { - Err(_) => { - tracing::warn!( - "Timed out sending external_delete_ack for key={}, holder_id={}, external_client_id={} after {}s", - key, - holder_id, - external_client_id, - EXTERNAL_DELETE_ACK_TIMEOUT_SECS - ); - } - Ok(Err(e)) => { - tracing::warn!( - "Failed to send external_delete_ack for key={}, holder_id={}, external_client_id={}: {}", - key, - holder_id, - external_client_id, - e - ); - } - Ok(Ok(())) => { - tracing::debug!( - "Successfully sent external_delete_ack for key={}, holder_id={}, external_client_id={}", - key, - holder_id, - external_client_id - ); - } - } - }) + Box::pin(async { unreachable!("external holder ACKs are enqueued synchronously") }) } fn on_view_dropped(&self) { tracing::warn!( - "ExternalClientApiView has been dropped, cannot send external_delete_ack for key='{}', holder_id {}.", - self.key, + "ExternalClientApiView has been dropped, cannot enqueue external_delete_ack for holder_id {}.", self.holder_id ); } fn on_skip_shutdown(&self) { tracing::info!( - "Skipping external_delete_ack for key={}, holder_id={} due to shutdown", - self.key, + "Skipping external_delete_ack for holder_id={} due to shutdown", self.holder_id ); } fn run_drop_ack(&self) { let v = self.view().clone(); - let Some(g) = ::try_upgrade(&v) else { + let Some(_guard) = ::try_upgrade(&v) else { self.on_view_dropped(); return; }; @@ -224,8 +171,18 @@ impl MemholderDropAck for ExternalDeleteAckCtx { self.on_skip_shutdown(); return; } - let fut = self.ack_future(g); - let _ = v.spawn("memholder_drop_ack_external", async move { fut.await }); + if let Err(err) = v.external_client_api().inner().enqueue_external_delete_ack( + self.external_client_id.clone(), + self.holder_id, + self.started_time, + ) { + tracing::warn!( + holder_id = self.holder_id, + external_client_id = %self.external_client_id, + error = %err, + "failed to enqueue external holder ACK" + ); + } } } diff --git a/fluxon_rs/fluxon_kv/src/memholder/mod.rs b/fluxon_rs/fluxon_kv/src/memholder/mod.rs index f44f7c3..f23c88a 100755 --- a/fluxon_rs/fluxon_kv/src/memholder/mod.rs +++ b/fluxon_rs/fluxon_kv/src/memholder/mod.rs @@ -405,7 +405,6 @@ impl Drop for ExternalMemHolder { let ctx = ExternalDeleteAckCtx { view: self.view.clone(), - key: self.key.clone(), external_client_id: self.external_client_id.clone(), holder_id: self.holder_id, started_time: self.owner_start_time, diff --git a/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/rpcresp_kvresult_convert.rs b/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/rpcresp_kvresult_convert.rs index 30ee572..77efaac 100755 --- a/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/rpcresp_kvresult_convert.rs +++ b/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/rpcresp_kvresult_convert.rs @@ -3,10 +3,10 @@ use super::msg_and_error::{ ApiError, ConfigError, ErrorCode, KvError, KvResult, SharedMemError, UnreachableError, }; use crate::client_kv_api::msg_pack::{ - ExternalBatchGetCancelResp, ExternalBatchGetItemResp, ExternalBatchGetResp, - ExternalBatchGetStartResp, ExternalBatchGetTransferResp, ExternalBatchIsExistResp, - ExternalBatchPutCommitItemResp, ExternalBatchPutCommitResp, ExternalBatchPutStartItemResp, - ExternalBatchPutStartResp, ExternalBatchPutTransferEndItemResp, + ExternalBatchDeleteAckResp, ExternalBatchGetCancelResp, ExternalBatchGetItemResp, + ExternalBatchGetResp, ExternalBatchGetStartResp, ExternalBatchGetTransferResp, + ExternalBatchIsExistResp, ExternalBatchPutCommitItemResp, ExternalBatchPutCommitResp, + ExternalBatchPutStartItemResp, ExternalBatchPutStartResp, ExternalBatchPutTransferEndItemResp, ExternalBatchPutTransferEndResp, ExternalDeleteAckResp, ExternalDeleteResp, ExternalGetResp, ExternalIsExistResp, ExternalObservabilitySnapshotResp, ExternalPutCommitResp, ExternalPutRevokeResp, ExternalPutStartResp, ExternalPutTransferEndResp, @@ -151,6 +151,17 @@ impl ToResult for ExternalDeleteAckResp { } } +impl ToResult for ExternalBatchDeleteAckResp { + type Ok = ExternalBatchDeleteAckResp; + fn to_result(self) -> KvResult { + if self.error_code == OK { + Ok(self) + } else { + Err(KvError::from_json(self.error_code, &self.error_json)) + } + } +} + impl ToResult for BatchIsExistResp { type Ok = Vec; fn to_result(self) -> KvResult { @@ -391,6 +402,16 @@ impl FromError for ExternalDeleteAckResp { } } } +impl FromError for ExternalBatchDeleteAckResp { + fn from_error(e: &KvError) -> Self { + let code = e.code(); + Self { + error_code: code, + error_json: e.to_json(), + ..Default::default() + } + } +} // ---- FromError for Master KV Router Resps ---- impl FromError for GetStartResp { diff --git a/fluxon_rs/fluxon_pyo3/src/lib.rs b/fluxon_rs/fluxon_pyo3/src/lib.rs index 412ec5f..be1a652 100644 --- a/fluxon_rs/fluxon_pyo3/src/lib.rs +++ b/fluxon_rs/fluxon_pyo3/src/lib.rs @@ -4615,9 +4615,14 @@ impl KvClient { .into_py_object(py) } - #[pyo3(signature = (handle))] - fn get_transfer(&self, handle: u64, py: Python) -> PyObject { - fn get_transfer_inner(client: &KvClient, handle: u64, py: Python) -> ApiResult { + #[pyo3(signature = (handle, consume_prefix_len=None))] + fn get_transfer(&self, handle: u64, consume_prefix_len: Option, py: Python) -> PyObject { + fn get_transfer_inner( + client: &KvClient, + handle: u64, + consume_prefix_len: Option, + py: Python, + ) -> ApiResult { let runtime = match client.runtime.as_ref() { Some(v) => v, None => { @@ -4644,7 +4649,7 @@ impl KvClient { .external_client_api_view() .external_client_api() .inner() - .get_transfer(handle) + .get_transfer(handle, consume_prefix_len) .await }) }) { @@ -4704,7 +4709,7 @@ impl KvClient { ApiResult::new_success((plan_ptr as u64).into_py(py)) } - get_transfer_inner(self, handle, py).into_py_object(py) + get_transfer_inner(self, handle, consume_prefix_len, py).into_py_object(py) } #[pyo3(signature = (handle))] From 2fa4448c7554ecbb2a50c56b3b32dbb02a28ea5b Mon Sep 17 00:00:00 2001 From: zTz01 <1773266173@qq.com> Date: Wed, 22 Jul 2026 19:26:41 +0800 Subject: [PATCH 08/10] backup --- fluxon_py/__init__.py | 6 + fluxon_py/kvclient/fluxon.py | 446 ++++++++++++ .../src/facade/transfer_engine.rs | 49 +- .../src/lib.rs | 12 +- .../src/closed_runtime.rs | 12 + fluxon_rs/fluxon_kv/framework_init_steps.yaml | 4 +- fluxon_rs/fluxon_kv/src/client_kv_api/get.rs | 2 + .../fluxon_kv/src/client_seg_pool/mod.rs | 36 +- .../src/client_transfer_engine/mod.rs | 572 ++++++++++++++- .../fluxon_kv/src/external_client_api/mod.rs | 687 +++++++++++++++++- fluxon_rs/fluxon_kv/src/lib.rs | 23 + .../fluxon_kv/src/master_kv_router/get.rs | 354 +++++++-- .../fluxon_kv/src/master_kv_router/mod.rs | 11 +- .../src/master_kv_router/msg_pack.rs | 20 + fluxon_rs/fluxon_pyo3/src/lib.rs | 428 +++++++++++ setup_and_pack/nix/pack_fluxonkv_pylib.py | 15 + .../tests/test_vendor_runtime_layout.py | 9 + 17 files changed, 2574 insertions(+), 112 deletions(-) diff --git a/fluxon_py/__init__.py b/fluxon_py/__init__.py index 753281c..7c57441 100644 --- a/fluxon_py/__init__.py +++ b/fluxon_py/__init__.py @@ -66,6 +66,9 @@ "KvFuture", "MemHolder", "FluxonMemHolder", + "GpuBufferRegistration", + "GpuDestination", + "GpuGetStartHandle", # Backend management "KvClientType", "new_store", @@ -148,6 +151,9 @@ _LAZY_PYO3 = { "FluxonMemHolder": ("kvclient.fluxon", "FluxonMemHolder"), + "GpuBufferRegistration": ("kvclient.fluxon", "GpuBufferRegistration"), + "GpuDestination": ("kvclient.fluxon", "GpuDestination"), + "GpuGetStartHandle": ("kvclient.fluxon", "GpuGetStartHandle"), } diff --git a/fluxon_py/kvclient/fluxon.py b/fluxon_py/kvclient/fluxon.py index ef17660..1602e88 100644 --- a/fluxon_py/kvclient/fluxon.py +++ b/fluxon_py/kvclient/fluxon.py @@ -224,6 +224,78 @@ def as_dict(self) -> Dict[str, Any]: } +@dataclass(frozen=True) +class GpuBufferRegistration: + registration_id: int + ptr: int + size: int + device_id: int + + def __post_init__(self) -> None: + if type(self.registration_id) is not int or self.registration_id <= 0: + raise ValueError("registration_id must be a positive int") + if type(self.ptr) is not int or self.ptr <= 0: + raise ValueError("GPU registration ptr must be a positive int") + if type(self.size) is not int or self.size <= 0: + raise ValueError("GPU registration size must be a positive int") + if type(self.device_id) is not int or self.device_id < 0: + raise ValueError("GPU device_id must be a non-negative int") + if self.end > (1 << 64): + raise ValueError("GPU registration range overflows u64") + + @property + def end(self) -> int: + return self.ptr + self.size + + def destination(self, ptr: int, capacity: int) -> "GpuDestination": + destination = GpuDestination( + registration_id=self.registration_id, + ptr=ptr, + capacity=capacity, + ) + if destination.ptr < self.ptr or destination.end > self.end: + raise ValueError( + "GPU destination is outside its registration: " + f"registration=[{self.ptr:#x},{self.end:#x}) " + f"destination=[{destination.ptr:#x},{destination.end:#x})" + ) + return destination + + +@dataclass(frozen=True) +class GpuDestination: + registration_id: int + ptr: int + capacity: int + + def __post_init__(self) -> None: + if type(self.registration_id) is not int or self.registration_id <= 0: + raise ValueError("registration_id must be a positive int") + if type(self.ptr) is not int or self.ptr <= 0: + raise ValueError("GPU destination ptr must be a positive int") + if type(self.capacity) is not int or self.capacity <= 0: + raise ValueError("GPU destination capacity must be a positive int") + if self.end > (1 << 64): + raise ValueError("GPU destination range overflows u64") + + @property + def end(self) -> int: + return self.ptr + self.capacity + + +@dataclass +class GpuGetStartHandle: + """One-shot handle for a background RDMA pull into GPU staging.""" + + keys: Tuple[str, ...] + destinations: Tuple[GpuDestination, ...] + result: GetStartResult + created_at_ns: int + backend_token: int + backend_handle: int + closed: bool = False + + def _map_nospace_to_storagefull(err: ApiError) -> ApiError: """Normalize storage-capacity errors without depending on backend internals.""" return err @@ -461,6 +533,7 @@ def __init__(self, config: FluxonKvClientConfig): self._config = config self._init_error: Optional[ApiError] = None self._registered_buffer_descriptors: List[_RegisteredBufferDescriptor] = [] + self._gpu_buffer_registration: Optional[GpuBufferRegistration] = None cluster_name = config.fluxonkv_spec_cluster_name self._batch_concurrency = 128 if self._batch_concurrency <= 0: @@ -997,6 +1070,15 @@ def register_buffer( message=f"device_kind must be str; got {type(device_kind)}" ) ) + if device_kind.strip().lower() != "host": + return Result.new_error( + InvalidArgumentError( + message=( + "register_buffer supports host memory only; " + "use register_gpu_buffer for a CUDA staging range" + ) + ) + ) if not isinstance(device_id, str): return Result.new_error( InvalidArgumentError( @@ -1034,6 +1116,164 @@ def register_buffer( except ApiError as e: return Result.new_error(e) + def register_gpu_buffer( + self, + ptr: int, + size: int, + device_id: int, + ) -> Result[GpuBufferRegistration, ApiError]: + if self._client is None: + return Result.new_error( + GeneralError( + message="Store not initialized when register_gpu_buffer(). Call setup() first." + ) + ) + if isinstance(ptr, bool) or not isinstance(ptr, int) or ptr <= 0: + return Result.new_error( + InvalidArgumentError(message=f"GPU ptr must be a positive int; got {ptr!r}") + ) + if isinstance(size, bool) or not isinstance(size, int) or size <= 0: + return Result.new_error( + InvalidArgumentError(message=f"GPU size must be a positive int; got {size!r}") + ) + if ( + isinstance(device_id, bool) + or not isinstance(device_id, int) + or device_id < 0 + ): + return Result.new_error( + InvalidArgumentError( + message=f"GPU device_id must be a non-negative int; got {device_id!r}" + ) + ) + if ptr + size > (1 << 64): + return Result.new_error( + InvalidArgumentError( + message=f"GPU registration range overflows u64: ptr={ptr:#x} size={size}" + ) + ) + if self._gpu_buffer_registration is not None: + return Result.new_error( + InvalidArgumentError( + message=( + "one GPU buffer is already registered: " + f"registration_id={self._gpu_buffer_registration.registration_id}" + ) + ) + ) + try: + inner_res = self._client.register_gpu_buffer(ptr, size, device_id) + if not inner_res.is_ok(): + return Result.new_error(inner_res.unwrap_error()) + payload = inner_res.unwrap() + if not isinstance(payload, dict): + return Result.new_error( + GeneralError( + message=f"register_gpu_buffer returned non-dict payload: {type(payload)}" + ) + ) + registration = GpuBufferRegistration( + registration_id=int(payload["registration_id"]), + ptr=int(payload["ptr"]), + size=int(payload["len"]), + device_id=int(payload["device_id"]), + ) + if ( + registration.registration_id <= 0 + or registration.ptr != ptr + or registration.size != size + or registration.device_id != device_id + ): + return Result.new_error( + GeneralError( + message=( + "register_gpu_buffer returned a mismatched registration: " + f"{registration!r}" + ) + ) + ) + self._gpu_buffer_registration = registration + return Result.new_ok(registration) + except ApiError as e: + return Result.new_error(e) + + def validate_gpu_destination( + self, + destination: GpuDestination, + ) -> Result[OkNone, ApiError]: + if self._client is None: + return Result.new_error( + GeneralError( + message="Store not initialized when validate_gpu_destination()." + ) + ) + if not isinstance(destination, GpuDestination): + return Result.new_error( + InvalidArgumentError( + message=( + "validate_gpu_destination requires GpuDestination; " + f"got {type(destination)}" + ) + ) + ) + if destination.capacity <= 0 or destination.ptr <= 0: + return Result.new_error( + InvalidArgumentError( + message=f"invalid GPU destination: {destination!r}" + ) + ) + try: + inner_res = self._client.validate_gpu_destination( + destination.registration_id, + destination.ptr, + destination.capacity, + ) + if not inner_res.is_ok(): + return Result.new_error(inner_res.unwrap_error()) + _ = inner_res.unwrap() + return Result.new_ok(OkNone()) + except ApiError as e: + return Result.new_error(e) + + def unregister_gpu_buffer( + self, + registration: GpuBufferRegistration, + ) -> Result[OkNone, ApiError]: + if self._client is None: + return Result.new_error( + GeneralError( + message="Store not initialized when unregister_gpu_buffer()." + ) + ) + if not isinstance(registration, GpuBufferRegistration): + return Result.new_error( + InvalidArgumentError( + message=( + "unregister_gpu_buffer requires GpuBufferRegistration; " + f"got {type(registration)}" + ) + ) + ) + active = self._gpu_buffer_registration + if active != registration: + return Result.new_error( + InvalidArgumentError( + message=( + "GPU registration is not active on this store: " + f"requested={registration!r} active={active!r}" + ) + ) + ) + try: + inner_res = self._client.unregister_gpu_buffer(registration.registration_id) + if not inner_res.is_ok(): + return Result.new_error(inner_res.unwrap_error()) + _ = inner_res.unwrap() + self._gpu_buffer_registration = None + return Result.new_ok(OkNone()) + except ApiError as e: + return Result.new_error(e) + def batch_put_from( self, keys: List[str], @@ -1443,6 +1683,13 @@ def instance_key(self) -> Result[str, ApiError]: def close(self) -> Result[OkNone, ApiError]: """Close and tear down the store.""" try: + if self._gpu_buffer_registration is not None: + unregister_result = self.unregister_gpu_buffer( + self._gpu_buffer_registration + ) + if not unregister_result.is_ok(): + return Result.new_error(unregister_result.unwrap_error()) + _ = unregister_result.unwrap() # Backend returns a Result; MUST be explicitly consumed to avoid # leaking an unconsumed Result that triggers __del__ assertion. res = self._client.close() @@ -1782,6 +2029,205 @@ def get_transfer( raise RuntimeError(f"get_transfer returned invalid plan_ptr: {plan_ptr!r}") return int(plan_ptr) + def get_start_gpu( + self, + keys: List[str], + destinations: List[GpuDestination], + prefix_best_effort: bool = True, + atomic_group_lens: Optional[List[int]] = None, + ) -> GpuGetStartHandle: + """Start background remote reads directly into caller-owned GPU staging.""" + if self._client is None: + raise RuntimeError( + "Store not initialized when get_start_gpu(). Call setup() first." + ) + if len(keys) == 0: + raise ValueError("get_start_gpu requires at least one key") + if len(keys) != len(destinations): + raise ValueError( + "get_start_gpu requires one destination per key: " + f"keys={len(keys)} destinations={len(destinations)}" + ) + active_registration = self._gpu_buffer_registration + if active_registration is None: + raise RuntimeError("get_start_gpu requires an active GPU registration") + for index, destination in enumerate(destinations): + if not isinstance(destination, GpuDestination): + raise TypeError( + "get_start_gpu destinations must be GpuDestination: " + f"index={index} got={type(destination)}" + ) + if destination.registration_id != active_registration.registration_id: + raise ValueError( + "get_start_gpu destination uses a stale registration: " + f"index={index} destination_id={destination.registration_id} " + f"active_id={active_registration.registration_id}" + ) + if ( + destination.ptr < active_registration.ptr + or destination.end > active_registration.end + ): + raise ValueError( + "get_start_gpu destination is outside the active registration: " + f"index={index} destination={destination!r} " + f"registration={active_registration!r}" + ) + + normalized_group_lens: Optional[List[int]] = None + if atomic_group_lens is not None: + normalized_group_lens = [int(length) for length in atomic_group_lens] + if any(length <= 0 for length in normalized_group_lens): + raise ValueError("get_start_gpu atomic_group_lens entries must be > 0") + if sum(normalized_group_lens) != len(keys): + raise ValueError( + "get_start_gpu atomic_group_lens must sum to keys length: " + f"sum={sum(normalized_group_lens)} keys={len(keys)}" + ) + + started_at_ns = time.monotonic_ns() + inner_res = self._client.get_start_gpu( + list(keys), + [ + ( + destination.registration_id, + destination.ptr, + destination.capacity, + ) + for destination in destinations + ], + bool(prefix_best_effort), + normalized_group_lens, + self._batch_concurrency, + ) + if not inner_res.is_ok(): + raise RuntimeError(f"get_start_gpu backend error: {inner_res.unwrap_error()}") + payload = inner_res.unwrap() + if not isinstance(payload, dict): + raise RuntimeError( + f"get_start_gpu returned non-dict payload: {type(payload)}" + ) + backend_handle = int(payload["handle"]) + try: + result = _build_get_start_result_from_backend_payload( + payload, + list(keys), + bool(prefix_best_effort), + normalized_group_lens, + ) + except Exception: + cancel_res = self._client.cancel_get_transfer_gpu(backend_handle) + if not cancel_res.is_ok(): + logging.exception( + "get_start_gpu payload validation failed and cleanup also failed: %s", + cancel_res.unwrap_error(), + ) + raise + return GpuGetStartHandle( + keys=tuple(keys), + destinations=tuple(destinations), + result=result, + created_at_ns=started_at_ns, + backend_token=id(self), + backend_handle=backend_handle, + ) + + def cancel_get_transfer_gpu(self, handle: GpuGetStartHandle) -> None: + if not isinstance(handle, GpuGetStartHandle): + raise TypeError( + f"cancel_get_transfer_gpu requires GpuGetStartHandle, got {type(handle)}" + ) + if handle.backend_token != id(self): + raise RuntimeError( + "cancel_get_transfer_gpu handle belongs to a different FluxonKVCacheStore" + ) + if handle.closed: + return + if self._client is None: + raise RuntimeError( + "Store not initialized when cancel_get_transfer_gpu(). Call setup() first." + ) + inner_res = self._client.cancel_get_transfer_gpu(handle.backend_handle) + handle.closed = True + if not inner_res.is_ok(): + raise RuntimeError( + f"cancel_get_transfer_gpu backend error: {inner_res.unwrap_error()}" + ) + + def get_transfer_gpu( + self, + handle: GpuGetStartHandle, + *, + consume_prefix_len: Optional[int] = None, + ) -> None: + """Wait for the GPU transfer terminal; destinations already contain the bytes.""" + if not isinstance(handle, GpuGetStartHandle): + raise TypeError( + f"get_transfer_gpu requires GpuGetStartHandle, got {type(handle)}" + ) + if handle.backend_token != id(self): + raise RuntimeError( + "get_transfer_gpu handle belongs to a different FluxonKVCacheStore" + ) + if handle.closed: + raise RuntimeError("get_transfer_gpu handle has been closed") + result = handle.result + normalized_consume_prefix_len = ( + result.transferable_len + if consume_prefix_len is None + else consume_prefix_len + ) + if ( + isinstance(normalized_consume_prefix_len, bool) + or not isinstance(normalized_consume_prefix_len, int) + or normalized_consume_prefix_len <= 0 + or normalized_consume_prefix_len > result.transferable_len + ): + raise ValueError( + "get_transfer_gpu consume_prefix_len must be within the live prefix: " + f"consume={normalized_consume_prefix_len!r} " + f"transferable={result.transferable_len}" + ) + group_lens = result.atomic_group_lens or (len(result.keys),) + group_end = 0 + for group_len in group_lens: + group_end += int(group_len) + if group_end >= normalized_consume_prefix_len: + break + if group_end != normalized_consume_prefix_len: + raise ValueError( + "get_transfer_gpu consume_prefix_len must end at an atomic-group boundary: " + f"consume={normalized_consume_prefix_len} groups={group_lens}" + ) + if self._client is None: + raise RuntimeError( + "Store not initialized when get_transfer_gpu(). Call setup() first." + ) + inner_res = self._client.get_transfer_gpu( + handle.backend_handle, + normalized_consume_prefix_len, + ) + handle.closed = True + if not inner_res.is_ok(): + raise RuntimeError( + f"get_transfer_gpu backend error: {inner_res.unwrap_error()}" + ) + payload = inner_res.unwrap() + if not isinstance(payload, dict): + raise RuntimeError( + f"get_transfer_gpu returned non-dict payload: {type(payload)}" + ) + transferred_prefix_len = int(payload["transferred_prefix_len"]) + consumed_prefix_len = int(payload["consumed_prefix_len"]) + if ( + transferred_prefix_len != result.transferable_len + or consumed_prefix_len != normalized_consume_prefix_len + ): + raise RuntimeError( + "get_transfer_gpu returned inconsistent terminal lengths: " + f"transferred={transferred_prefix_len}/{result.transferable_len} " + f"consumed={consumed_prefix_len}/{normalized_consume_prefix_len}" + ) + def get_etcd_config(self) -> List[str]: if self._client is None: raise RuntimeError("Store not initialized") diff --git a/fluxon_rs/fluxon_commu/src/facade/transfer_engine.rs b/fluxon_rs/fluxon_commu/src/facade/transfer_engine.rs index e5353a5..f701659 100644 --- a/fluxon_rs/fluxon_commu/src/facade/transfer_engine.rs +++ b/fluxon_rs/fluxon_commu/src/facade/transfer_engine.rs @@ -7,6 +7,9 @@ use std::collections::HashMap; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use crate::NodeIDString; +pub use fluxon_commu_contract::{ + CLOSED_RUNTIME_DIRECT_FAST_PATH_NOT_READY_MARKER, ClosedRuntimeLocalMemoryKind, +}; use fluxon_commu_contract::{ ClosedRuntimeHandle, ClosedRuntimePeerGen, ClosedRuntimeTransferEngineOpenRuntimeRequest, ClosedRuntimeTransferEngineOpenRuntimeResponse, @@ -377,6 +380,25 @@ impl ClientTransferEngineCore { runtime: R, cpu_mem: &CpuAllocatedMem, ) -> TransferEngineResult<()> + where + R: ClientTransferEngineRuntime, + { + self.register_local_memory( + runtime, + cpu_mem.allocated_addr, + cpu_mem.allocated_size, + ClosedRuntimeLocalMemoryKind::Host, + ) + .await + } + + pub async fn register_local_memory( + &self, + runtime: R, + allocated_addr: u64, + allocated_size: u64, + memory_kind: ClosedRuntimeLocalMemoryKind, + ) -> TransferEngineResult<()> where R: ClientTransferEngineRuntime, { @@ -384,8 +406,9 @@ impl ClientTransferEngineCore { let handle = self.ensure_closed_runtime_handle(&runtime).await?; transfer_engine_register_local_segment( handle, - cpu_mem.allocated_addr, - cpu_mem.allocated_size, + allocated_addr, + allocated_size, + memory_kind, ) .await .map_err(transfer_engine_closed_sdk_error) @@ -395,13 +418,28 @@ impl ClientTransferEngineCore { pub async fn unregister_local_segment( &self, cpu_mem: &CpuAllocatedMem, + ) -> TransferEngineResult<()> { + self.unregister_local_memory( + cpu_mem.allocated_addr, + cpu_mem.allocated_size, + ClosedRuntimeLocalMemoryKind::Host, + ) + .await + } + + pub async fn unregister_local_memory( + &self, + allocated_addr: u64, + allocated_size: u64, + memory_kind: ClosedRuntimeLocalMemoryKind, ) -> TransferEngineResult<()> { { if let Some(handle) = self.closed.handle.get().copied() { transfer_engine_unregister_local_segment( handle, - cpu_mem.allocated_addr, - cpu_mem.allocated_size, + allocated_addr, + allocated_size, + memory_kind, ) .await .map_err(transfer_engine_closed_sdk_error) @@ -458,6 +496,7 @@ impl ClientTransferEngineCore { target_addr, len, seg_guard, + false, ) .await } @@ -472,6 +511,7 @@ impl ClientTransferEngineCore { target_addr: u64, len: u64, seg_guard: Option, + require_fast_path: bool, ) -> TransferEngineResult where R: ClientTransferEngineRuntime, @@ -506,6 +546,7 @@ impl ClientTransferEngineCore { target_addr, len, initial_local_segment_guard_handle, + require_fast_path, ) .await .map_err(transfer_engine_closed_sdk_error); diff --git a/fluxon_rs/fluxon_commu_closed_sdk_consumer/src/lib.rs b/fluxon_rs/fluxon_commu_closed_sdk_consumer/src/lib.rs index caad34b..7395347 100644 --- a/fluxon_rs/fluxon_commu_closed_sdk_consumer/src/lib.rs +++ b/fluxon_rs/fluxon_commu_closed_sdk_consumer/src/lib.rs @@ -13,7 +13,7 @@ use fluxon_commu_contract::{ ClosedRuntimeClusterRdmaResolvedConfigStreamItem, ClosedRuntimeDesiredTransferPeer, ClosedRuntimeDispatchRequestView, ClosedRuntimeDispatchResponse, ClosedRuntimeDispatchTransportPolicy, ClosedRuntimeError, ClosedRuntimeHandle, - ClosedRuntimeHostCallbackHandle, ClosedRuntimeP2pCall, + ClosedRuntimeHostCallbackHandle, ClosedRuntimeLocalMemoryKind, ClosedRuntimeP2pCall, ClosedRuntimeP2pCallRawObservedRequestView, ClosedRuntimeP2pResponse, ClosedRuntimeP2pSendResponseRawRequestView, ClosedRuntimePeerGen, ClosedRuntimeRawSlice, ClosedRuntimeRequest, ClosedRuntimeResponse, ClosedRuntimeTransferEngineCall, @@ -26,8 +26,8 @@ use fluxon_commu_contract::{ pub mod rdma_probe; -pub const FLUXON_COMMU_CLOSED_SDK_SCHEMA_VERSION: u32 = 5; -pub const FLUXON_COMMU_CLOSED_ABI_VERSION: u32 = 8; +pub const FLUXON_COMMU_CLOSED_SDK_SCHEMA_VERSION: u32 = 6; +pub const FLUXON_COMMU_CLOSED_ABI_VERSION: u32 = 9; pub const FLUXON_COMMU_CLOSED_HOST_CALLBACKS_ABI_VERSION: u32 = 8; pub const FLUXON_COMMU_CLOSED_RUNTIME_RESULT_OK: i32 = 0; pub const FLUXON_COMMU_CLOSED_RUNTIME_RESULT_ERR: i32 = 1; @@ -1866,12 +1866,14 @@ pub async fn transfer_engine_register_local_segment( handle: ClosedRuntimeHandle, allocated_addr: u64, allocated_size: u64, + memory_kind: ClosedRuntimeLocalMemoryKind, ) -> Result<(), ClosedSdkConsumerError> { match transfer_engine_call( handle, ClosedRuntimeTransferEngineCall::RegisterLocalSegment { allocated_addr, allocated_size, + memory_kind, }, ) .await? @@ -1887,12 +1889,14 @@ pub async fn transfer_engine_unregister_local_segment( handle: ClosedRuntimeHandle, allocated_addr: u64, allocated_size: u64, + memory_kind: ClosedRuntimeLocalMemoryKind, ) -> Result<(), ClosedSdkConsumerError> { match transfer_engine_call( handle, ClosedRuntimeTransferEngineCall::UnregisterLocalSegment { allocated_addr, allocated_size, + memory_kind, }, ) .await? @@ -1912,6 +1916,7 @@ pub async fn transfer_engine_transfer_data_no_copy( target_addr: u64, len: u64, initial_local_segment_guard_handle: Option, + require_fast_path: bool, ) -> Result { match transfer_engine_call( handle, @@ -1922,6 +1927,7 @@ pub async fn transfer_engine_transfer_data_no_copy( target_addr, len, initial_local_segment_guard_handle, + require_fast_path, }, ) .await? diff --git a/fluxon_rs/fluxon_commu_contract/src/closed_runtime.rs b/fluxon_rs/fluxon_commu_contract/src/closed_runtime.rs index 80872e2..17241cf 100644 --- a/fluxon_rs/fluxon_commu_contract/src/closed_runtime.rs +++ b/fluxon_rs/fluxon_commu_contract/src/closed_runtime.rs @@ -744,6 +744,15 @@ pub struct ClosedRuntimeDesiredTransferPeer { pub enable_transfer_segment: bool, } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)] +pub enum ClosedRuntimeLocalMemoryKind { + Host, + Gpu { device_id: u32 }, +} + +pub const CLOSED_RUNTIME_DIRECT_FAST_PATH_NOT_READY_MARKER: &str = + "fluxon_direct_fast_path_not_ready"; + #[derive(Debug, Clone, Encode, Decode)] pub enum ClosedRuntimeTransferEngineCall { Init2ForInitDag { @@ -764,10 +773,12 @@ pub enum ClosedRuntimeTransferEngineCall { RegisterLocalSegment { allocated_addr: u64, allocated_size: u64, + memory_kind: ClosedRuntimeLocalMemoryKind, }, UnregisterLocalSegment { allocated_addr: u64, allocated_size: u64, + memory_kind: ClosedRuntimeLocalMemoryKind, }, TransferDataNoCopy { peer_node: Option, @@ -776,6 +787,7 @@ pub enum ClosedRuntimeTransferEngineCall { target_addr: u64, len: u64, initial_local_segment_guard_handle: Option, + require_fast_path: bool, }, TrySendWireDirect { peer_gen: ClosedRuntimePeerGen, diff --git a/fluxon_rs/fluxon_kv/framework_init_steps.yaml b/fluxon_rs/fluxon_kv/framework_init_steps.yaml index 923ae30..24ca312 100644 --- a/fluxon_rs/fluxon_kv/framework_init_steps.yaml +++ b/fluxon_rs/fluxon_kv/framework_init_steps.yaml @@ -62,8 +62,8 @@ module_tags: MasterKvRouter: [master] MetricReporter: [master, owner, external] ClientKvApi: [owner] - ClientSegPool: [owner] - ClientTransferEngine: [master, owner] + ClientSegPool: [owner, external] + ClientTransferEngine: [master, owner, external] ExternalClientApi: [external] MasterLeaseManager: [master] diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs index ddc5803..9e1c6a9 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs @@ -1424,6 +1424,7 @@ impl ClientKvApiInner { serialize_part: GetStartReq { key: key.to_string(), prepared_target: None, + external_sink_target: None, }, raw_bytes: Vec::new(), }; @@ -1464,6 +1465,7 @@ impl ClientKvApiInner { serialize_part: BatchGetStartReq { keys, prepared_targets, + external_sink_targets: Vec::new(), }, raw_bytes: Vec::new(), }; diff --git a/fluxon_rs/fluxon_kv/src/client_seg_pool/mod.rs b/fluxon_rs/fluxon_kv/src/client_seg_pool/mod.rs index 8c7cc78..8dd61aa 100644 --- a/fluxon_rs/fluxon_kv/src/client_seg_pool/mod.rs +++ b/fluxon_rs/fluxon_kv/src/client_seg_pool/mod.rs @@ -1,7 +1,7 @@ use crate::ClientKvApiAccessTrait; use crate::client_kv_api::ClientKvApi; use crate::client_transfer_engine::{ClientTransferEngine, ClientTransferEngineAccessTrait}; -use crate::cluster_manager::ClusterManagerAccessTrait; +use crate::cluster_manager::{ClusterManagerAccessTrait, NodeRole}; use crate::config::ContributeToClusterPoolSize; use crate::master_seg_manager::msg_pack::SegmentDeviceMemInfo; use crate::p2p::p2p_module::P2pModule; @@ -968,15 +968,24 @@ impl LogicalModule for ClientSegPool { async fn shutdown(&self) -> Result<(), Self::Error> { let _ = self.remove_side_transfer_peer().await; - loop { - if self.inner().view().client_kv_api().can_be_dropped() { - tracing::info!("ClientSegPool can be dropped"); - break; + if !matches!( + self.inner() + .view() + .cluster_manager() + .get_self_info() + .node_role(), + NodeRole::External + ) { + loop { + if self.inner().view().client_kv_api().can_be_dropped() { + tracing::info!("ClientSegPool can be dropped"); + break; + } + tracing::info!( + "ClientSegPool waiting ClientKvApi can not be dropped , will try again after 3s (some user memholder may still be in use)" + ); + tokio::time::sleep(Duration::from_secs(3)).await; } - tracing::info!( - "ClientSegPool waiting ClientKvApi can not be dropped , will try again after 3s (some user memholder may still be in use)" - ); - tokio::time::sleep(Duration::from_secs(3)).await; } if self.0.cpu_allocated_mem.read().await.is_some() { @@ -989,6 +998,15 @@ impl LogicalModule for ClientSegPool { impl ClientSegPool { pub async fn init2_for_init_dag(&self) -> KvResult<()> { let inner = &self.0; + if matches!( + inner.view().cluster_manager().get_self_info().node_role(), + NodeRole::External + ) { + // External clients contribute no cache segment. They construct this + // module only to provide lifetime guards for an explicitly + // registered GPU staging range. + return Ok(()); + } // English note: // - Invariant: register inbound RPC handlers before any awaited etcd operations that diff --git a/fluxon_rs/fluxon_kv/src/client_transfer_engine/mod.rs b/fluxon_rs/fluxon_kv/src/client_transfer_engine/mod.rs index 75f82f5..829b57e 100644 --- a/fluxon_rs/fluxon_kv/src/client_transfer_engine/mod.rs +++ b/fluxon_rs/fluxon_kv/src/client_transfer_engine/mod.rs @@ -21,7 +21,10 @@ use crate::{P2pModuleAccessTrait, cluster_manager::ClusterManagerAccessTrait}; use async_trait::async_trait; use fluxon_commu::ClosedRuntimeHandle; use fluxon_commu::p2p::PeerGen; -use fluxon_commu::transfer_engine::AttachedTransferEngine; +use fluxon_commu::transfer_engine::{ + AttachedTransferEngine, CLOSED_RUNTIME_DIRECT_FAST_PATH_NOT_READY_MARKER, + ClosedRuntimeLocalMemoryKind, +}; use fluxon_commu::{ ClientTransferEngineClusterRuntime, ClientTransferEngineCore, ClientTransferEngineRuntime, CpuAllocatedMem, TransferBreakdown, @@ -29,7 +32,9 @@ use fluxon_commu::{ use fluxon_framework::{LogicalModule, define_module}; use std::future::Future; use std::pin::Pin; -use std::sync::OnceLock; +use std::sync::atomic::{AtomicU64, Ordering}; +use std::sync::{Arc, Mutex, OnceLock}; +use std::time::{Duration, Instant}; pub use fluxon_commu::{ClientTransferEngineNewArg, ClientTransferEngineRuntimeConfig}; @@ -43,15 +48,228 @@ define_module!( (client_seg_pool, ClientSegPool) ); +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct GpuMemoryRegistration { + pub registration_id: u64, + pub addr: u64, + pub len: u64, + pub device_id: u32, +} + +impl GpuMemoryRegistration { + fn contains(&self, addr: u64, len: u64) -> bool { + if len == 0 { + return addr >= self.addr + && self + .addr + .checked_add(self.len) + .is_some_and(|end| addr <= end); + } + let Some(end) = addr.checked_add(len) else { + return false; + }; + let Some(registration_end) = self.addr.checked_add(self.len) else { + return false; + }; + addr >= self.addr && end <= registration_end + } +} + +#[derive(Clone, Debug)] +pub struct GpuMemoryGuard { + registration: Arc, +} + +impl GpuMemoryGuard { + pub fn registration(&self) -> &GpuMemoryRegistration { + self.registration.as_ref() + } + + fn contains(&self, addr: u64, len: u64) -> bool { + self.registration.contains(addr, len) + } +} + +pub enum ClientTransferMemoryGuard { + Cpu(ClientCpuMemReadGuard), + Gpu(GpuMemoryGuard), +} + +#[derive(Debug)] +enum GpuMemoryRegistryState { + Empty, + Registering(GpuMemoryRegistration), + Active(Arc), + Unregistering(GpuMemoryRegistration), +} + +#[derive(Debug)] +struct GpuMemoryRegistry { + next_registration_id: AtomicU64, + state: Mutex, +} + +impl GpuMemoryRegistry { + fn new() -> Self { + Self { + next_registration_id: AtomicU64::new(1), + state: Mutex::new(GpuMemoryRegistryState::Empty), + } + } + + fn begin_register( + &self, + addr: u64, + len: u64, + device_id: u32, + ) -> Result { + if addr == 0 { + return Err("GPU registration address must be non-zero".to_string()); + } + if len == 0 { + return Err("GPU registration length must be non-zero".to_string()); + } + if addr.checked_add(len).is_none() { + return Err(format!( + "GPU registration range overflows: addr={:#x} len={}", + addr, len + )); + } + let registration_id = self.next_registration_id.fetch_add(1, Ordering::Relaxed); + let registration = GpuMemoryRegistration { + registration_id, + addr, + len, + device_id, + }; + let mut state = self.state.lock().expect("gpu memory registry poisoned"); + match &*state { + GpuMemoryRegistryState::Empty => { + *state = GpuMemoryRegistryState::Registering(registration.clone()); + Ok(registration) + } + current => Err(format!( + "one GPU registration is already active or changing: {current:?}" + )), + } + } + + fn finish_register(&self, registration_id: u64, success: bool) { + let mut state = self.state.lock().expect("gpu memory registry poisoned"); + let previous = std::mem::replace(&mut *state, GpuMemoryRegistryState::Empty); + match previous { + GpuMemoryRegistryState::Registering(registration) + if registration.registration_id == registration_id => + { + if success { + *state = GpuMemoryRegistryState::Active(Arc::new(registration)); + } + } + other => panic!( + "GPU registration completion does not match registry state: id={} state={other:?}", + registration_id + ), + } + } + + fn begin_unregister(&self, registration_id: u64) -> Result { + let mut state = self.state.lock().expect("gpu memory registry poisoned"); + let previous = std::mem::replace(&mut *state, GpuMemoryRegistryState::Empty); + match previous { + GpuMemoryRegistryState::Active(registration) => { + if registration.registration_id != registration_id { + let actual = registration.registration_id; + *state = GpuMemoryRegistryState::Active(registration); + return Err(format!( + "GPU registration id mismatch: expected={} got={}", + actual, registration_id + )); + } + let guard_count = Arc::strong_count(®istration).saturating_sub(1); + if guard_count != 0 { + *state = GpuMemoryRegistryState::Active(registration); + return Err(format!( + "GPU registration is busy: registration_id={} active_guards={}", + registration_id, guard_count + )); + } + let descriptor = registration.as_ref().clone(); + *state = GpuMemoryRegistryState::Unregistering(descriptor.clone()); + Ok(descriptor) + } + other => { + *state = other; + Err(format!( + "GPU registration is not active: registration_id={}", + registration_id + )) + } + } + } + + fn finish_unregister(&self, registration_id: u64, success: bool) { + let mut state = self.state.lock().expect("gpu memory registry poisoned"); + let previous = std::mem::replace(&mut *state, GpuMemoryRegistryState::Empty); + match previous { + GpuMemoryRegistryState::Unregistering(registration) + if registration.registration_id == registration_id => + { + if !success { + *state = GpuMemoryRegistryState::Active(Arc::new(registration)); + } + } + other => panic!( + "GPU unregistration completion does not match registry state: id={} state={other:?}", + registration_id + ), + } + } + + fn guard_for_range(&self, addr: u64, len: u64) -> Option { + let state = self.state.lock().expect("gpu memory registry poisoned"); + match &*state { + GpuMemoryRegistryState::Active(registration) if registration.contains(addr, len) => { + Some(GpuMemoryGuard { + registration: registration.clone(), + }) + } + _ => None, + } + } + + fn validate_destination( + &self, + registration_id: u64, + addr: u64, + capacity: u64, + ) -> Result { + let guard = self.guard_for_range(addr, capacity).ok_or_else(|| { + format!( + "GPU destination is outside the active registration: registration_id={} addr={:#x} capacity={}", + registration_id, addr, capacity + ) + })?; + if guard.registration().registration_id != registration_id { + return Err(format!( + "GPU destination registration id mismatch: expected={} got={}", + guard.registration().registration_id, + registration_id + )); + } + Ok(guard) + } +} + #[derive(Clone)] struct ClientTransferRuntimeAdapter { view: ClientTransferEngineView, + gpu_memory_registry: Arc, } impl ClientTransferRuntimeAdapter { fn local_segment_transfer_enabled(&self) -> bool { let self_info = self.view.cluster_manager().get_self_info(); - matches!(self_info.node_role(), NodeRole::Client) + matches!(self_info.node_role(), NodeRole::Client | NodeRole::External) || self_info .metadata .get("side_transfer_worker") @@ -156,7 +374,7 @@ impl ClientTransferEngineClusterRuntime for ClientTransferRuntimeAdapter { #[async_trait] impl ClientTransferEngineRuntime for ClientTransferRuntimeAdapter { - type LocalSegmentGuard = ClientCpuMemReadGuard; + type LocalSegmentGuard = ClientTransferMemoryGuard; fn supports_local_segment_transfer(&self) -> bool { self.local_segment_transfer_enabled() @@ -181,12 +399,40 @@ impl ClientTransferEngineRuntime for ClientTransferRuntimeAdapter { async fn ensure_local_segment_guard( &self, local_addr: u64, - seg_guard: Option, - ) -> Result { + seg_guard: Option, + ) -> Result { if !self.local_segment_transfer_enabled() { return Err("local segment transfer is not supported on this node role".to_string()); } - p2p_transfer_rpc::ensure_local_segment_guard(&self.view, local_addr, seg_guard).await + if let Some(guard) = seg_guard { + return match guard { + ClientTransferMemoryGuard::Cpu(cpu_guard) => { + p2p_transfer_rpc::ensure_local_segment_guard( + &self.view, + local_addr, + Some(cpu_guard), + ) + .await + .map(ClientTransferMemoryGuard::Cpu) + } + ClientTransferMemoryGuard::Gpu(gpu_guard) => { + if gpu_guard.contains(local_addr, 1) { + Ok(ClientTransferMemoryGuard::Gpu(gpu_guard)) + } else { + Err(format!( + "GPU guard does not cover local address: addr={:#x}", + local_addr + )) + } + } + }; + } + if let Some(gpu_guard) = self.gpu_memory_registry.guard_for_range(local_addr, 1) { + return Ok(ClientTransferMemoryGuard::Gpu(gpu_guard)); + } + p2p_transfer_rpc::ensure_local_segment_guard(&self.view, local_addr, None) + .await + .map(ClientTransferMemoryGuard::Cpu) } fn register_p2p_transfer_rpc(&self) { @@ -231,20 +477,27 @@ impl ClientTransferEngineRuntime for ClientTransferRuntimeAdapter { remote_src: u64, local_target: u64, len: u64, - seg_guard: ClientCpuMemReadGuard, + seg_guard: ClientTransferMemoryGuard, ) -> Result<(), String> { if !self.local_segment_transfer_enabled() { return Err("p2p raw-memory read is not supported on this node role".to_string()); } - p2p_transfer_rpc::p2p_read_to_local( - &self.view, - peer, - remote_src, - local_target, - len, - seg_guard, - ) - .await + match seg_guard { + ClientTransferMemoryGuard::Cpu(cpu_guard) => { + p2p_transfer_rpc::p2p_read_to_local( + &self.view, + peer, + remote_src, + local_target, + len, + cpu_guard, + ) + .await + } + ClientTransferMemoryGuard::Gpu(_) => Err( + "GPU destination requires the RDMA fast path; P2P fallback is disabled".to_string(), + ), + } } async fn p2p_write_from_local( @@ -254,21 +507,28 @@ impl ClientTransferEngineRuntime for ClientTransferRuntimeAdapter { remote_target: u64, len: u64, copy_from: Option>, - seg_guard: ClientCpuMemReadGuard, + seg_guard: ClientTransferMemoryGuard, ) -> Result<(), String> { if !self.local_segment_transfer_enabled() { return Err("p2p raw-memory write is not supported on this node role".to_string()); } - p2p_transfer_rpc::p2p_write_from_local( - &self.view, - peer, - local_src, - remote_target, - len, - copy_from, - seg_guard, - ) - .await + match seg_guard { + ClientTransferMemoryGuard::Cpu(cpu_guard) => { + p2p_transfer_rpc::p2p_write_from_local( + &self.view, + peer, + local_src, + remote_target, + len, + copy_from, + cpu_guard, + ) + .await + } + ClientTransferMemoryGuard::Gpu(_) => { + Err("GPU source requires the RDMA fast path; P2P fallback is disabled".to_string()) + } + } } fn try_record_local_ipc_bytes_for_owner_topology( @@ -308,12 +568,14 @@ impl ClientTransferEngineRuntime for ClientTransferRuntimeAdapter { pub struct ClientTransferEngine { view: OnceLock, core: ClientTransferEngineCore, + gpu_memory_registry: Arc, } impl ClientTransferEngine { fn runtime(&self) -> ClientTransferRuntimeAdapter { ClientTransferRuntimeAdapter { view: self.view.get().unwrap().clone(), + gpu_memory_registry: self.gpu_memory_registry.clone(), } } @@ -333,6 +595,7 @@ impl ClientTransferEngine { Ok(Self { view: OnceLock::new(), core, + gpu_memory_registry: Arc::new(GpuMemoryRegistry::new()), }) } @@ -369,6 +632,81 @@ impl ClientTransferEngine { .map_err(KvError::from) } + pub async fn register_gpu_memory( + &self, + addr: u64, + len: u64, + device_id: u32, + ) -> KvResult { + let registration = self + .gpu_memory_registry + .begin_register(addr, len, device_id) + .map_err(|detail| { + KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::InvalidArgument { + detail, + }, + ) + })?; + let result = self + .core + .register_local_memory( + self.runtime(), + addr, + len, + ClosedRuntimeLocalMemoryKind::Gpu { device_id }, + ) + .await + .map_err(KvError::from); + self.gpu_memory_registry + .finish_register(registration.registration_id, result.is_ok()); + result.map(|()| registration) + } + + pub async fn unregister_gpu_memory(&self, registration_id: u64) -> KvResult<()> { + let registration = self + .gpu_memory_registry + .begin_unregister(registration_id) + .map_err(|detail| { + KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::InvalidArgument { + detail, + }, + ) + })?; + let result = self + .core + .unregister_local_memory( + registration.addr, + registration.len, + ClosedRuntimeLocalMemoryKind::Gpu { + device_id: registration.device_id, + }, + ) + .await + .map_err(KvError::from); + self.gpu_memory_registry + .finish_unregister(registration_id, result.is_ok()); + result + } + + pub fn validate_gpu_destination( + &self, + registration_id: u64, + addr: u64, + capacity: u64, + ) -> KvResult { + self.gpu_memory_registry + .validate_destination(registration_id, addr, capacity) + .map_err(|detail| { + KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::InvalidArgument { + detail, + }, + ) + }) + } + pub async fn write_data( &self, data: Pin<&[u8]>, @@ -386,7 +724,7 @@ impl ClientTransferEngine { target_addr, peer_id, do_copy, - seg_guard, + seg_guard.map(ClientTransferMemoryGuard::Cpu), ) .await .map_err(KvError::from) @@ -409,11 +747,87 @@ impl ClientTransferEngine { src_addr, target_addr, len, - seg_guard, + seg_guard.map(ClientTransferMemoryGuard::Cpu), + false, ) .await .map_err(KvError::from) } + + /// Pull remote bytes into an explicitly validated caller-owned GPU range. + /// + /// Keeping this separate from the CPU entry point prevents a CUDA virtual + /// address from silently falling through CPU/P2P guard discovery. The + /// guard is moved into the transfer engine and retains the exact + /// registration generation until the backend releases the local segment + /// lease. + pub async fn transfer_data_no_copy_to_gpu( + &self, + peer_node: NodeIDString, + src_addr: u64, + target_addr: u64, + len: u64, + gpu_guard: GpuMemoryGuard, + ) -> KvResult { + if len == 0 { + return Err(KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::InvalidArgument { + detail: "GPU transfer length must be non-zero".to_string(), + }, + )); + } + if !gpu_guard.contains(target_addr, len) { + return Err(KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::InvalidArgument { + detail: format!( + "GPU transfer exceeds destination guard: target={:#x} len={} registration_id={}", + target_addr, + len, + gpu_guard.registration().registration_id + ), + }, + )); + } + const DIRECT_READY_TIMEOUT: Duration = Duration::from_secs(5); + const DIRECT_RETRY_DELAY: Duration = Duration::from_millis(10); + + let started = Instant::now(); + let mut attempt = 0_u32; + loop { + attempt = attempt.saturating_add(1); + let result = self + .core + .transfer_data_no_copy( + self.runtime(), + Some(peer_node.clone()), + true, + src_addr, + target_addr, + len, + Some(ClientTransferMemoryGuard::Gpu(gpu_guard.clone())), + true, + ) + .await; + match result { + Ok(breakdown) => return Ok(breakdown), + Err(err) + if err + .to_string() + .contains(CLOSED_RUNTIME_DIRECT_FAST_PATH_NOT_READY_MARKER) + && started.elapsed() < DIRECT_READY_TIMEOUT => + { + tracing::debug!( + peer = %peer_node, + attempt, + elapsed_ms = started.elapsed().as_millis(), + "GPU direct transfer is waiting for the RDMA peer fast path" + ); + limit_thirdparty::tokio::time::sleep(DIRECT_RETRY_DELAY).await; + } + Err(err) => return Err(KvError::from(err)), + } + } + } } #[async_trait] @@ -435,3 +849,101 @@ impl LogicalModule for ClientTransferEngine { Ok(()) } } + +#[cfg(test)] +mod gpu_memory_registry_tests { + use super::GpuMemoryRegistry; + + fn active_registry() -> (GpuMemoryRegistry, u64) { + let registry = GpuMemoryRegistry::new(); + let registration = registry + .begin_register(0x1000, 0x1000, 2) + .expect("registration must start"); + let registration_id = registration.registration_id; + registry.finish_register(registration_id, true); + (registry, registration_id) + } + + #[test] + fn validates_exact_registration_generation_and_range() { + let (registry, registration_id) = active_registry(); + + let guard = registry + .validate_destination(registration_id, 0x1400, 0x400) + .expect("subrange must validate"); + assert_eq!(guard.registration().registration_id, registration_id); + assert_eq!(guard.registration().device_id, 2); + + assert!( + registry + .validate_destination(registration_id + 1, 0x1400, 0x400) + .unwrap_err() + .contains("registration id mismatch") + ); + assert!( + registry + .validate_destination(registration_id, 0x1f00, 0x200) + .unwrap_err() + .contains("outside the active registration") + ); + } + + #[test] + fn rejects_invalid_registration_geometry() { + let registry = GpuMemoryRegistry::new(); + assert!(registry.begin_register(0, 1, 0).is_err()); + assert!(registry.begin_register(1, 0, 0).is_err()); + assert!(registry.begin_register(u64::MAX, 2, 0).is_err()); + } + + #[test] + fn unregister_waits_for_destination_guards() { + let (registry, registration_id) = active_registry(); + let guard = registry + .validate_destination(registration_id, 0x1000, 0x1000) + .expect("full range must validate"); + + assert!( + registry + .begin_unregister(registration_id) + .unwrap_err() + .contains("GPU registration is busy") + ); + drop(guard); + + let descriptor = registry + .begin_unregister(registration_id) + .expect("unregister must start after guards drop"); + assert_eq!(descriptor.registration_id, registration_id); + registry.finish_unregister(registration_id, true); + assert!( + registry + .validate_destination(registration_id, 0x1000, 1) + .is_err() + ); + } + + #[test] + fn failed_backend_transitions_restore_retryable_state() { + let registry = GpuMemoryRegistry::new(); + let first = registry + .begin_register(0x1000, 0x1000, 0) + .expect("first registration must start"); + registry.finish_register(first.registration_id, false); + + let second = registry + .begin_register(0x3000, 0x1000, 1) + .expect("failed registration must return to empty"); + registry.finish_register(second.registration_id, true); + let descriptor = registry + .begin_unregister(second.registration_id) + .expect("unregister must start"); + registry.finish_unregister(descriptor.registration_id, false); + + assert!( + registry + .validate_destination(second.registration_id, 0x3000, 1) + .is_ok() + ); + } +} diff --git a/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs b/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs index 2008f1b..86851bf 100644 --- a/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs +++ b/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs @@ -1,3 +1,4 @@ +use crate::ClientTransferEngineAccessTrait; use crate::SharedJsonMeta; use crate::client_kv_api::external_api::{ compute_external_get_start_transfer_prefix, normalize_external_get_start_group_lens, @@ -8,9 +9,16 @@ use crate::client_kv_api::msg_pack::{ ExternalInvalidateWeakIndexResp, }; use crate::client_seg_pool::{ClientSegPool, SideTransferPeerFileMeta}; +use crate::client_transfer_engine::{ClientTransferEngine, GpuMemoryGuard}; +use crate::cluster_manager::app_logic_ext::ClusterManagerAppLogicExt; use crate::cluster_manager::{ META_KEY_SHARED_STORAGE_NODE_ID, META_KEY_SHARED_STORAGE_NODE_START_TIME, }; +use crate::master_kv_router::msg_pack::{ + BatchGetDoneReq, BatchGetDoneResp, BatchGetRevokeReq, BatchGetRevokeResp, + BatchGetStartItemResp, BatchGetStartReq, BatchGetStartResp, GetAllocationMode, + GetExternalSinkTarget, +}; use crate::rpcresp_kvresult_convert::ToResult; use crate::{ client_kv_api::msg_pack::{ @@ -37,6 +45,7 @@ use crate::{ }, rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, KvResult, OK, SharedMemError}, }; +use ::tokio::sync::watch; use async_trait::async_trait; use core::panic; use dashmap::DashMap; @@ -44,6 +53,7 @@ use fluxon_commu::ShareGroupOwnerRef; use fluxon_framework::{LogicalModule, define_module}; use fluxon_observability::kv_metrics_actor::{ObserveComponent, ObserveDirection}; use fluxon_util::semaphore_map::SemaphoreMap; +use futures::{StreamExt, stream}; use libc::{MAP_SHARED, PROT_READ, PROT_WRITE, mmap}; use limit_thirdparty::tokio; use limit_thirdparty::tokio::sync::{ARwLock, Notify}; @@ -54,7 +64,7 @@ use std::{ // path::PathBuf, // 不再使用PathBuf sync::{ Arc, OnceLock, Weak, - atomic::{AtomicUsize, Ordering}, + atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering}, }, time::{Duration, Instant}, }; @@ -79,6 +89,7 @@ const EXTERNAL_PUT_START_RPC_TIMEOUT_SECS: u64 = 30; const EXTERNAL_PUT_TRANSFER_END_RPC_TIMEOUT_SECS: u64 = 30; const EXTERNAL_RPC_P2P_RECOVER_MAX_ATTEMPTS: usize = 3; const EXTERNAL_PUT_TRACE_LOG_WINDOW_SECS: u64 = 10; +const EXTERNAL_OWNER_INTRA_RPC_READY_TIMEOUT_SECS: u64 = 30; #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub(crate) enum ExternalDeleteAckBatchSendResult { @@ -92,6 +103,52 @@ pub struct ExternalClientGetStartResp { pub raw_prefix_hit_len: usize, } +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ExternalGpuDestination { + pub registration_id: u64, + pub addr: u64, + pub capacity: u64, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ExternalGpuGetStartResp { + pub handle: u64, + pub raw_prefix_hit_len: usize, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ExternalGpuGetTransferResp { + pub transferred_prefix_len: usize, + pub consumed_prefix_len: usize, +} + +fn external_gpu_transfer_plan_geometry_is_valid( + item: &BatchGetStartItemResp, + destination: &ExternalGpuDestination, + registered_generation: u64, +) -> bool { + item.len != 0 + && item.target_addr == destination.addr + && item.target_base_addr == destination.addr + && item.len <= destination.capacity + && item.prepared_target.is_none() + && registered_generation == destination.registration_id +} + +#[derive(Clone, Debug)] +enum ExternalGpuGetTerminal { + Completed, + Revoked { transfer_error: Option }, + Failed { detail: String }, +} + +struct PendingExternalGpuGet { + transferable_len: usize, + atomic_group_lens: Vec, + cancel_requested: Arc, + terminal_rx: watch::Receiver>, +} + struct PendingExternalGetStart { keys: Vec, transferable_len: usize, @@ -182,10 +239,12 @@ fn inline_external_get_tail_holder_ids( #[cfg(test)] mod inline_external_get_start_tests { use super::{ + ExternalGpuDestination, external_gpu_transfer_plan_geometry_is_valid, inline_external_get_tail_holder_ids, validate_inline_external_get_owner_generation, validate_inline_external_get_start_plan, }; use crate::client_kv_api::msg_pack::ExternalBatchGetItemResp; + use crate::master_kv_router::msg_pack::BatchGetStartItemResp; use crate::memholder::ExternalMemHolderInfo; use crate::rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, OK}; @@ -241,6 +300,28 @@ mod inline_external_get_start_tests { assert!(inline_external_get_tail_holder_ids(&items, 0).is_err()); assert!(inline_external_get_tail_holder_ids(&items, 4).is_err()); } + + #[test] + fn gpu_transfer_plan_accepts_zero_as_the_first_master_get_id() { + let destination = ExternalGpuDestination { + registration_id: 7, + addr: 0x1000, + capacity: 4096, + }; + let item = BatchGetStartItemResp { + get_id: 0, + target_addr: destination.addr, + target_base_addr: destination.addr, + len: destination.capacity, + ..Default::default() + }; + + assert!(external_gpu_transfer_plan_geometry_is_valid( + &item, + &destination, + destination.registration_id, + )); + } } fn duration_to_i64_us(duration: std::time::Duration) -> i64 { @@ -422,7 +503,8 @@ define_module!( ExternalClientApi, (external_client_api, ExternalClientApi), (p2p, P2pModule), - (cluster_manager, ClusterManager) + (cluster_manager, ClusterManager), + (client_transfer_engine, ClientTransferEngine) ); /// External Client configuration parameters @@ -498,6 +580,9 @@ pub struct ExternalInner { rpc_caller_external_batch_get_start: RPCCaller, rpc_caller_external_batch_get_transfer: RPCCaller, rpc_caller_external_batch_get_cancel: RPCCaller, + rpc_caller_master_batch_get_start: RPCCaller, + rpc_caller_master_batch_get_done: RPCCaller, + rpc_caller_master_batch_get_revoke: RPCCaller, rpc_caller_external_put_commit: RPCCaller, rpc_caller_external_batch_put_commit: RPCCaller, rpc_caller_external_put_start: RPCCaller, @@ -519,6 +604,8 @@ pub struct ExternalInner { pending_external_get_start: DashMap, /// Fully local plans consumed without a follow-up owner transfer RPC. pending_inline_external_get_start: DashMap, + next_gpu_get_handle: AtomicU64, + pending_external_gpu_get: DashMap, /// per-key semaphore (permits=1) to ensure single inflight per key inflight1_per_key: SemaphoreMap, put_trace_log_window: Mutex, @@ -527,6 +614,133 @@ pub struct ExternalInner { pub struct ExternalClientApi(ExternalInner); +async fn wait_external_gpu_get_terminal( + mut terminal_rx: watch::Receiver>, +) -> KvResult { + loop { + if let Some(terminal) = terminal_rx.borrow().clone() { + return Ok(terminal); + } + if terminal_rx.changed().await.is_err() { + return Err(KvError::Api(ApiError::Unknown { + detail: "GPU Get transfer task ended without publishing a terminal state" + .to_string(), + })); + } + } +} + +async fn run_external_gpu_get_transfer( + view: ExternalClientApiView, + transfer_items: Vec<(BatchGetStartItemResp, GpuMemoryGuard)>, + skipped_get_ids: Vec, + transfer_concurrency: usize, + cancel_requested: Arc, +) -> ExternalGpuGetTerminal { + let transfer_get_ids = transfer_items + .iter() + .map(|(item, _)| item.get_id) + .collect::>(); + let mut all_get_ids = skipped_get_ids.clone(); + all_get_ids.extend(transfer_get_ids.iter().copied()); + + let skipped_revoke_error = view + .external_client_api() + .inner() + .master_batch_gpu_get_revoke(skipped_get_ids) + .await + .err() + .map(|err| err.to_string()); + + if transfer_items.is_empty() { + return match skipped_revoke_error { + Some(detail) => ExternalGpuGetTerminal::Failed { + detail: format!("GPU Get could not revoke non-transferable starts: {detail}"), + }, + None => ExternalGpuGetTerminal::Revoked { + transfer_error: None, + }, + }; + } + + let transfer_futures = transfer_items.into_iter().map(|(item, gpu_guard)| { + let transfer_view = view.clone(); + let cancel_requested = cancel_requested.clone(); + async move { + if cancel_requested.load(Ordering::Acquire) { + return None; + } + transfer_view + .client_transfer_engine() + .transfer_data_no_copy_to_gpu( + item.node_id.clone(), + item.src_addr, + item.target_addr, + item.len, + gpu_guard, + ) + .await + .err() + .map(|err| { + format!( + "GPU Get transfer failed: get_id={} source={} src={:#x} target={:#x} len={} error={}", + item.get_id, + item.node_id, + item.src_addr, + item.target_addr, + item.len, + err + ) + }) + } + }); + let mut transfer_stream = + stream::iter(transfer_futures).buffer_unordered(transfer_concurrency.max(1)); + let mut transfer_error = None; + while let Some(item_error) = transfer_stream.next().await { + if transfer_error.is_none() { + transfer_error = item_error; + } + } + + let cancelled = cancel_requested.load(Ordering::Acquire); + if cancelled || transfer_error.is_some() || skipped_revoke_error.is_some() { + if let Err(err) = view + .external_client_api() + .inner() + .master_batch_gpu_get_revoke(all_get_ids) + .await + { + return ExternalGpuGetTerminal::Failed { + detail: format!( + "GPU Get cleanup failed after transfer/cancel: transfer_error={:?} skipped_revoke_error={:?} revoke_error={}", + transfer_error, skipped_revoke_error, err + ), + }; + } + if let Some(detail) = skipped_revoke_error { + return ExternalGpuGetTerminal::Failed { + detail: format!( + "GPU Get initially failed to revoke non-transferable starts: {detail}" + ), + }; + } + return ExternalGpuGetTerminal::Revoked { transfer_error }; + } + + match view + .external_client_api() + .inner() + .master_batch_gpu_get_done(transfer_get_ids) + .await + { + Ok(()) => ExternalGpuGetTerminal::Completed, + Err(err) => ExternalGpuGetTerminal::Failed { + detail: format!("GPU Get BatchDone failed: {err}"), + }, + } +} + impl ExternalClientApi { /// Access inner external-only API. Safe to unwrap in external role. pub fn inner(&self) -> &ExternalInner { @@ -567,6 +781,9 @@ impl ExternalClientApi { rpc_caller_external_batch_get_start: RPCCaller::::new(), rpc_caller_external_batch_get_transfer: RPCCaller::::new(), rpc_caller_external_batch_get_cancel: RPCCaller::::new(), + rpc_caller_master_batch_get_start: RPCCaller::::new(), + rpc_caller_master_batch_get_done: RPCCaller::::new(), + rpc_caller_master_batch_get_revoke: RPCCaller::::new(), rpc_caller_external_put_commit: RPCCaller::::new(), rpc_caller_external_batch_put_commit: RPCCaller::::new(), rpc_caller_external_put_start: RPCCaller::::new(), @@ -587,6 +804,8 @@ impl ExternalClientApi { key_weak_memholder_index: DashMap::new(), pending_external_get_start: DashMap::new(), pending_inline_external_get_start: DashMap::new(), + next_gpu_get_handle: AtomicU64::new(1), + pending_external_gpu_get: DashMap::new(), inflight1_per_key: SemaphoreMap::new(1, std::time::Duration::from_secs(120)), put_trace_log_window: Mutex::new(ExternalPutTraceLogWindow::new()), external_delete_ack_batch: ExternalDeleteAckBatchHandle::new(), @@ -666,6 +885,12 @@ impl ExternalClientApi { .regist(ext.view.p2p_module()); ext.rpc_caller_external_batch_get_cancel .regist(ext.view.p2p_module()); + ext.rpc_caller_master_batch_get_start + .regist(ext.view.p2p_module()); + ext.rpc_caller_master_batch_get_done + .regist(ext.view.p2p_module()); + ext.rpc_caller_master_batch_get_revoke + .regist(ext.view.p2p_module()); ext.rpc_caller_external_put_commit .regist(ext.view.p2p_module()); ext.rpc_caller_external_batch_put_commit @@ -740,6 +965,11 @@ impl ExternalClientApi { .set_self_sub_cluster(ext.initial_sub_cluster.get().unwrap().clone()) .await .map_err(KvError::from)?; + // Publishing the share-group binding changes the desired local-owner route from the + // pre-binding direct lane to intra-machine-only. Do not announce external init complete + // until that topology transition has converged for the exact owner generation. + self.wait_current_owner_intra_rpc_ready_after_binding() + .await?; { let view = ext.view.clone_view(); @@ -894,6 +1124,61 @@ impl ExternalClientApi { } } } + + async fn wait_current_owner_intra_rpc_ready_after_binding(&self) -> Result<(), KvError> { + let ext = &self.0; + let owner_id = ext + .shared_storage_node_id() + .await + .expect("external role expects current_owner to be Some after init2"); + let owner_node_id = owner_id.clone().into(); + let owner_start_time = ext.current_owner_start_time().await; + let expected_binding = ShareGroupOwnerRef { + owner_id: owner_id.clone(), + owner_start_time, + }; + let started_at = Instant::now(); + let timeout = Duration::from_secs(EXTERNAL_OWNER_INTRA_RPC_READY_TIMEOUT_SECS); + + tracing::info!( + owner_id = %owner_id, + owner_start_time, + "External init: waiting for current owner intra-machine RPC route after share-group binding" + ); + loop { + let snapshot = ext.view.p2p_module().tier_snapshot(); + let self_binding_ready = snapshot + .share_group_owner(&snapshot.self_peer_gen.peer_id) + == Some(&expected_binding); + if self_binding_ready + && let Some(peer_gen) = snapshot.peer_gen(&owner_node_id) + && peer_gen.node_start_time == owner_start_time + && snapshot.is_send_ready_intra_effective(&peer_gen) + { + tracing::info!( + owner_id = %owner_id, + owner_start_time, + elapsed_ms = started_at.elapsed().as_millis(), + "External init: current owner intra-machine RPC route ready after share-group binding" + ); + return Ok(()); + } + + if started_at.elapsed() >= timeout { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "timed out waiting for current owner intra-machine RPC route after share-group binding: owner_id={} owner_start_time={} timeout_s={} self_binding={:?} peer={:?}", + owner_id, + owner_start_time, + EXTERNAL_OWNER_INTRA_RPC_READY_TIMEOUT_SECS, + snapshot.share_group_owner(&snapshot.self_peer_gen.peer_id), + snapshot.peers.get(owner_id.as_str()), + ), + })); + } + sleep(Duration::from_millis(20)).await; + } + } } impl ExternalInner { @@ -2044,6 +2329,404 @@ impl ExternalInner { } } + async fn master_batch_gpu_get_revoke(&self, get_ids: Vec) -> KvResult<()> { + if get_ids.is_empty() { + return Ok(()); + } + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let expected_get_ids = get_ids.clone(); + let resp: MsgPack = self + .rpc_caller_master_batch_get_revoke + .call( + self.view.p2p_module(), + master_node_id.into(), + MsgPack { + serialize_part: BatchGetRevokeReq { get_ids }, + raw_bytes: Vec::new(), + }, + None, + 0, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + if resp.serialize_part.items.len() != expected_get_ids.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "GPU Get BatchRevoke response length mismatch: expected={} got={}", + expected_get_ids.len(), + resp.serialize_part.items.len() + ), + })); + } + for (expected_get_id, item) in expected_get_ids + .into_iter() + .zip(resp.serialize_part.items.into_iter()) + { + if item.get_id != expected_get_id { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "GPU Get BatchRevoke response identity mismatch: expected={} got={}", + expected_get_id, item.get_id + ), + })); + } + crate::rpcresp_kvresult_convert::try_from_code(item.error_code, item.error_json)?; + } + Ok(()) + } + + async fn master_batch_gpu_get_done(&self, get_ids: Vec) -> KvResult<()> { + if get_ids.is_empty() { + return Ok(()); + } + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let expected_get_ids = get_ids.clone(); + let resp: MsgPack = self + .rpc_caller_master_batch_get_done + .call( + self.view.p2p_module(), + master_node_id.into(), + MsgPack { + serialize_part: BatchGetDoneReq { get_ids }, + raw_bytes: Vec::new(), + }, + None, + 0, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + if resp.serialize_part.items.len() != expected_get_ids.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "GPU Get BatchDone response length mismatch: expected={} got={}", + expected_get_ids.len(), + resp.serialize_part.items.len() + ), + })); + } + for (expected_get_id, item) in expected_get_ids + .into_iter() + .zip(resp.serialize_part.items.into_iter()) + { + if item.get_id != expected_get_id { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "GPU Get BatchDone response identity mismatch: expected={} got={}", + expected_get_id, item.get_id + ), + })); + } + crate::rpcresp_kvresult_convert::try_from_code(item.error_code, item.error_json)?; + if item.holder_id != 0 || item.allocation_mode != GetAllocationMode::ExternalSink { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "GPU Get BatchDone returned a cache-owned target: get_id={} holder_id={} allocation_mode={:?}", + item.get_id, item.holder_id, item.allocation_mode + ), + })); + } + } + Ok(()) + } + + pub async fn get_start_gpu( + &self, + keys: Vec, + destinations: Vec, + prefix_best_effort: bool, + atomic_group_lens: Option>, + transfer_concurrency: usize, + ) -> KvResult { + if keys.is_empty() { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: "get_start_gpu requires at least one key".to_string(), + })); + } + if keys.len() != destinations.len() { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "get_start_gpu keys/destinations length mismatch: keys={} destinations={}", + keys.len(), + destinations.len() + ), + })); + } + if transfer_concurrency == 0 { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: "get_start_gpu transfer_concurrency must be > 0".to_string(), + })); + } + let group_lens = normalize_external_get_start_group_lens(keys.len(), atomic_group_lens)?; + let self_info = self.view.cluster_manager().get_self_info(); + if self_info.node_role() != NodeRole::External { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: "get_start_gpu requires an external node membership".to_string(), + })); + } + + let mut destination_guards = Vec::with_capacity(destinations.len()); + let mut external_sink_targets = Vec::with_capacity(destinations.len()); + for destination in &destinations { + let guard = self + .view + .client_transfer_engine() + .validate_gpu_destination( + destination.registration_id, + destination.addr, + destination.capacity, + )?; + destination_guards.push(guard); + external_sink_targets.push(Some(GetExternalSinkTarget { + addr: destination.addr, + capacity: destination.capacity, + registration_id: destination.registration_id, + requester_node_start_time: self_info.node_start_time, + })); + } + + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let resp: MsgPack = self + .rpc_caller_master_batch_get_start + .call( + self.view.p2p_module(), + master_node_id.into(), + MsgPack { + serialize_part: BatchGetStartReq { + keys: keys.clone(), + prepared_targets: Vec::new(), + external_sink_targets, + }, + raw_bytes: Vec::new(), + }, + None, + 0, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + + let start_items = resp.serialize_part.items; + let started_get_ids = start_items + .iter() + .filter(|item| item.error_code == OK) + .map(|item| item.get_id) + .collect::>(); + if start_items.len() != keys.len() { + let cleanup = self + .master_batch_gpu_get_revoke(started_get_ids) + .await + .err() + .map(|err| err.to_string()); + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "get_start_gpu response length mismatch: expected={} got={} cleanup_error={:?}", + keys.len(), + start_items.len(), + cleanup + ), + })); + } + + for item in &start_items { + if item.error_code != OK + && item.error_code + != crate::rpcresp_kvresult_convert::msg_and_error::codes_api::API_KEY_NOT_FOUND + { + let err = crate::rpcresp_kvresult_convert::try_from_code( + item.error_code, + item.error_json.clone(), + ) + .expect_err("non-OK GPU GetStart item must decode as an error"); + let cleanup = self + .master_batch_gpu_get_revoke(started_get_ids) + .await + .err() + .map(|cleanup_err| cleanup_err.to_string()); + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "get_start_gpu item failed: error={} cleanup_error={:?}", + err, cleanup + ), + })); + } + } + + for (idx, ((item, destination), guard)) in start_items + .iter() + .zip(destinations.iter()) + .zip(destination_guards.iter()) + .enumerate() + { + if item.error_code != OK { + continue; + } + let geometry_is_valid = external_gpu_transfer_plan_geometry_is_valid( + item, + destination, + guard.registration().registration_id, + ); + if !geometry_is_valid || item.node_id == self_info.id { + let cleanup = self + .master_batch_gpu_get_revoke(started_get_ids) + .await + .err() + .map(|cleanup_err| cleanup_err.to_string()); + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "get_start_gpu invalid master transfer plan: index={} get_id={} source={} target={:#x} base={:#x} len={} destination={:?} cleanup_error={:?}", + idx, + item.get_id, + item.node_id, + item.target_addr, + item.target_base_addr, + item.len, + destination, + cleanup + ), + })); + } + } + + let raw_prefix_hit_len = start_items + .iter() + .take_while(|item| item.error_code == OK) + .count(); + let transferable_len = compute_external_get_start_transfer_prefix( + raw_prefix_hit_len, + &group_lens, + prefix_best_effort, + ); + let mut transfer_items = Vec::with_capacity(transferable_len); + let mut skipped_get_ids = Vec::new(); + for (idx, (item, guard)) in start_items + .into_iter() + .zip(destination_guards.into_iter()) + .enumerate() + { + if item.error_code != OK { + continue; + } + if idx < transferable_len { + transfer_items.push((item, guard)); + } else { + skipped_get_ids.push(item.get_id); + } + } + + let handle = self.next_gpu_get_handle.fetch_add(1, Ordering::Relaxed); + if handle == 0 { + let mut all_get_ids = skipped_get_ids.clone(); + all_get_ids.extend(transfer_items.iter().map(|(item, _)| item.get_id)); + let _ = self.master_batch_gpu_get_revoke(all_get_ids).await; + return Err(KvError::Api(ApiError::Unknown { + detail: "get_start_gpu local handle space exhausted".to_string(), + })); + } + let cancel_requested = Arc::new(AtomicBool::new(false)); + let (terminal_tx, terminal_rx) = watch::channel(None); + self.pending_external_gpu_get.insert( + handle, + PendingExternalGpuGet { + transferable_len, + atomic_group_lens: group_lens, + cancel_requested: cancel_requested.clone(), + terminal_rx, + }, + ); + let view = self.view.clone_view(); + let view_task = view.clone(); + view.spawn(format!("external_gpu_get_transfer_{handle}"), async move { + let terminal = run_external_gpu_get_transfer( + view_task, + transfer_items, + skipped_get_ids, + transfer_concurrency, + cancel_requested, + ) + .await; + let _ = terminal_tx.send(Some(terminal)); + }); + Ok(ExternalGpuGetStartResp { + handle, + raw_prefix_hit_len, + }) + } + + pub async fn get_transfer_gpu( + &self, + handle: u64, + consume_prefix_len: Option, + ) -> KvResult { + let Some((_, pending)) = self.pending_external_gpu_get.remove(&handle) else { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!("get_transfer_gpu requires a live handle: {handle}"), + })); + }; + let consumed_prefix_len = consume_prefix_len.unwrap_or(pending.transferable_len); + if let Err(err) = validate_external_get_consume_prefix( + consumed_prefix_len, + pending.transferable_len, + &pending.atomic_group_lens, + ) { + self.pending_external_gpu_get.insert(handle, pending); + return Err(err); + } + let terminal = wait_external_gpu_get_terminal(pending.terminal_rx).await?; + match terminal { + ExternalGpuGetTerminal::Completed => Ok(ExternalGpuGetTransferResp { + transferred_prefix_len: pending.transferable_len, + consumed_prefix_len, + }), + ExternalGpuGetTerminal::Revoked { transfer_error } => { + Err(KvError::Api(ApiError::Unknown { + detail: format!( + "get_transfer_gpu was revoked: handle={} transfer_error={:?}", + handle, transfer_error + ), + })) + } + ExternalGpuGetTerminal::Failed { detail } => { + Err(KvError::Api(ApiError::Unknown { detail })) + } + } + } + + pub async fn cancel_get_transfer_gpu(&self, handle: u64) -> KvResult<()> { + let Some((_, pending)) = self.pending_external_gpu_get.remove(&handle) else { + return Ok(()); + }; + pending.cancel_requested.store(true, Ordering::Release); + match wait_external_gpu_get_terminal(pending.terminal_rx).await? { + ExternalGpuGetTerminal::Completed | ExternalGpuGetTerminal::Revoked { .. } => Ok(()), + ExternalGpuGetTerminal::Failed { detail } => { + Err(KvError::Api(ApiError::Unknown { detail })) + } + } + } + pub async fn batch_get_start( &self, keys: Vec, diff --git a/fluxon_rs/fluxon_kv/src/lib.rs b/fluxon_rs/fluxon_kv/src/lib.rs index 0842a68..a9d38ae 100644 --- a/fluxon_rs/fluxon_kv/src/lib.rs +++ b/fluxon_rs/fluxon_kv/src/lib.rs @@ -2057,6 +2057,29 @@ async fn run_client_impl( metric_reporter_arg: MetricReporterNewArg { test_spec_config: config.test_spec_config.clone(), }, + client_seg_pool_arg: ClientSegPoolNewArg { + contribute_size: config.contribute_to_cluster_pool_size.clone(), + share_mem_path: config.share_mem_path.clone(), + large_file_paths: config.large_file_paths.clone(), + cluster_name: config.cluster_name.clone(), + etcd_addresses: config.etcd_addresses_raw.clone(), + attach_existing_meta: None, + side_transfer_worker: false, + require_transfer_rpc_fast_path_ready_timeout: None, + }, + client_transfer_engine_arg: ClientTransferEngineNewArg { + metadata_uri: config.fluxonkv_spec.etcd_addresses[0].clone(), + instance_name: config.instance_key.clone(), + enable_transfer_rpc_fast_path: config.fluxonkv_spec.enable_transfer_rpc_fast_path, + rpc_port: 12345, + protocol_type: config.protocol.protocol_type.clone(), + rdma_device_names: transfer_engine_rdma_device_names_from_config( + &config.protocol, + Some(&config.test_spec_config), + ), + backend_activation_mode: transfer_backend_activation_mode, + transfer_engine: config.fluxonkv_spec.transfer_engine.clone(), + }, external_client_api_arg: ExternalClientApiNewArg { shared_memory_path: config.share_mem_path.clone(), shared_file_path: config.share_mem_path.clone(), diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs index 795a1c4..46c8e2f 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs @@ -6,9 +6,9 @@ use super::{ BatchGetDoneItemResp, BatchGetDoneReq, BatchGetDoneResp, BatchGetRevokeItemResp, BatchGetRevokeReq, BatchGetRevokeResp, BatchGetStartItemResp, BatchGetStartReq, BatchGetStartResp, BatchIsExistReq, BatchIsExistResp, GetAllocationMode, GetDoneReq, - GetDoneResp, GetMetaReq, GetMetaResp, GetPreparedLocalReserveTarget, GetRevokeReq, - GetRevokeResp, GetStartReq, GetStartResp, MemHolderKeepAliveReq, MemHolderKeepAliveResp, - MemHolderReleaseReq, MemHolderReleaseResp, + GetDoneResp, GetExternalSinkTarget, GetMetaReq, GetMetaResp, GetPreparedLocalReserveTarget, + GetRevokeReq, GetRevokeResp, GetStartReq, GetStartResp, MemHolderKeepAliveReq, + MemHolderKeepAliveResp, MemHolderReleaseReq, MemHolderReleaseResp, }, node_generation_is_current_live, publish_route_replica_tomb_fenced, route_maintenance::{RoutePublishEvent, apply_post_route_maintenance_batch}, @@ -17,12 +17,13 @@ use crate::master_kv_router::OneKvNodesRoutes; use crate::master_kv_router::put::PutIDForAKey; use crate::memholder::MemholderManagerTrait; use crate::{ - cluster_manager::NodeID, + cluster_manager::{ClusterManagerAccessTrait, NodeID, NodeRole}, master_seg_manager::{MasterSegManagerAccessTrait, NodeTombTag, one_seg_allocator::Allocation}, p2p::msg_pack::MsgPack, rpcresp_kvresult_convert::msg_and_error::{self, kv}, }; use dashmap::DashMap; +use fluxon_commu::share_group_owner_ref_from_metadata; use limit_thirdparty::tokio; use rand::Rng; use rand::seq::SliceRandom; @@ -170,6 +171,75 @@ fn validate_prepared_local_reserve_target( )) } +fn external_sink_local_owner_id( + view: &MasterKvRouterView, + req_node_id: &NodeID, + requester_node_start_time: i64, +) -> Option { + let requester = view + .cluster_manager() + .get_member_info_cached(req_node_id.as_ref())?; + if requester.node_start_time != requester_node_start_time + || requester.node_role() != NodeRole::External + { + return None; + } + let owner_ref = share_group_owner_ref_from_metadata(&requester.metadata)?; + let owner = view + .cluster_manager() + .get_member_info_cached(&owner_ref.owner_id)?; + (owner.node_start_time == owner_ref.owner_start_time && owner.node_role() == NodeRole::Client) + .then_some(owner_ref.owner_id) +} + +fn external_sink_requester_generation_is_current( + view: &MasterKvRouterView, + req_node_id: &NodeID, + requester_node_start_time: i64, +) -> bool { + external_sink_local_owner_id(view, req_node_id, requester_node_start_time).is_some() +} + +fn validate_external_sink_target( + view: &MasterKvRouterView, + req_node_id: &NodeID, + target: &GetExternalSinkTarget, + value_len: u64, +) -> Result<(), msg_and_error::KvError> { + let invalid = |detail: String| { + msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { detail }) + }; + if target.addr == 0 || target.capacity == 0 || target.registration_id == 0 { + return Err(invalid(format!( + "external Get sink requires non-zero addr/capacity/registration_id: addr={:#x} capacity={} registration_id={}", + target.addr, target.capacity, target.registration_id + ))); + } + if target.addr.checked_add(target.capacity).is_none() { + return Err(invalid(format!( + "external Get sink range overflows: addr={:#x} capacity={}", + target.addr, target.capacity + ))); + } + if value_len > target.capacity { + return Err(invalid(format!( + "external Get sink is too small: value_len={} capacity={}", + value_len, target.capacity + ))); + } + if !external_sink_requester_generation_is_current( + view, + req_node_id, + target.requester_node_start_time, + ) { + return Err(invalid(format!( + "external Get sink requester generation is not current: requester={} start_time={}", + req_node_id, target.requester_node_start_time + ))); + } + Ok(()) +} + pub async fn handle_get_start( view: MasterKvRouterView, req: MsgPack, @@ -218,6 +288,16 @@ pub async fn handle_get_start( tracing::debug!("Handling GetStartReq: {:?}", req.serialize_part); + if req.serialize_part.prepared_target.is_some() + && req.serialize_part.external_sink_target.is_some() + { + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { + detail: "GetStart prepared_target and external_sink_target are mutually exclusive" + .to_string(), + }); + return failed_resp_err(err, None, &view, &req.serialize_part.key); + } + let activity_lease = match view .master_kv_router() .reserve_inflight_get_key(&req.serialize_part.key) @@ -262,6 +342,10 @@ pub async fn handle_get_start( let replicas: HashMap = one_kv_nodes_routes.nodes_replicas.read().clone(); let prepared_target = req.serialize_part.prepared_target.clone(); + let external_sink_target = req.serialize_part.external_sink_target.clone(); + let external_sink_local_owner = external_sink_target.as_ref().and_then(|target| { + external_sink_local_owner_id(&view, &req_node_id, target.requester_node_start_time) + }); // Currently we are holding the lock with `replicas` // 选择一个replica (这里可以实现更复杂的选择逻辑) let mut replica_keys = replicas.keys().collect::>(); @@ -277,6 +361,16 @@ pub async fn handle_get_start( tombs.insert(selected_replica_key.to_owned()); continue; } + if external_sink_local_owner + .as_deref() + .is_some_and(|owner_id| selected_replica.node_id.as_ref() == owner_id) + { + // The explicit GPU path is RDMA-only. The requester's share-group + // owner is local IPC/P2P topology, whose fallback would require + // CPU access to a CUDA virtual address. Leave that replica for the + // ordinary CPU-buffered Get path and search for a remote route. + continue; + } let src_node_id = selected_replica.node_id.clone(); let src_len = selected_replica.backing.len(); let src_abs_addr = selected_replica.backing.abs_addr(); @@ -354,34 +448,14 @@ pub async fn handle_get_start( // 为get调用方分配接收内存作为传输target if target.is_none() { - target = Some(if let Some(prepared_target) = prepared_target.as_ref() { - if replicas - .get(&req_node_id) - .is_some_and(|replica| !replica.tomb_tag.is_tomb()) - { - let err = msg_and_error::KvError::Api( - msg_and_error::ApiError::InvalidArgument { - detail: format!( - "prepared local-reserve Get target cannot replace a live replica: key={} requester={}", - req.serialize_part.key, req_node_id - ), - }, - ); - return failed_resp_err( - err, - Some((tombs.clone(), one_kv_nodes_routes.put_id)), + target = Some( + if let Some(external_sink_target) = external_sink_target.as_ref() { + if let Err(err) = validate_external_sink_target( &view, - &req.serialize_part.key, - ); - } - let (slot, _prepared_tomb_tag) = match validate_prepared_local_reserve_target( - &view, - &req_node_id, - prepared_target, - src_len, - ) { - Ok(slot) => slot, - Err(err) => { + &req_node_id, + external_sink_target, + src_len, + ) { return failed_resp_err( err, Some((tombs.clone(), one_kv_nodes_routes.put_id)), @@ -389,26 +463,66 @@ pub async fn handle_get_start( &req.serialize_part.key, ); } - }; - allocation_mode = GetAllocationMode::LocalCommittedSlot; - InflightGetTarget::PreparedLocalReserveSlot(slot) - } else if let Some(replica_on_recv_node) = replicas.get(&req_node_id) { - match &replica_on_recv_node.backing { - super::KvReplicaBacking::Allocation(allocation) => { - allocation_mode = GetAllocationMode::ReuseReplica; - InflightGetTarget::Allocation(allocation.clone()) + allocation_mode = GetAllocationMode::ExternalSink; + InflightGetTarget::ExternalSink(external_sink_target.clone()) + } else if let Some(prepared_target) = prepared_target.as_ref() { + if replicas + .get(&req_node_id) + .is_some_and(|replica| !replica.tomb_tag.is_tomb()) + { + let err = msg_and_error::KvError::Api( + msg_and_error::ApiError::InvalidArgument { + detail: format!( + "prepared local-reserve Get target cannot replace a live replica: key={} requester={}", + req.serialize_part.key, req_node_id + ), + }, + ); + return failed_resp_err( + err, + Some((tombs.clone(), one_kv_nodes_routes.put_id)), + &view, + &req.serialize_part.key, + ); } - super::KvReplicaBacking::CommittedSlot(_) => match allocate_request_target() { + let (slot, _prepared_tomb_tag) = match validate_prepared_local_reserve_target( + &view, + &req_node_id, + prepared_target, + src_len, + ) { + Ok(slot) => slot, + Err(err) => { + return failed_resp_err( + err, + Some((tombs.clone(), one_kv_nodes_routes.put_id)), + &view, + &req.serialize_part.key, + ); + } + }; + allocation_mode = GetAllocationMode::LocalCommittedSlot; + InflightGetTarget::PreparedLocalReserveSlot(slot) + } else if let Some(replica_on_recv_node) = replicas.get(&req_node_id) { + match &replica_on_recv_node.backing { + super::KvReplicaBacking::Allocation(allocation) => { + allocation_mode = GetAllocationMode::ReuseReplica; + InflightGetTarget::Allocation(allocation.clone()) + } + super::KvReplicaBacking::CommittedSlot(_) => { + match allocate_request_target() { + Ok(allocation) => allocation, + Err(resp) => return resp, + } + } + } + } else { + match allocate_request_target() { Ok(allocation) => allocation, Err(resp) => return resp, - }, - } - } else { - match allocate_request_target() { - Ok(allocation) => allocation, - Err(resp) => return resp, - } - }); + } + }, + ); } let target = target @@ -433,8 +547,9 @@ pub async fn handle_get_start( && node_generation_is_current_live(&view, &req_node_id, &grant.tomb_tag)) .then(|| grant.tomb_tag.clone()) }), + InflightGetTarget::ExternalSink(_) => None, }; - let Some(target_tomb_tag) = target_tomb_tag else { + if !matches!(&target, InflightGetTarget::ExternalSink(_)) && target_tomb_tag.is_none() { let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { detail: format!( "Get target generation changed before start publication: get_id={} key={} requester={}", @@ -447,7 +562,7 @@ pub async fn handle_get_start( &view, &req.serialize_part.key, ); - }; + } // Convert to absolute addresses for Mooncake (requires absolute) // Use allocation's allocator base directly @@ -704,7 +819,88 @@ async fn handle_get_done_locked( let req_node_id = inflight_info.req_node_id.clone(); let key = inflight_info.key; let target_cap = inflight_info.target.capacity(); - if !node_generation_is_current_live(&view, &req_node_id, &inflight_info.target_tomb_tag) { + if allocation_mode == GetAllocationMode::ExternalSink { + let generation_is_current = match &inflight_info.target { + InflightGetTarget::ExternalSink(target) => { + external_sink_requester_generation_is_current( + &view, + &req_node_id, + target.requester_node_start_time, + ) + } + _ => false, + }; + let terminal = if generation_is_current { + view.master_kv_router() + .view() + .metric_reporter() + .metrics() + .inc_kv_get_done_allocation("external_sink"); + GetDoneResp { + holder_id: 0, + allocation_mode: GetAllocationMode::ExternalSink, + error_code: msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + } + } else { + let err = msg_and_error::KvError::Api( + msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "external Get sink requester generation departed before Done: get_id={} key={} requester={}", + get_id, key, req_node_id + ), + }, + ); + crate::rpcresp_kvresult_convert::FromError::from_error(&err) + }; + let completed = CompletedGetInfo { + req_node_id: req_node_id.clone(), + response: terminal.clone(), + }; + if let Some(terminals) = deferred_terminals.as_deref_mut() { + terminals.push((get_id, completed)); + } else { + view.master_kv_router() + .inner() + .completed_gets + .insert(get_id, completed) + .await; + } + return MsgPack { + serialize_part: terminal, + raw_bytes: Vec::new(), + }; + } + + let Some(target_tomb_tag) = inflight_info.target_tomb_tag.as_ref() else { + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { + detail: format!( + "allocator-backed Get lost its target generation: get_id={} key={} requester={}", + get_id, key, req_node_id + ), + }); + let terminal: GetDoneResp = + crate::rpcresp_kvresult_convert::FromError::from_error(&err); + let completed = CompletedGetInfo { + req_node_id: req_node_id.clone(), + response: terminal.clone(), + }; + if let Some(terminals) = deferred_terminals.as_deref_mut() { + terminals.push((get_id, completed)); + } else { + view.master_kv_router() + .inner() + .completed_gets + .insert(get_id, completed) + .await; + } + return MsgPack { + serialize_part: terminal, + raw_bytes: Vec::new(), + }; + }; + if !node_generation_is_current_live(&view, &req_node_id, target_tomb_tag) { let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidPutMasterState { detail: format!( "GetDone target generation departed: get_id={} key={} requester={}", @@ -757,12 +953,15 @@ async fn handle_get_done_locked( holder_id } InflightGetTarget::PreparedLocalReserveSlot(_) => 0, + InflightGetTarget::ExternalSink(_) => { + unreachable!("external Get sink must complete before holder publication") + } }; // Close the insertion-vs-MemberLeft cleanup race for the holder. If // MemberLeft marked the shared tag before this check, remove the exact // holder we just inserted. Otherwise its later cleanup must observe it. - if inflight_info.target_tomb_tag.is_tomb() { + if target_tomb_tag.is_tomb() { if let Some(holder_key) = inserted_holder_key.as_ref() { view.master_kv_router() .inner() @@ -809,7 +1008,7 @@ async fn handle_get_done_locked( if one_kv_nodes_routes.put_id == inflight_info.put_id { match view.master_kv_router().reserve_node_cache_capacity( &req_node_id, - &inflight_info.target_tomb_tag, + target_tomb_tag, ReservedCapacityReason::OwnerIndexedAllocation, target_cap, ) { @@ -823,11 +1022,14 @@ async fn handle_get_done_locked( InflightGetTarget::PreparedLocalReserveSlot(_) => { unreachable!("durable Get mode must use Allocation target") } + InflightGetTarget::ExternalSink(_) => { + unreachable!("durable Get mode cannot use external sink") + } }), owner_local_indexed: true, get_durable_reservation: inflight_info.durable_reservation.clone(), capacity_reservation, - tomb_tag: inflight_info.target_tomb_tag.clone(), + tomb_tag: target_tomb_tag.clone(), }; if publish_route_replica_tomb_fenced( &one_kv_nodes_routes, @@ -888,7 +1090,7 @@ async fn handle_get_done_locked( let mut route_lease_id = None; let capacity_reservation = view.master_kv_router().reserve_node_cache_capacity( &req_node_id, - &inflight_info.target_tomb_tag, + target_tomb_tag, ReservedCapacityReason::OwnerIndexedAllocation, target_cap, ); @@ -906,9 +1108,7 @@ async fn handle_get_done_locked( let mut replicas = current_route.nodes_replicas.write(); if let Some(replica) = replicas.get_mut(&req_node_id) { local_index_published = !replica.tomb_tag.is_tomb() - && replica - .tomb_tag - .same_generation(&inflight_info.target_tomb_tag) + && replica.tomb_tag.same_generation(target_tomb_tag) && matches!( &replica.backing, super::KvReplicaBacking::Allocation(allocation) @@ -977,6 +1177,9 @@ async fn handle_get_done_locked( InflightGetTarget::Allocation(_) => { unreachable!("local committed-slot Get mode must use a prepared slot") } + InflightGetTarget::ExternalSink(_) => { + unreachable!("local committed-slot Get mode cannot use external sink") + } }; let mut published = false; let mut route_publish_event = None; @@ -988,7 +1191,7 @@ async fn handle_get_done_locked( owner_local_indexed: true, get_durable_reservation: None, capacity_reservation: None, - tomb_tag: inflight_info.target_tomb_tag.clone(), + tomb_tag: target_tomb_tag.clone(), }; if publish_route_replica_tomb_fenced( ¤t_route, @@ -1056,6 +1259,7 @@ async fn handle_get_done_locked( GetAllocationMode::ReuseReplica => "reuse_replica", GetAllocationMode::DurableReplica => "durable_replica", GetAllocationMode::LocalCommittedSlot => "local_committed_slot", + GetAllocationMode::ExternalSink => "external_sink", }); let terminal = GetDoneResp { @@ -1343,6 +1547,7 @@ pub async fn handle_batch_get_start( let BatchGetStartReq { keys, prepared_targets, + external_sink_targets, } = req.serialize_part; if !prepared_targets.is_empty() && prepared_targets.len() != keys.len() { let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { @@ -1363,19 +1568,48 @@ pub async fn handle_batch_get_start( raw_bytes: Vec::new(), }; } + if !external_sink_targets.is_empty() && external_sink_targets.len() != keys.len() { + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { + detail: format!( + "batch_get_start external sink target length mismatch: keys={} targets={}", + keys.len(), + external_sink_targets.len() + ), + }); + let error: GetStartResp = crate::rpcresp_kvresult_convert::FromError::from_error(&err); + return MsgPack { + serialize_part: BatchGetStartResp { + items: Vec::new(), + error_code: error.error_code, + error_json: error.error_json, + server_process_us: 0, + }, + raw_bytes: Vec::new(), + }; + } let prepared_targets = if prepared_targets.is_empty() { vec![None; keys.len()] } else { prepared_targets }; + let external_sink_targets = if external_sink_targets.is_empty() { + vec![None; keys.len()] + } else { + external_sink_targets + }; let mut items = Vec::with_capacity(keys.len()); - for (key, prepared_target) in keys.into_iter().zip(prepared_targets) { + for ((key, prepared_target), external_sink_target) in keys + .into_iter() + .zip(prepared_targets) + .zip(external_sink_targets) + { let (_get_id, resp) = handle_get_start( view.clone(), MsgPack { serialize_part: GetStartReq { key, prepared_target, + external_sink_target, }, raw_bytes: Vec::new(), }, diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs index 3939fb2..9f927d9 100644 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs @@ -431,8 +431,10 @@ pub struct InflightGetInfo { pub req_node_id: NodeID, pub len: u64, pub target: InflightGetTarget, - /// Exact requester registration generation that owns `target`. - pub target_tomb_tag: NodeTombTag, + /// Exact requester segment-registration generation that owns an + /// allocator-backed target. External sinks are caller-owned and instead + /// carry their membership generation inside `InflightGetTarget`. + pub target_tomb_tag: Option, pub route: Arc, pub allocation_mode: GetAllocationMode, pub durable_reservation: Option>, @@ -453,6 +455,7 @@ pub struct CompletedGetInfo { pub enum InflightGetTarget { Allocation(Arc), PreparedLocalReserveSlot(CommittedSlotReplica), + ExternalSink(crate::master_kv_router::msg_pack::GetExternalSinkTarget), } impl InflightGetTarget { @@ -460,6 +463,7 @@ impl InflightGetTarget { match self { Self::Allocation(allocation) => allocation.base_addr() + allocation.addr(), Self::PreparedLocalReserveSlot(slot) => slot.addr, + Self::ExternalSink(target) => target.addr, } } @@ -467,6 +471,7 @@ impl InflightGetTarget { match self { Self::Allocation(allocation) => allocation.base_addr(), Self::PreparedLocalReserveSlot(slot) => slot.base_addr, + Self::ExternalSink(target) => target.addr, } } @@ -474,6 +479,7 @@ impl InflightGetTarget { match self { Self::Allocation(allocation) => allocation.capcity(), Self::PreparedLocalReserveSlot(slot) => slot.slot_size, + Self::ExternalSink(target) => target.capacity, } } } @@ -4506,6 +4512,7 @@ impl MasterKvRouter { GetAllocationMode::ReuseReplica => "reuse_replica", GetAllocationMode::DurableReplica => "durable_replica", GetAllocationMode::LocalCommittedSlot => "local_committed_slot", + GetAllocationMode::ExternalSink => "external_sink", }; let mode_count = self .inner() diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs index 7ba3eb0..d21e39d 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs @@ -18,6 +18,9 @@ pub enum GetAllocationMode { ReuseReplica = 1, DurableReplica = 2, LocalCommittedSlot = 3, + /// Caller-owned memory used only as the terminal data sink. The master + /// neither allocates it nor publishes it as a cache route on GetDone. + ExternalSink = 4, } #[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)] @@ -29,10 +32,24 @@ pub struct GetPreparedLocalReserveTarget { pub base_addr: u64, } +#[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)] +pub struct GetExternalSinkTarget { + /// Exact destination address in the requester's registered memory. + pub addr: u64, + /// Caller-validated writable bytes starting at `addr`. + pub capacity: u64, + /// Opaque requester-side registration generation, retained for identity + /// and observability. The requester remains authoritative for MR lifetime. + pub registration_id: u64, + /// Requester membership generation captured with the GPU registration. + pub requester_node_start_time: i64, +} + #[derive(Default, Debug, Clone, Encode, Decode)] pub struct GetStartReq { pub key: String, pub prepared_target: Option, + pub external_sink_target: Option, } impl MsgPackSerializePart for GetStartReq { fn msg_id(&self) -> u32 { @@ -124,6 +141,9 @@ pub struct BatchGetStartReq { /// Empty selects ordinary master allocations. Otherwise this must contain /// exactly one entry per key. pub prepared_targets: Vec>, + /// Empty selects no external sinks. Otherwise this must contain exactly + /// one entry per key and is mutually exclusive with prepared targets. + pub external_sink_targets: Vec>, } impl MsgPackSerializePart for BatchGetStartReq { fn msg_id(&self) -> u32 { diff --git a/fluxon_rs/fluxon_pyo3/src/lib.rs b/fluxon_rs/fluxon_pyo3/src/lib.rs index be1a652..d849e62 100644 --- a/fluxon_rs/fluxon_pyo3/src/lib.rs +++ b/fluxon_rs/fluxon_pyo3/src/lib.rs @@ -25,6 +25,7 @@ use fluxon_kv::client_kv_api::{ ClientKvApiInner, OwnerLocalPublishItem, OwnerLocalPublishJob, OwnerLocalReserveSlotLease, }; use fluxon_kv::client_seg_pool::ClientSegPoolViewTrait; +use fluxon_kv::client_transfer_engine::ClientTransferEngineAccessTrait; use fluxon_kv::cluster_manager::ClusterManagerViewTrait; use fluxon_kv::cluster_manager::app_logic_ext::ClusterManagerAppLogicExt; use fluxon_kv::config::{ClientConfigYaml, MasterConfigYaml}; @@ -4770,6 +4771,263 @@ impl KvClient { cancel_get_transfer_inner(self, handle, py).into_py_object(py) } + /// Start background RDMA pulls directly into caller-owned GPU destinations. + #[pyo3(signature = (keys, destinations, prefix_best_effort=true, atomic_group_lens=None, concurrency=None))] + fn get_start_gpu( + &self, + keys: Vec, + destinations: Vec<(u64, u64, u64)>, + prefix_best_effort: bool, + atomic_group_lens: Option>, + concurrency: Option, + py: Python, + ) -> PyObject { + fn get_start_gpu_inner( + client: &KvClient, + keys: Vec, + destinations: Vec<(u64, u64, u64)>, + prefix_best_effort: bool, + atomic_group_lens: Option>, + concurrency: Option, + py: Python, + ) -> ApiResult { + if keys.is_empty() { + return ApiResult::new_error(new_invalid_argument_error( + py, + "get_start_gpu requires at least one key", + )); + } + if keys.len() != destinations.len() { + return ApiResult::new_error(new_invalid_argument_error( + py, + "get_start_gpu requires one destination per key", + )); + } + let batch_concurrency = match concurrency.unwrap_or(DEFAULT_PYO3_BATCH_CONCURRENCY) { + 0 => { + return ApiResult::new_error(new_invalid_argument_error( + py, + "get_start_gpu concurrency must be > 0", + )); + } + value => value, + }; + let framework = match require_kv_framework_api(client, py) { + Ok(value) => value, + Err(err) => return ApiResult::new_error(err), + }; + if !framework.is_external_mode() { + return ApiResult::new_error(new_invalid_argument_error( + py, + "get_start_gpu is supported only in external-client mode", + )); + } + let runtime = match client.runtime.as_ref() { + Some(value) => value, + None => { + return ApiResult::new_error(new_general_error( + py, + "Client runtime is missing", + )); + } + }; + let destinations = destinations + .into_iter() + .map(|(registration_id, addr, capacity)| { + fluxon_kv::external_client_api::ExternalGpuDestination { + registration_id, + addr, + capacity, + } + }) + .collect(); + let framework_for_start = framework.clone(); + let result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + framework_for_start + .external_client_api_view() + .external_client_api() + .inner() + .get_start_gpu( + keys, + destinations, + prefix_best_effort, + atomic_group_lens, + batch_concurrency, + ) + .await + }) + }) { + Ok(value) => value, + Err(err) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {err}"), + )); + } + }; + match result { + Ok(started) => { + let out = PyDict::new_bound(py); + out.set_item("handle", started.handle).expect("set handle"); + out.set_item("raw_prefix_hit_len", started.raw_prefix_hit_len as u64) + .expect("set raw_prefix_hit_len"); + ApiResult::new_success(out.into_py(py)) + } + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "get_start_gpu failed", + )), + } + } + + get_start_gpu_inner( + self, + keys, + destinations, + prefix_best_effort, + atomic_group_lens, + concurrency, + py, + ) + .into_py_object(py) + } + + /// Wait for a GPU Get terminal and consume an atomic prefix. + #[pyo3(signature = (handle, consume_prefix_len=None))] + fn get_transfer_gpu( + &self, + handle: u64, + consume_prefix_len: Option, + py: Python, + ) -> PyObject { + fn get_transfer_gpu_inner( + client: &KvClient, + handle: u64, + consume_prefix_len: Option, + py: Python, + ) -> ApiResult { + let framework = match require_kv_framework_api(client, py) { + Ok(value) => value, + Err(err) => return ApiResult::new_error(err), + }; + if !framework.is_external_mode() { + return ApiResult::new_error(new_invalid_argument_error( + py, + "get_transfer_gpu is supported only in external-client mode", + )); + } + let runtime = match client.runtime.as_ref() { + Some(value) => value, + None => { + return ApiResult::new_error(new_general_error( + py, + "Client runtime is missing", + )); + } + }; + let framework_for_transfer = framework.clone(); + let result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + framework_for_transfer + .external_client_api_view() + .external_client_api() + .inner() + .get_transfer_gpu(handle, consume_prefix_len) + .await + }) + }) { + Ok(value) => value, + Err(err) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {err}"), + )); + } + }; + match result { + Ok(terminal) => { + let out = PyDict::new_bound(py); + out.set_item( + "transferred_prefix_len", + terminal.transferred_prefix_len as u64, + ) + .expect("set transferred_prefix_len"); + out.set_item("consumed_prefix_len", terminal.consumed_prefix_len as u64) + .expect("set consumed_prefix_len"); + ApiResult::new_success(out.into_py(py)) + } + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "get_transfer_gpu failed", + )), + } + } + + get_transfer_gpu_inner(self, handle, consume_prefix_len, py).into_py_object(py) + } + + /// Cancel a live GPU Get handle and wait until master cleanup is terminal. + #[pyo3(signature = (handle))] + fn cancel_get_transfer_gpu(&self, handle: u64, py: Python) -> PyObject { + fn cancel_get_transfer_gpu_inner( + client: &KvClient, + handle: u64, + py: Python, + ) -> ApiResult { + let framework = match require_kv_framework_api(client, py) { + Ok(value) => value, + Err(err) => return ApiResult::new_error(err), + }; + if !framework.is_external_mode() { + return ApiResult::new_error(new_invalid_argument_error( + py, + "cancel_get_transfer_gpu is supported only in external-client mode", + )); + } + let runtime = match client.runtime.as_ref() { + Some(value) => value, + None => { + return ApiResult::new_error(new_general_error( + py, + "Client runtime is missing", + )); + } + }; + let framework_for_cancel = framework.clone(); + let result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + framework_for_cancel + .external_client_api_view() + .external_client_api() + .inner() + .cancel_get_transfer_gpu(handle) + .await + }) + }) { + Ok(value) => value, + Err(err) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {err}"), + )); + } + }; + match result { + Ok(()) => ApiResult::new_success(0i32.into_py(py)), + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "cancel_get_transfer_gpu failed", + )), + } + } + + cancel_get_transfer_gpu_inner(self, handle, py).into_py_object(py) + } + /// Allocate a fluxon-kv lease id synchronously. /// Always allocate a new lease id (no reuse by requested id). /// Allocate with the provided TTL seconds (must be >= MIN_CLIENT_TTL_SECONDS). @@ -5371,6 +5629,176 @@ impl KvClient { .into_py_object(py) } + /// Register one caller-owned GPU staging range with the transfer engine. + #[pyo3(signature = (ptr, len, device_id))] + fn register_gpu_buffer(&self, ptr: u64, len: u64, device_id: u32, py: Python) -> PyObject { + fn register_gpu_buffer_inner( + client: &KvClient, + ptr: u64, + len: u64, + device_id: u32, + py: Python, + ) -> ApiResult { + let framework = match require_kv_framework_api(client, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + if !framework.is_external_mode() { + return ApiResult::new_error(new_invalid_argument_error( + py, + "register_gpu_buffer is supported only in external-client mode", + )); + } + let runtime = match client.runtime.as_ref() { + Some(v) => v, + None => { + return ApiResult::new_error(new_general_error( + py, + "Client runtime is missing", + )); + } + }; + let framework_for_register = framework.clone(); + let result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + framework_for_register + .client_seg_pool_view() + .client_transfer_engine() + .register_gpu_memory(ptr, len, device_id) + .await + }) + }) { + Ok(v) => v, + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); + } + }; + match result { + Ok(registration) => { + let out = PyDict::new_bound(py); + out.set_item("registration_id", registration.registration_id) + .expect("set registration_id"); + out.set_item("ptr", registration.addr).expect("set ptr"); + out.set_item("len", registration.len).expect("set len"); + out.set_item("device_id", registration.device_id) + .expect("set device_id"); + ApiResult::new_success(out.into_py(py)) + } + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "register_gpu_buffer failed", + )), + } + } + + register_gpu_buffer_inner(self, ptr, len, device_id, py).into_py_object(py) + } + + /// Unregister a GPU staging range after every destination guard is released. + #[pyo3(signature = (registration_id))] + fn unregister_gpu_buffer(&self, registration_id: u64, py: Python) -> PyObject { + fn unregister_gpu_buffer_inner( + client: &KvClient, + registration_id: u64, + py: Python, + ) -> ApiResult { + let framework = match require_kv_framework_api(client, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + if !framework.is_external_mode() { + return ApiResult::new_error(new_invalid_argument_error( + py, + "unregister_gpu_buffer is supported only in external-client mode", + )); + } + let runtime = match client.runtime.as_ref() { + Some(v) => v, + None => { + return ApiResult::new_error(new_general_error( + py, + "Client runtime is missing", + )); + } + }; + let framework_for_unregister = framework.clone(); + let result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + framework_for_unregister + .client_seg_pool_view() + .client_transfer_engine() + .unregister_gpu_memory(registration_id) + .await + }) + }) { + Ok(v) => v, + Err(e) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {}", e), + )); + } + }; + match result { + Ok(()) => ApiResult::new_success(0i32.into_py(py)), + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "unregister_gpu_buffer failed", + )), + } + } + + unregister_gpu_buffer_inner(self, registration_id, py).into_py_object(py) + } + + /// Validate one destination against the exact GPU registration generation. + #[pyo3(signature = (registration_id, ptr, capacity))] + fn validate_gpu_destination( + &self, + registration_id: u64, + ptr: u64, + capacity: u64, + py: Python, + ) -> PyObject { + fn validate_gpu_destination_inner( + client: &KvClient, + registration_id: u64, + ptr: u64, + capacity: u64, + py: Python, + ) -> ApiResult { + let framework = match require_kv_framework_api(client, py) { + Ok(v) => v, + Err(e) => return ApiResult::new_error(e), + }; + if !framework.is_external_mode() { + return ApiResult::new_error(new_invalid_argument_error( + py, + "validate_gpu_destination is supported only in external-client mode", + )); + } + match framework + .client_seg_pool_view() + .client_transfer_engine() + .validate_gpu_destination(registration_id, ptr, capacity) + { + Ok(_guard) => ApiResult::new_success(0i32.into_py(py)), + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "validate_gpu_destination failed", + )), + } + } + + validate_gpu_destination_inner(self, registration_id, ptr, capacity, py).into_py_object(py) + } + /// Register a caller-owned host buffer range used by batch zero-copy paths. #[pyo3(signature = (ptr, len))] fn register_buffer(&self, ptr: u64, len: u64, py: Python) -> PyObject { diff --git a/setup_and_pack/nix/pack_fluxonkv_pylib.py b/setup_and_pack/nix/pack_fluxonkv_pylib.py index e12f8fe..cb0af6d 100644 --- a/setup_and_pack/nix/pack_fluxonkv_pylib.py +++ b/setup_and_pack/nix/pack_fluxonkv_pylib.py @@ -198,6 +198,11 @@ def _cleanup_temp_workspace_mount_dirs() -> None: "libstdc++.so.6", "libgomp.so.1", ) +EXTERNAL_DRIVER_RUNTIME_LIBRARY_NAMES = ( + # libcuda is supplied by the NVIDIA kernel-driver installation on the target GPU node. + # Packaging the build-time stub would make the wheel non-functional at runtime. + "libcuda.so.1", +) def _dedupe_relative_paths(relative_paths: tuple[str, ...]) -> tuple[str, ...]: ordered_relative_paths: list[str] = [] @@ -2273,6 +2278,10 @@ def _is_core_system_runtime_lib(lib_name: str) -> bool: return any(lib_name.startswith(prefix) for prefix in CORE_SYSTEM_RUNTIME_LIB_PREFIXES) +def _is_external_driver_runtime_lib(lib_name: str) -> bool: + return lib_name in EXTERNAL_DRIVER_RUNTIME_LIBRARY_NAMES + + def _read_runtime_dependency_entries( path: Path, *, @@ -2314,6 +2323,12 @@ def _read_runtime_dependency_entries( if "=>" in line: needed_name, raw_target = (part.strip() for part in line.split("=>", 1)) if raw_target == "not found": + if _is_external_driver_runtime_lib(needed_name): + print( + "wheel finalize: leaving target-driver dependency external: " + f"{path} -> {needed_name}" + ) + continue raise RuntimeError(f"runtime dependency not found for {path}: {needed_name}") dep_path_str = raw_target.split(" ", 1)[0].strip() else: diff --git a/setup_and_pack/tests/test_vendor_runtime_layout.py b/setup_and_pack/tests/test_vendor_runtime_layout.py index 48f87be..52eac3d 100644 --- a/setup_and_pack/tests/test_vendor_runtime_layout.py +++ b/setup_and_pack/tests/test_vendor_runtime_layout.py @@ -33,6 +33,15 @@ def _load_module(module_path: Path, module_name: str): class VendorRuntimeLayoutTest(unittest.TestCase): + def test_cuda_driver_is_external_but_cuda_runtime_is_packaged(self) -> None: + for module_path in PACKER_MODULE_PATHS: + mod = _load_module( + module_path=module_path, + module_name=f"vendor_runtime_cuda_external_{module_path.stem}", + ) + self.assertTrue(mod._is_external_driver_runtime_lib("libcuda.so.1")) + self.assertFalse(mod._is_external_driver_runtime_lib("libcudart.so.12")) + def test_ensure_vendor_runtime_soname_aliases_materializes_missing_alias_files(self) -> None: with tempfile.TemporaryDirectory() as tmpdir: root = Path(tmpdir) From 0bc5524f5fc2551a712638375c6d02911524d836 Mon Sep 17 00:00:00 2001 From: zTz01 <1773266173@qq.com> Date: Fri, 24 Jul 2026 19:04:31 +0800 Subject: [PATCH 09/10] backup gdr --- fluxon_py/kvclient/fluxon.py | 294 ++- .../src/client_kv_api/external_api.rs | 454 +++- fluxon_rs/fluxon_kv/src/client_kv_api/get.rs | 57 +- fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs | 196 +- .../fluxon_kv/src/client_kv_api/msg_pack.rs | 164 +- .../fluxon_kv/src/external_client_api/mod.rs | 2229 +++++++++++++++-- .../fluxon_kv/src/master_kv_router/get.rs | 696 ++++- .../fluxon_kv/src/master_kv_router/mod.rs | 167 +- .../src/master_kv_router/msg_pack.rs | 137 + .../rpcresp_kvresult_convert/msg_and_error.rs | 7 + .../fluxon_pyo3/src/fixed_slab_allocator.rs | 52 + fluxon_rs/fluxon_pyo3/src/lib.rs | 275 ++ .../fluxon_util/src/fixed_slab_allocator.rs | 245 ++ fluxon_rs/fluxon_util/src/lib.rs | 1 + 14 files changed, 4741 insertions(+), 233 deletions(-) create mode 100644 fluxon_rs/fluxon_pyo3/src/fixed_slab_allocator.rs create mode 100644 fluxon_rs/fluxon_util/src/fixed_slab_allocator.rs diff --git a/fluxon_py/kvclient/fluxon.py b/fluxon_py/kvclient/fluxon.py index 1602e88..25f3776 100644 --- a/fluxon_py/kvclient/fluxon.py +++ b/fluxon_py/kvclient/fluxon.py @@ -293,6 +293,25 @@ class GpuGetStartHandle: created_at_ns: int backend_token: int backend_handle: int + remote_indices: Tuple[int, ...] + closed: bool = False + transfer_wall_us: Optional[int] = None + finish_wait_us: Optional[int] = None + terminal_before_consume: Optional[bool] = None + terminal_to_consume_us: Optional[int] = None + + +@dataclass +class GetPlanHandle: + """Target-free Get plan that must be executed once or cancelled.""" + + keys: Tuple[str, ...] + result: GetStartResult + gpu_result: GetStartResult + created_at_ns: int + backend_token: int + backend_handle: int + gpu_remote_indices: Tuple[int, ...] closed: bool = False @@ -376,6 +395,34 @@ def _build_get_start_result_from_backend_payload( ) +def _narrow_get_start_result(result: GetStartResult, consume_prefix_len: int) -> GetStartResult: + group_lens = result.atomic_group_lens or (len(result.keys),) + selected_groups: List[int] = [] + cursor = 0 + for group_len in group_lens: + if cursor + group_len > consume_prefix_len: + break + selected_groups.append(int(group_len)) + cursor += int(group_len) + if cursor != consume_prefix_len: + raise ValueError( + "consume_prefix_len must end at an atomic-group boundary: " + f"consume={consume_prefix_len} groups={group_lens}" + ) + keys = result.keys[:consume_prefix_len] + return GetStartResult( + keys=keys, + raw_prefix_hit_len=consume_prefix_len, + transferable_len=consume_prefix_len, + prefix_hit_groups=len(selected_groups), + atomic_group_lens=tuple(selected_groups), + prefix_best_effort=result.prefix_best_effort, + first_miss_index=None, + first_miss_group_index=None, + all_hit=True, + ) + + def _error_to_ret_code(err: ApiError) -> int: if hasattr(err, "code") and callable(err.code): try: @@ -1935,6 +1982,218 @@ def get_start( backend_handle=backend_handle, ) + def get_plan( + self, + keys: List[str], + prefix_best_effort: bool = True, + atomic_group_lens: Optional[List[int]] = None, + ) -> GetPlanHandle: + if self._client is None: + raise RuntimeError("Store not initialized when get_plan(). Call setup() first.") + if not keys: + raise ValueError("get_plan requires at least one key") + normalized_group_lens: Optional[List[int]] = None + if atomic_group_lens is not None: + normalized_group_lens = [int(length) for length in atomic_group_lens] + if any(length <= 0 for length in normalized_group_lens): + raise ValueError("get_plan atomic_group_lens entries must be > 0") + if sum(normalized_group_lens) != len(keys): + raise ValueError( + "get_plan atomic_group_lens must sum to keys length: " + f"sum={sum(normalized_group_lens)} keys={len(keys)}" + ) + started_at_ns = time.monotonic_ns() + inner_res = self._client.get_plan( + list(keys), + bool(prefix_best_effort), + normalized_group_lens, + ) + if not inner_res.is_ok(): + raise RuntimeError(f"get_plan backend error: {inner_res.unwrap_error()}") + payload = inner_res.unwrap() + if not isinstance(payload, dict): + raise RuntimeError(f"get_plan returned non-dict payload: {type(payload)}") + backend_handle = int(payload["handle"]) + try: + result = _build_get_start_result_from_backend_payload( + payload, + list(keys), + bool(prefix_best_effort), + normalized_group_lens, + ) + gpu_payload = dict(payload) + gpu_payload["raw_prefix_hit_len"] = payload["gpu_raw_prefix_hit_len"] + gpu_result = _build_get_start_result_from_backend_payload( + gpu_payload, + list(keys), + bool(prefix_best_effort), + normalized_group_lens, + ) + gpu_remote_indices = tuple(int(index) for index in payload["gpu_remote_indices"]) + if ( + tuple(sorted(set(gpu_remote_indices))) != gpu_remote_indices + or any( + index < 0 or index >= gpu_result.transferable_len + for index in gpu_remote_indices + ) + ): + raise RuntimeError( + "get_plan returned invalid gpu_remote_indices: " + f"indices={gpu_remote_indices} " + f"transferable={gpu_result.transferable_len}" + ) + except Exception: + cancel_res = self._client.cancel_get_plan(backend_handle) + if not cancel_res.is_ok(): + logging.exception( + "get_plan payload validation failed and cleanup also failed: %s", + cancel_res.unwrap_error(), + ) + else: + _ = cancel_res.unwrap() + raise + return GetPlanHandle( + keys=tuple(keys), + result=result, + gpu_result=gpu_result, + created_at_ns=started_at_ns, + backend_token=id(self), + backend_handle=backend_handle, + gpu_remote_indices=gpu_remote_indices, + ) + + def cancel_get_plan(self, handle: GetPlanHandle) -> None: + if not isinstance(handle, GetPlanHandle): + raise TypeError(f"cancel_get_plan requires GetPlanHandle, got {type(handle)}") + if handle.backend_token != id(self): + raise RuntimeError("cancel_get_plan handle belongs to a different store") + if handle.closed: + return + if self._client is None: + raise RuntimeError("Store not initialized when cancel_get_plan().") + inner_res = self._client.cancel_get_plan(handle.backend_handle) + if not inner_res.is_ok(): + raise RuntimeError(f"cancel_get_plan backend error: {inner_res.unwrap_error()}") + _ = inner_res.unwrap() + handle.closed = True + + def execute_get_plan_cpu( + self, + handle: GetPlanHandle, + *, + consume_prefix_len: int, + concurrency: Optional[int] = None, + ) -> GetStartHandle: + if not isinstance(handle, GetPlanHandle): + raise TypeError( + f"execute_get_plan_cpu requires GetPlanHandle, got {type(handle)}" + ) + if handle.backend_token != id(self) or handle.closed: + raise RuntimeError("execute_get_plan_cpu requires a live plan from this store") + narrowed = _narrow_get_start_result(handle.result, int(consume_prefix_len)) + if consume_prefix_len <= 0 or consume_prefix_len > handle.result.transferable_len: + raise ValueError( + "execute_get_plan_cpu consume prefix is outside the CPU plan: " + f"consume={consume_prefix_len} transferable={handle.result.transferable_len}" + ) + if self._client is None: + raise RuntimeError("Store not initialized when execute_get_plan_cpu().") + inner_res = self._client.execute_get_plan_cpu( + handle.backend_handle, + int(consume_prefix_len), + self._batch_concurrency if concurrency is None else int(concurrency), + ) + if not inner_res.is_ok(): + raise RuntimeError( + f"execute_get_plan_cpu backend error: {inner_res.unwrap_error()}" + ) + _ = inner_res.unwrap() + handle.closed = True + return GetStartHandle( + keys=narrowed.keys, + result=narrowed, + created_at_ns=handle.created_at_ns, + backend_token=id(self), + backend_handle=handle.backend_handle, + ) + + def execute_get_plan_gpu( + self, + handle: GetPlanHandle, + destinations: List[GpuDestination], + *, + consume_prefix_len: int, + concurrency: Optional[int] = None, + ) -> GpuGetStartHandle: + if not isinstance(handle, GetPlanHandle): + raise TypeError( + f"execute_get_plan_gpu requires GetPlanHandle, got {type(handle)}" + ) + if handle.backend_token != id(self) or handle.closed: + raise RuntimeError("execute_get_plan_gpu requires a live plan from this store") + remote_indices = tuple( + index for index in handle.gpu_remote_indices if index < consume_prefix_len + ) + if not remote_indices: + raise ValueError("execute_get_plan_gpu requires at least one remote source") + if len(destinations) != len(remote_indices): + raise ValueError( + "execute_get_plan_gpu requires one exact destination per remote source: " + f"destinations={len(destinations)} remote={len(remote_indices)} " + f"consume={consume_prefix_len}" + ) + narrowed = _narrow_get_start_result(handle.gpu_result, int(consume_prefix_len)) + if consume_prefix_len <= 0 or consume_prefix_len > handle.gpu_result.transferable_len: + raise ValueError( + "execute_get_plan_gpu consume prefix is outside the GPU plan: " + f"consume={consume_prefix_len} transferable={handle.gpu_result.transferable_len}" + ) + active_registration = self._gpu_buffer_registration + if active_registration is None: + raise RuntimeError("execute_get_plan_gpu requires an active GPU registration") + for index, destination in enumerate(destinations): + if not isinstance(destination, GpuDestination): + raise TypeError( + "execute_get_plan_gpu destinations must be GpuDestination: " + f"index={index} got={type(destination)}" + ) + if destination.registration_id != active_registration.registration_id: + raise ValueError( + "execute_get_plan_gpu destination uses a stale registration: " + f"index={index}" + ) + if destination.ptr < active_registration.ptr or destination.end > active_registration.end: + raise ValueError( + "execute_get_plan_gpu destination is outside the active registration: " + f"index={index}" + ) + if self._client is None: + raise RuntimeError("Store not initialized when execute_get_plan_gpu().") + inner_res = self._client.execute_get_plan_gpu( + handle.backend_handle, + [ + (destination.registration_id, destination.ptr, destination.capacity) + for destination in destinations + ], + int(consume_prefix_len), + self._batch_concurrency if concurrency is None else int(concurrency), + ) + if not inner_res.is_ok(): + raise RuntimeError( + f"execute_get_plan_gpu backend error: {inner_res.unwrap_error()}" + ) + _ = inner_res.unwrap() + handle.closed = True + return GpuGetStartHandle( + keys=narrowed.keys, + destinations=tuple(destinations), + result=narrowed, + created_at_ns=handle.created_at_ns, + backend_token=id(self), + backend_handle=handle.backend_handle, + remote_indices=remote_indices, + ) + def cancel_get_transfer(self, handle: GetStartHandle) -> None: if not isinstance(handle, GetStartHandle): raise TypeError(f"cancel_get_transfer requires GetStartHandle, got {type(handle)}") @@ -2121,6 +2380,8 @@ def get_start_gpu( "get_start_gpu payload validation failed and cleanup also failed: %s", cancel_res.unwrap_error(), ) + else: + _ = cancel_res.unwrap() raise return GpuGetStartHandle( keys=tuple(keys), @@ -2129,6 +2390,7 @@ def get_start_gpu( created_at_ns=started_at_ns, backend_token=id(self), backend_handle=backend_handle, + remote_indices=tuple(range(result.transferable_len)), ) def cancel_get_transfer_gpu(self, handle: GpuGetStartHandle) -> None: @@ -2152,14 +2414,15 @@ def cancel_get_transfer_gpu(self, handle: GpuGetStartHandle) -> None: raise RuntimeError( f"cancel_get_transfer_gpu backend error: {inner_res.unwrap_error()}" ) + _ = inner_res.unwrap() def get_transfer_gpu( self, handle: GpuGetStartHandle, *, consume_prefix_len: Optional[int] = None, - ) -> None: - """Wait for the GPU transfer terminal; destinations already contain the bytes.""" + ) -> int: + """Wait for GPU transfer and return one ordered CPU/GPU source plan.""" if not isinstance(handle, GpuGetStartHandle): raise TypeError( f"get_transfer_gpu requires GpuGetStartHandle, got {type(handle)}" @@ -2227,6 +2490,33 @@ def get_transfer_gpu( f"transferred={transferred_prefix_len}/{result.transferable_len} " f"consumed={consumed_prefix_len}/{normalized_consume_prefix_len}" ) + transfer_wall_us = payload["transfer_wall_us"] + finish_wait_us = payload["finish_wait_us"] + terminal_before_consume = payload["terminal_before_consume"] + terminal_to_consume_us = payload["terminal_to_consume_us"] + for field_name, value in ( + ("transfer_wall_us", transfer_wall_us), + ("finish_wait_us", finish_wait_us), + ("terminal_to_consume_us", terminal_to_consume_us), + ): + if type(value) is not int or value < 0: + raise RuntimeError( + "get_transfer_gpu returned invalid timing: " + f"{field_name}={value!r}" + ) + if type(terminal_before_consume) is not bool: + raise RuntimeError( + "get_transfer_gpu returned invalid terminal_before_consume: " + f"{terminal_before_consume!r}" + ) + handle.transfer_wall_us = transfer_wall_us + handle.finish_wait_us = finish_wait_us + handle.terminal_before_consume = terminal_before_consume + handle.terminal_to_consume_us = terminal_to_consume_us + plan_ptr = int(payload["plan_ptr"]) + if plan_ptr <= 0: + raise RuntimeError(f"get_transfer_gpu returned invalid plan_ptr: {plan_ptr}") + return plan_ptr def get_etcd_config(self) -> List[str]: if self._client is None: diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs index 22b4882..e6f3caa 100755 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs @@ -2,17 +2,18 @@ use crate::client_kv_api::ClientKvApi; use crate::client_kv_api::get::{StartedGetRevokeCleanup, finish_started_get_revoke_cleanup}; use crate::client_kv_api::msg_pack::{ ExternalBatchGetCancelPlan, ExternalBatchGetCancelReq, ExternalBatchGetCancelResp, - ExternalBatchGetItemResp, ExternalBatchGetReq, ExternalBatchGetResp, ExternalBatchGetStartReq, - ExternalBatchGetStartResp, ExternalBatchGetStartTransferPlan, ExternalBatchGetTransferReq, - ExternalBatchGetTransferResp, ExternalBatchIsExistReq, ExternalBatchIsExistResp, - ExternalBatchPutCommitItemResp, ExternalBatchPutCommitReq, ExternalBatchPutCommitResp, - ExternalBatchPutStartItemResp, ExternalBatchPutStartReq, ExternalBatchPutStartResp, - ExternalBatchPutTransferEndItemResp, ExternalBatchPutTransferEndReq, - ExternalBatchPutTransferEndResp, ExternalDeleteReq, ExternalDeleteResp, ExternalGetReq, - ExternalGetResp, ExternalIsExistReq, ExternalIsExistResp, ExternalObservabilitySnapshotReq, - ExternalObservabilitySnapshotResp, ExternalPutCommitReq, ExternalPutCommitResp, - ExternalPutRevokeReq, ExternalPutRevokeResp, ExternalPutStartReq, ExternalPutStartResp, - ExternalPutTransferEndReq, ExternalPutTransferEndResp, TestPutPhaseTrace, + ExternalBatchGetItemResp, ExternalBatchGetLocalProbeReq, ExternalBatchGetLocalProbeResp, + ExternalBatchGetReq, ExternalBatchGetResp, ExternalBatchGetStartReq, ExternalBatchGetStartResp, + ExternalBatchGetStartTransferPlan, ExternalBatchGetTransferReq, ExternalBatchGetTransferResp, + ExternalBatchIsExistReq, ExternalBatchIsExistResp, ExternalBatchPutCommitItemResp, + ExternalBatchPutCommitReq, ExternalBatchPutCommitResp, ExternalBatchPutStartItemResp, + ExternalBatchPutStartReq, ExternalBatchPutStartResp, ExternalBatchPutTransferEndItemResp, + ExternalBatchPutTransferEndReq, ExternalBatchPutTransferEndResp, ExternalDeleteReq, + ExternalDeleteResp, ExternalExecutePlannedGetReq, ExternalExecutePlannedGetResp, + ExternalGetReq, ExternalGetResp, ExternalIsExistReq, ExternalIsExistResp, + ExternalObservabilitySnapshotReq, ExternalObservabilitySnapshotResp, ExternalPutCommitReq, + ExternalPutCommitResp, ExternalPutRevokeReq, ExternalPutRevokeResp, ExternalPutStartReq, + ExternalPutStartResp, ExternalPutTransferEndReq, ExternalPutTransferEndResp, TestPutPhaseTrace, }; use crate::client_kv_api::{ self, ExternalGetKeyInterest, ExternalGetKeySharedOp, ExternalGetKeySharedPhase, @@ -838,6 +839,84 @@ async fn batch_get_start_with_local_reserve_targets( Ok(response) } +async fn batch_get_bind_with_local_reserve_targets( + inner: &client_kv_api::ClientKvApiInner, + get_ids: &[u64], +) -> KvResult> { + if get_ids.is_empty() { + return Ok(Vec::new()); + } + let Some(value_len) = inner + .test_spec_config + .owner_local_reserve_expected_capacity + .as_ref() + .map(|expected| expected.value_len) + else { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: "planned external Get requires owner-local reserve capacity".to_string(), + })); + }; + let lease = inner + .owner_claim_local_reserve_slot_lease(value_len, get_ids.len()) + .await?; + let mut claim_guard = PreparedGetSlotClaimGuard::new(inner.view.clone_view(), lease); + let prepared_targets = claim_guard + .lease() + .slots + .iter() + .map(|slot| prepared_target_from_slot(claim_guard.lease().slot_size, slot)) + .collect::>(); + let response = match inner + .batch_get_bind_prepared_targets(get_ids.to_vec(), prepared_targets.clone()) + .await + { + Ok(response) => { + claim_guard.mark_start_response_received(); + response + } + Err(err) => return Err(err), + }; + if response.items.len() != get_ids.len() { + let started = claim_guard.handoff_started(&response.items); + finish_started_get_revoke_cleanup(inner, started, "BatchGetBind length mismatch").await; + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "planned BatchGetBind response length mismatch: expected={} got={}", + get_ids.len(), + response.items.len() + ), + })); + } + let identities_match = response + .items + .iter() + .zip(get_ids) + .all(|(item, get_id)| item.get_id == *get_id); + let targets_match = + response + .items + .iter() + .zip(prepared_targets.iter()) + .all(|(item, expected)| { + item.error_code != OK || item.prepared_target.as_ref() == Some(expected) + }); + if !identities_match || !targets_match { + let started = claim_guard.handoff_started(&response.items); + finish_started_get_revoke_cleanup(inner, started, "BatchGetBind identity/target mismatch") + .await; + return Err(KvError::Api(ApiError::Unknown { + detail: "master did not replay the exact planned Get identity and prepared target" + .to_string(), + })); + } + for (item, target) in response.items.iter().zip(prepared_targets.iter()) { + if item.error_code == OK { + claim_guard.disarm_accepted(target); + } + } + Ok(response.items) +} + #[cfg(test)] mod external_put_pending_tests { use super::{ExternalPutStartFenceClaim, require_external_pending_put_ctx_value}; @@ -2626,6 +2705,10 @@ pub trait HandlerForExternalClient { fn validate_requester_owner_status_updated(&self, started_time: i64) -> KvResult<()>; async fn external_get(&self, req: ExternalGetReq) -> KvResult; async fn external_batch_get(&self, req: ExternalBatchGetReq) -> KvResult; + async fn external_batch_get_local_probe( + &self, + req: ExternalBatchGetLocalProbeReq, + ) -> KvResult; async fn external_batch_get_start( &self, req: ExternalBatchGetStartReq, @@ -2638,6 +2721,10 @@ pub trait HandlerForExternalClient { &self, req: ExternalBatchGetCancelReq, ) -> KvResult; + async fn external_execute_planned_get( + &self, + req: ExternalExecutePlannedGetReq, + ) -> KvResult; async fn external_put_start(&self, req: ExternalPutStartReq) -> KvResult; async fn external_batch_put_start( &self, @@ -2763,6 +2850,118 @@ impl HandlerForExternalClient for ClientKvApi { }) } + async fn external_batch_get_local_probe( + &self, + req: ExternalBatchGetLocalProbeReq, + ) -> KvResult { + if self.is_side_transfer_worker() { + return Err(Self::side_transfer_unsupported( + "external_batch_get_local_probe", + )); + } + if req.keys.is_empty() { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: "external_batch_get_local_probe requires at least one key".to_string(), + })); + } + if req.plan_handle == 0 { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: "external_batch_get_local_probe requires a non-zero plan_handle" + .to_string(), + })); + } + self.validate_requester_owner_status_updated(req.started_time)?; + let inner = self.inner(); + let identity = (req.req_node_id.clone(), req.started_time, req.plan_handle); + let operation_lock = inner + .external_get_local_probe_locks + .get_lock(identity.clone()); + let _operation_guard = operation_lock.lock().await; + if let Some((completed_keys, completed)) = inner + .completed_external_get_local_probes + .get(&identity) + .await + { + if completed_keys != req.keys { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "external_batch_get_local_probe operation identity was reused with different keys: plan_handle={}", + req.plan_handle + ), + })); + } + return Ok(completed); + } + let mut items = Vec::with_capacity(req.keys.len()); + let mut hot_touches = Vec::new(); + for key in &req.keys { + let (item, hot_touch) = { + let controls = inner.owner_key_control.lock_key(key); + if controls + .get(key) + .is_some_and(|state| state.local_access_fenced()) + { + (None, None) + } else if let Some(memory_info) = inner.local_visible_mem_holder_unfenced(key) { + let hot_touch = inner.get_cached_info.get(key).and_then(|cached| { + Arc::ptr_eq(&cached.mem_holder, &memory_info).then_some(( + (cached.put_time_ms, cached.put_version), + memory_info.clone(), + )) + }); + // Install the holder under the same per-key fence used for + // local visibility. Reclaim cannot slip between the probe + // decision and the pin that owns this exact backing. + let info = inner.install_external_get_holding(&req.req_node_id, memory_info); + (Some(info), hot_touch) + } else { + (None, None) + } + }; + if let Some((put_id, memory_info)) = hot_touch { + hot_touches.push((key.clone(), put_id, memory_info)); + } + items.push(item); + } + for (key, put_id, memory_info) in hot_touches { + inner.owner_hot_touch_or_promote(&key, put_id, &memory_info); + } + let local_items = items.iter().filter(|item| item.is_some()).count(); + let remote_items = items.len().saturating_sub(local_items); + inner + .planned_get_counters + .local_probe_batches + .fetch_add(1, Ordering::Relaxed); + inner + .planned_get_counters + .local_probe_items + .fetch_add(items.len() as u64, Ordering::Relaxed); + inner + .planned_get_counters + .local_probe_local_items + .fetch_add(local_items as u64, Ordering::Relaxed); + inner + .planned_get_counters + .local_probe_remote_items + .fetch_add(remote_items as u64, Ordering::Relaxed); + tracing::debug!( + requested = req.keys.len(), + local = local_items, + remote = remote_items, + "external Get owner-local probe" + ); + let response = ExternalBatchGetLocalProbeResp { + items, + error_code: OK, + error_json: String::new(), + }; + inner + .completed_external_get_local_probes + .insert(identity, (req.keys, response.clone())) + .await; + Ok(response) + } + async fn external_batch_get_start( &self, req: ExternalBatchGetStartReq, @@ -3027,6 +3226,239 @@ impl HandlerForExternalClient for ClientKvApi { }) } + async fn external_execute_planned_get( + &self, + req: ExternalExecutePlannedGetReq, + ) -> KvResult { + if self.is_side_transfer_worker() { + return Err(Self::side_transfer_unsupported( + "external_execute_planned_get", + )); + } + if req.items.is_empty() || req.transfer_concurrency == 0 { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "external_execute_planned_get requires non-empty items and positive concurrency: items={} concurrency={}", + req.items.len(), + req.transfer_concurrency + ), + })); + } + let inner = self.inner(); + self.validate_requester_owner_status_updated(req.started_time)?; + let identity = (req.req_node_id.clone(), req.started_time, req.plan_handle); + let operation_lock = inner + .planned_external_get_execute_locks + .get_lock(identity.clone()); + let _operation_guard = operation_lock.lock().await; + if let Some(completed) = inner + .completed_planned_external_get_executes + .get(&identity) + .await + { + return Ok(completed); + } + + let mut requested_by_key = HashMap::with_capacity(req.items.len()); + for item in &req.items { + if item.key.is_empty() + || requested_by_key + .insert(item.key.clone(), item.get_id) + .is_some() + { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "external_execute_planned_get requires unique non-empty keys: plan_handle={}", + req.plan_handle + ), + })); + } + } + let keys = req + .items + .iter() + .map(|item| item.key.clone()) + .collect::>(); + let (mut owner_items, leaders) = plan_external_get_key_items(inner, &keys).await; + let local_items = owner_items + .iter() + .filter(|item| matches!(item, ExternalGetStartOwnerItem::Local { .. })) + .count(); + let leader_items = leaders.len(); + let follower_items = owner_items + .len() + .saturating_sub(local_items) + .saturating_sub(leader_items); + inner + .planned_get_counters + .batches + .fetch_add(1, Ordering::Relaxed); + inner + .planned_get_counters + .local_items + .fetch_add(local_items as u64, Ordering::Relaxed); + inner + .planned_get_counters + .leader_items + .fetch_add(leader_items as u64, Ordering::Relaxed); + inner + .planned_get_counters + .follower_items + .fetch_add(follower_items as u64, Ordering::Relaxed); + tracing::info!( + plan_handle = req.plan_handle, + items = owner_items.len(), + local_items, + leader_items, + follower_items, + "planned CPU Get owner classification" + ); + let leader_get_ids = leaders + .iter() + .map(|leader| { + requested_by_key + .get(&leader.key) + .copied() + .expect("planned leader key must come from the request") + }) + .collect::>(); + let leader_id_set = leader_get_ids + .iter() + .copied() + .collect::>(); + let mut cleanup = req + .items + .iter() + .filter(|item| !leader_id_set.contains(&item.get_id)) + .map(|item| StartedGetRevokeCleanup { + get_id: item.get_id, + prepared_target: None, + }) + .collect::>(); + + let bound_items = + match batch_get_bind_with_local_reserve_targets(inner, &leader_get_ids).await { + Ok(items) => items, + Err(err) => { + for leader in &leaders { + publish_external_get_key_failed(inner, leader, &err); + } + cleanup.extend(leader_get_ids.into_iter().map(|get_id| { + StartedGetRevokeCleanup { + get_id, + prepared_target: None, + } + })); + finish_started_get_revoke_cleanup( + inner, + cleanup, + "planned external Get bind failure", + ) + .await; + let response = ExternalExecutePlannedGetResp { + items: Vec::new(), + error_code: err.code(), + error_json: err.to_json(), + }; + inner + .completed_planned_external_get_executes + .insert(identity, response.clone()) + .await; + return Ok(response); + } + }; + assert_eq!(leaders.len(), bound_items.len()); + for (leader, item) in leaders.iter().zip(bound_items) { + if item.error_code != OK { + cleanup.push(StartedGetRevokeCleanup { + get_id: item.get_id, + prepared_target: None, + }); + } + publish_external_get_key_started(leader, item); + } + for item in &mut owner_items { + decide_external_get_key_item(item, true); + } + + // From this point on the owner has published Started for every leader, + // so it must retain lifecycle ownership independently of the inbound + // RPC future. P2P timeout/cancellation drops the handler future; if + // finish lived on that future, the per-key marker would remain in + // Finishing forever and every replay would only become a follower. + // The registered owner task is process-scoped and therefore continues + // both transfer/Done and unused-operation cleanup after caller loss. + let spawn_view = inner.view.clone_view(); + let worker_view = spawn_view.clone(); + let finish_leaders = leaders; + let transfer_concurrency = req.transfer_concurrency; + let plan_handle = req.plan_handle; + spawn_view.spawn( + format!("planned_external_get_finish_{plan_handle}"), + async move { + let finish_view = worker_view.clone(); + let cleanup_view = worker_view; + let finish = finish_external_get_key_leaders( + finish_view, + finish_leaders, + transfer_concurrency, + ); + let cleanup_future = async move { + finish_started_get_revoke_cleanup( + cleanup_view.client_kv_api().inner(), + cleanup, + "planned external Get unused operation", + ) + .await; + }; + tokio::join!(finish, cleanup_future); + }, + ); + + let transfer_results = + finish_external_get_start_transfer(inner.view.clone_view(), owner_items, 0).await?; + if transfer_results.len() != keys.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "planned external Get result length mismatch: expected={} got={}", + keys.len(), + transfer_results.len() + ), + })); + } + let mut items = Vec::with_capacity(keys.len()); + for (key, result) in keys.iter().zip(transfer_results) { + match result { + Ok(Some((holder, _))) => items.push(ExternalBatchGetItemResp { + error_code: OK, + error_json: String::new(), + external_memholder_info: Some( + inner.install_external_get_holding(&req.req_node_id, holder.memory_info()), + ), + }), + Ok(None) => items.push(ExternalBatchGetItemResp { + error_code: codes_api::API_KEY_NOT_FOUND, + error_json: format!("Key not found: {key}"), + external_memholder_info: None, + }), + Err(err) => items.push(ExternalBatchGetItemResp { + external_memholder_info: None, + ..ExternalBatchGetItemResp::from_error(&err) + }), + } + } + let response = ExternalExecutePlannedGetResp { + items, + error_code: OK, + error_json: String::new(), + }; + inner + .completed_planned_external_get_executes + .insert(identity, response.clone()) + .await; + Ok(response) + } + async fn external_batch_get_cancel( &self, req: ExternalBatchGetCancelReq, diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs index 9e1c6a9..35e2dd4 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs @@ -14,10 +14,11 @@ use crate::observe_kvope::{ use crate::{ cluster_manager::NodeID, master_kv_router::msg_pack::{ - BatchGetDoneReq, BatchGetDoneResp, BatchGetRevokeReq, BatchGetRevokeResp, - BatchGetStartItemResp, BatchGetStartReq, BatchGetStartResp, BatchIsExistReq, - GetAllocationMode, GetDoneReq, GetDoneResp, GetMetaReq, GetMetaResp, - GetPreparedLocalReserveTarget, GetRevokeReq, GetStartReq, GetStartResp, + BatchGetBindItemReq, BatchGetBindReq, BatchGetBindResp, BatchGetDoneReq, BatchGetDoneResp, + BatchGetRevokeReq, BatchGetRevokeResp, BatchGetStartItemResp, BatchGetStartReq, + BatchGetStartResp, BatchIsExistReq, GetAllocationMode, GetBindTarget, GetDoneReq, + GetDoneResp, GetMetaReq, GetMetaResp, GetPreparedLocalReserveTarget, GetRevokeReq, + GetStartReq, GetStartResp, }, p2p::msg_pack::MsgPack, rpcresp_kvresult_convert::msg_and_error::codes_api, @@ -1486,6 +1487,54 @@ impl ClientKvApiInner { Ok(resp.serialize_part) } + pub(crate) async fn batch_get_bind_prepared_targets( + &self, + get_ids: Vec, + prepared_targets: Vec, + ) -> KvResult { + if get_ids.len() != prepared_targets.len() { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "batch_get_bind_prepared_targets length mismatch: get_ids={} targets={}", + get_ids.len(), + prepared_targets.len() + ), + })); + } + let items = get_ids + .into_iter() + .zip(prepared_targets) + .map(|(get_id, target)| BatchGetBindItemReq { + get_id, + target: GetBindTarget::PreparedLocalReserve(target), + }) + .collect(); + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let resp = self + .rpc_caller_batch_get_bind + .call( + self.view.p2p_module(), + master_node_id.into(), + MsgPack { + serialize_part: BatchGetBindReq { items }, + raw_bytes: Vec::new(), + }, + None, + 0, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + Ok(resp.serialize_part) + } + /// 撤销 Get 操作,释放已分配的资源 pub async fn get_revoke(&self, get_id: u64) -> KvResult<()> { let req = MsgPack { diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs index fd5a06e..6d59d5f 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs @@ -4,28 +4,29 @@ use crate::client_kv_api::local_reserve_rebalance::{ }; use crate::client_kv_api::msg_pack::{ ExternalBatchDeleteAckReq, ExternalBatchDeleteAckResp, ExternalBatchGetCancelReq, - ExternalBatchGetCancelResp, ExternalBatchGetReq, ExternalBatchGetResp, - ExternalBatchGetStartReq, ExternalBatchGetStartResp, ExternalBatchGetTransferReq, - ExternalBatchGetTransferResp, ExternalBatchIsExistReq, ExternalBatchIsExistResp, - ExternalBatchPutCommitReq, ExternalBatchPutCommitResp, ExternalBatchPutStartReq, - ExternalBatchPutStartResp, ExternalBatchPutTransferEndReq, ExternalBatchPutTransferEndResp, - ExternalDeleteAckReq, ExternalDeleteAckResp, ExternalDeleteReq, ExternalDeleteResp, - ExternalGetReq, ExternalGetResp, ExternalIsExistReq, ExternalIsExistResp, - ExternalObservabilitySnapshotReq, ExternalObservabilitySnapshotResp, ExternalPutCommitReq, - ExternalPutCommitResp, ExternalPutRevokeReq, ExternalPutRevokeResp, ExternalPutStartReq, - ExternalPutStartResp, ExternalPutTransferEndReq, ExternalPutTransferEndResp, SyncKvToFileReq, - SyncKvToFileResp, TestPutPhaseTrace, + ExternalBatchGetCancelResp, ExternalBatchGetLocalProbeReq, ExternalBatchGetLocalProbeResp, + ExternalBatchGetReq, ExternalBatchGetResp, ExternalBatchGetStartReq, ExternalBatchGetStartResp, + ExternalBatchGetTransferReq, ExternalBatchGetTransferResp, ExternalBatchIsExistReq, + ExternalBatchIsExistResp, ExternalBatchPutCommitReq, ExternalBatchPutCommitResp, + ExternalBatchPutStartReq, ExternalBatchPutStartResp, ExternalBatchPutTransferEndReq, + ExternalBatchPutTransferEndResp, ExternalDeleteAckReq, ExternalDeleteAckResp, + ExternalDeleteReq, ExternalDeleteResp, ExternalExecutePlannedGetReq, + ExternalExecutePlannedGetResp, ExternalGetReq, ExternalGetResp, ExternalIsExistReq, + ExternalIsExistResp, ExternalObservabilitySnapshotReq, ExternalObservabilitySnapshotResp, + ExternalPutCommitReq, ExternalPutCommitResp, ExternalPutRevokeReq, ExternalPutRevokeResp, + ExternalPutStartReq, ExternalPutStartResp, ExternalPutTransferEndReq, + ExternalPutTransferEndResp, SyncKvToFileReq, SyncKvToFileResp, TestPutPhaseTrace, }; use crate::client_kv_api::reclaim::handle_batch_owner_reclaim; use crate::cluster_manager::{NodeID, NodeIDString}; use crate::config::TestSpecConfig; use crate::master_kv_router::msg_pack::{ BatchDeleteAckReq, BatchDeleteClientKvMetaCacheReq, BatchEnqueueReplicaTaskReq, - BatchEvictOwnerSourceReq, BatchGetDoneReq, BatchGetRevokeReq, BatchGetStartItemResp, - BatchGetStartReq, BatchIsExistReq, BatchOwnerReclaimReq, BatchPreparePutKeysReq, - BatchPutAppendDoneReq, BatchPutAppendStartReq, BatchPutDoneReq, BatchPutRevokeReq, - BatchPutStartReq, BatchReleasePutKeyReservationsReq, DeleteClientKvMetaCacheItem, - GroupedBatchPutDoneReq, + BatchEvictOwnerSourceReq, BatchGetBindReq, BatchGetDoneReq, BatchGetRevokeReq, + BatchGetStartItemResp, BatchGetStartReq, BatchIsExistReq, BatchOwnerReclaimReq, + BatchPreparePutKeysReq, BatchPutAppendDoneReq, BatchPutAppendStartReq, BatchPutDoneReq, + BatchPutRevokeReq, BatchPutStartReq, BatchReleasePutKeyReservationsReq, + DeleteClientKvMetaCacheItem, GroupedBatchPutDoneReq, }; use crate::master_lease_manager::msg_pack::{AllocateClientLeaseReq, ClientLeaseKeepaliveReq}; use crate::memholder::{AllMemholderRefCount, ExternalMemHolderInfo, MemoryInfo, UserMemHolder}; @@ -95,6 +96,14 @@ pub struct OwnerRuntimeObserveSnapshot { pub external_get_flights_revoking: u64, pub external_get_undecided_interests: u64, pub external_get_retained_interests: u64, + pub owner_local_probe_batches: u64, + pub owner_local_probe_items: u64, + pub owner_local_probe_local_items: u64, + pub owner_local_probe_remote_items: u64, + pub planned_cpu_get_batches: u64, + pub planned_cpu_get_local_items: u64, + pub planned_cpu_get_leader_items: u64, + pub planned_cpu_get_follower_items: u64, pub external_pending_put_entries: u64, pub remote_put_flights_active: u64, pub remote_put_flight_leaders: u64, @@ -631,6 +640,33 @@ async fn handle_external_batch_get( } } +async fn handle_external_batch_get_local_probe( + view: &ClientKvApiView, + msg: &MsgPack, +) -> MsgPack { + let req = msg.serialize_part.clone(); + let dbg_len = req.keys.len(); + let resp = view + .client_kv_api() + .external_batch_get_local_probe(req) + .await + .unwrap_or_else(|e| { + tracing::error!( + "handle_external_batch_get_local_probe error: {e}; batch_len={batch_len}", + batch_len = dbg_len + ); + ExternalBatchGetLocalProbeResp { + items: Vec::new(), + error_code: e.code(), + error_json: e.to_json(), + } + }); + MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + } +} + async fn handle_external_batch_get_start( view: &ClientKvApiView, msg: &MsgPack, @@ -680,6 +716,36 @@ async fn handle_external_batch_get_transfer( } } +async fn handle_external_execute_planned_get( + view: &ClientKvApiView, + msg: &MsgPack, +) -> MsgPack { + let req = msg.serialize_part.clone(); + let plan_handle = req.plan_handle; + let item_count = req.items.len(); + let resp = view + .client_kv_api() + .external_execute_planned_get(req) + .await + .unwrap_or_else(|err| { + tracing::error!( + "handle_external_execute_planned_get error: {}; plan_handle={} items={}", + err, + plan_handle, + item_count + ); + ExternalExecutePlannedGetResp { + items: Vec::new(), + error_code: err.code(), + error_json: err.to_json(), + } + }); + MsgPack { + serialize_part: resp, + raw_bytes: Vec::new(), + } +} + async fn handle_external_batch_get_cancel( view: &ClientKvApiView, msg: &MsgPack, @@ -1399,6 +1465,18 @@ struct OwnerRemotePutCounters { failed: AtomicU64, } +#[derive(Default)] +struct OwnerPlannedGetCounters { + local_probe_batches: AtomicU64, + local_probe_items: AtomicU64, + local_probe_local_items: AtomicU64, + local_probe_remote_items: AtomicU64, + batches: AtomicU64, + local_items: AtomicU64, + leader_items: AtomicU64, + follower_items: AtomicU64, +} + struct OwnerHotSelectionDebt { weight_bytes: u64, outstanding_bytes: Arc, @@ -2382,6 +2460,7 @@ pub struct ClientKvApiInner { Arc>>, owner_hot_counters: Arc, owner_remote_put_counters: Arc, + planned_get_counters: OwnerPlannedGetCounters, owner_hot_retry_queue: Arc, owner_hot_eviction_tx: tokio::sync::ampsc::UnboundedSender, owner_hot_eviction_rx: @@ -2401,6 +2480,12 @@ pub struct ClientKvApiInner { /// remains in the sharded key-control table; observing metrics must never /// scan or hold those fences. external_get_flight_registry: DashMap>, + external_get_local_probe_locks: AMapLock<(String, i64, u64)>, + completed_external_get_local_probes: + moka::future::Cache<(String, i64, u64), (Vec, ExternalBatchGetLocalProbeResp)>, + planned_external_get_execute_locks: AMapLock<(String, i64, u64)>, + completed_planned_external_get_executes: + moka::future::Cache<(String, i64, u64), ExternalExecutePlannedGetResp>, next_external_get_start_handle: AtomicU64, /// External holding identities are independent from upstream and resident holder ids. next_external_holding_id: AtomicU64, @@ -2420,6 +2505,7 @@ pub struct ClientKvApiInner { rpc_caller_get_revoke: RPCCaller, rpc_caller_get_done: RPCCaller, rpc_caller_batch_get_start: RPCCaller, + rpc_caller_batch_get_bind: RPCCaller, rpc_caller_batch_get_revoke: RPCCaller, rpc_caller_batch_get_done: RPCCaller, rpc_caller_put_start: RPCCaller, @@ -5689,6 +5775,35 @@ impl ClientKvApiInner { external_get_flights_revoking, external_get_undecided_interests, external_get_retained_interests, + owner_local_probe_batches: self + .planned_get_counters + .local_probe_batches + .load(Ordering::Relaxed), + owner_local_probe_items: self + .planned_get_counters + .local_probe_items + .load(Ordering::Relaxed), + owner_local_probe_local_items: self + .planned_get_counters + .local_probe_local_items + .load(Ordering::Relaxed), + owner_local_probe_remote_items: self + .planned_get_counters + .local_probe_remote_items + .load(Ordering::Relaxed), + planned_cpu_get_batches: self.planned_get_counters.batches.load(Ordering::Relaxed), + planned_cpu_get_local_items: self + .planned_get_counters + .local_items + .load(Ordering::Relaxed), + planned_cpu_get_leader_items: self + .planned_get_counters + .leader_items + .load(Ordering::Relaxed), + planned_cpu_get_follower_items: self + .planned_get_counters + .follower_items + .load(Ordering::Relaxed), external_pending_put_entries: self.external_pending_puts.entry_count(), remote_put_flights_active: self .owner_remote_put_counters @@ -6341,6 +6456,14 @@ impl ClientKvApi { revoking_flights = snapshot.external_get_flights_revoking, undecided_interests = snapshot.external_get_undecided_interests, retained_interests = snapshot.external_get_retained_interests, + local_probe_batches = snapshot.owner_local_probe_batches, + local_probe_items = snapshot.owner_local_probe_items, + local_probe_local_items = snapshot.owner_local_probe_local_items, + local_probe_remote_items = snapshot.owner_local_probe_remote_items, + planned_cpu_batches = snapshot.planned_cpu_get_batches, + planned_cpu_local_items = snapshot.planned_cpu_get_local_items, + planned_cpu_leader_items = snapshot.planned_cpu_get_leader_items, + planned_cpu_follower_items = snapshot.planned_cpu_get_follower_items, reserve_free = snapshot.local_reserve_slots_free, reserve_prepared = snapshot.local_reserve_slots_prepared, reserve_pending_visible = snapshot.local_reserve_slots_pending_visible, @@ -6453,6 +6576,7 @@ impl ClientKvApi { owner_source_eviction_selected, owner_hot_counters, owner_remote_put_counters, + planned_get_counters: OwnerPlannedGetCounters::default(), owner_hot_retry_queue, owner_hot_eviction_tx, owner_hot_eviction_rx: Mutex::new(Some(owner_hot_eviction_rx)), @@ -6466,6 +6590,14 @@ impl ClientKvApi { external_get_holding: OwnerExternalMemMgr::default(), external_get_start_registry: DashMap::new(), external_get_flight_registry: DashMap::new(), + external_get_local_probe_locks: AMapLock::new(Duration::from_secs(120)), + completed_external_get_local_probes: moka::future::Cache::builder() + .time_to_live(Duration::from_secs(120)) + .build(), + planned_external_get_execute_locks: AMapLock::new(Duration::from_secs(120)), + completed_planned_external_get_executes: moka::future::Cache::builder() + .time_to_live(Duration::from_secs(120)) + .build(), next_external_get_start_handle: AtomicU64::new(1), next_external_holding_id: AtomicU64::new(1), external_pending_puts: moka::sync::Cache::builder() @@ -6478,6 +6610,7 @@ impl ClientKvApi { rpc_caller_get_revoke: RPCCaller::new(), rpc_caller_get_done: RPCCaller::new(), rpc_caller_batch_get_start: RPCCaller::new(), + rpc_caller_batch_get_bind: RPCCaller::new(), rpc_caller_batch_get_revoke: RPCCaller::new(), rpc_caller_batch_get_done: RPCCaller::new(), rpc_caller_put_start: RPCCaller::new(), @@ -6527,6 +6660,9 @@ impl ClientKvApi { inner .rpc_caller_batch_get_start .regist(inner.view.p2p_module()); + inner + .rpc_caller_batch_get_bind + .regist(inner.view.p2p_module()); inner .rpc_caller_batch_get_revoke .regist(inner.view.p2p_module()); @@ -6633,6 +6769,20 @@ impl ClientKvApi { }, ); + let view_ext = inner.view.clone_view(); + RPCHandler::::new().regist( + inner.view.p2p_module(), + move |resp, msg| { + let view = view_ext.clone(); + let view_task = view.clone(); + view.spawn("rpc_external_batch_get_local_probe", async move { + let result = handle_external_batch_get_local_probe(&view_task, &msg).await; + let _ = resp.send_resp(result).await; + }); + Ok(()) + }, + ); + let view_ext = inner.view.clone_view(); RPCHandler::::new().regist( inner.view.p2p_module(), @@ -6675,6 +6825,20 @@ impl ClientKvApi { }, ); + let view_ext = inner.view.clone_view(); + RPCHandler::::new().regist( + inner.view.p2p_module(), + move |resp, msg| { + let view = view_ext.clone(); + let view_task = view.clone(); + view.spawn("rpc_external_execute_planned_get", async move { + let result = handle_external_execute_planned_get(&view_task, &msg).await; + let _ = resp.send_resp(result).await; + }); + Ok(()) + }, + ); + let view_ext = inner.view.clone_view(); RPCHandler::::new().regist(inner.view.p2p_module(), move |resp, msg| { let view = view_ext.clone(); diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs index b0077c7..372a9a2 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs @@ -3,7 +3,7 @@ use crate::p2p::msg_pack::{MsgPackSerializePart, RPCReq}; use crate::rpcresp_kvresult_convert::msg_and_error::{ErrorCode, OK}; use bitcode::{Decode, Encode}; -use crate::memholder::{ExternalMemHolder, ExternalMemHolderInfo}; +use crate::memholder::ExternalMemHolderInfo; #[derive(Default, Debug, Clone, Encode, Decode)] pub struct TestPutPhaseTrace { @@ -119,6 +119,78 @@ pub struct ExternalBatchGetResp { pub error_code: ErrorCode, pub error_json: String, } + +/// Probe only the requester's share-group owner. A `Some` item is pinned +/// owner-local data; `None` must be resolved through the remote directory. +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchGetLocalProbeReq { + pub plan_handle: u64, + pub keys: Vec, + pub req_node_id: String, + pub started_time: i64, +} +impl MsgPackSerializePart for ExternalBatchGetLocalProbeReq { + fn msg_id(&self) -> u32 { + 4040 + } +} +impl RPCReq for ExternalBatchGetLocalProbeReq { + type Resp = ExternalBatchGetLocalProbeResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalBatchGetLocalProbeResp { + pub items: Vec>, + pub error_code: ErrorCode, + pub error_json: String, +} +impl MsgPackSerializePart for ExternalBatchGetLocalProbeResp { + fn msg_id(&self) -> u32 { + 4041 + } +} + +#[cfg(test)] +mod external_batch_get_local_probe_wire_tests { + use super::{ExternalBatchGetLocalProbeReq, ExternalBatchGetLocalProbeResp}; + use crate::memholder::ExternalMemHolderInfo; + use crate::rpcresp_kvresult_convert::msg_and_error::OK; + + #[test] + fn mixed_local_remote_probe_round_trip() { + let request = ExternalBatchGetLocalProbeReq { + plan_handle: 41, + keys: vec!["local".to_string(), "remote".to_string()], + req_node_id: "external-a".to_string(), + started_time: 17, + }; + let decoded: ExternalBatchGetLocalProbeReq = + bitcode::decode(&bitcode::encode(&request)).expect("decode local probe request"); + assert_eq!(decoded.plan_handle, 41); + assert_eq!(decoded.keys, request.keys); + + let response = ExternalBatchGetLocalProbeResp { + items: vec![ + Some(ExternalMemHolderInfo { + offset: 4096, + len: 8192, + holder_id: 23, + }), + None, + ], + error_code: OK, + error_json: String::new(), + }; + let decoded: ExternalBatchGetLocalProbeResp = + bitcode::decode(&bitcode::encode(&response)).expect("decode local probe response"); + assert_eq!(decoded.items.len(), 2); + assert_eq!( + decoded.items[0].as_ref().map(|info| info.holder_id), + Some(23) + ); + assert!(decoded.items[1].is_none()); + } +} impl MsgPackSerializePart for ExternalBatchGetResp { fn msg_id(&self) -> u32 { 4021 @@ -229,6 +301,96 @@ pub struct ExternalBatchGetCancelResp { pub error_code: ErrorCode, pub error_json: String, } + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalPlannedGetItem { + pub key: String, + pub get_id: u64, +} + +/// Execute a target-free master plan into the requester's owner-local CPU +/// pool. The stable `(requester generation, plan_handle)` identity makes a +/// lost response replayable without another lookup or transfer. +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalExecutePlannedGetReq { + pub plan_handle: u64, + pub items: Vec, + pub req_node_id: String, + pub started_time: i64, + pub transfer_concurrency: usize, +} +impl MsgPackSerializePart for ExternalExecutePlannedGetReq { + fn msg_id(&self) -> u32 { + 4038 + } +} +impl RPCReq for ExternalExecutePlannedGetReq { + type Resp = ExternalExecutePlannedGetResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct ExternalExecutePlannedGetResp { + pub items: Vec, + pub error_code: ErrorCode, + pub error_json: String, +} + +#[cfg(test)] +mod external_execute_planned_get_wire_tests { + use super::{ + ExternalBatchGetItemResp, ExternalExecutePlannedGetReq, ExternalExecutePlannedGetResp, + ExternalPlannedGetItem, + }; + use crate::memholder::ExternalMemHolderInfo; + use crate::rpcresp_kvresult_convert::msg_and_error::OK; + + #[test] + fn operation_identity_and_holder_terminal_round_trip() { + let request = ExternalExecutePlannedGetReq { + plan_handle: 19, + items: vec![ExternalPlannedGetItem { + key: "page-a".to_string(), + get_id: 0, + }], + req_node_id: "external-a".to_string(), + started_time: 23, + transfer_concurrency: 32, + }; + let decoded: ExternalExecutePlannedGetReq = + bitcode::decode(&bitcode::encode(&request)).expect("decode planned execute request"); + assert_eq!(decoded.plan_handle, 19); + assert_eq!(decoded.items[0].get_id, 0); + assert_eq!(decoded.started_time, 23); + + let terminal = ExternalExecutePlannedGetResp { + items: vec![ExternalBatchGetItemResp { + error_code: OK, + error_json: String::new(), + external_memholder_info: Some(ExternalMemHolderInfo { + offset: 4096, + len: 8192, + holder_id: 29, + }), + }], + error_code: OK, + error_json: String::new(), + }; + let decoded: ExternalExecutePlannedGetResp = + bitcode::decode(&bitcode::encode(&terminal)).expect("decode planned execute terminal"); + assert_eq!( + decoded.items[0] + .external_memholder_info + .as_ref() + .map(|info| info.holder_id), + Some(29) + ); + } +} +impl MsgPackSerializePart for ExternalExecutePlannedGetResp { + fn msg_id(&self) -> u32 { + 4039 + } +} impl MsgPackSerializePart for ExternalBatchGetCancelResp { fn msg_id(&self) -> u32 { 4035 diff --git a/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs b/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs index 86851bf..5af3351 100644 --- a/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs +++ b/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs @@ -5,8 +5,9 @@ use crate::client_kv_api::external_api::{ validate_external_get_consume_prefix, }; use crate::client_kv_api::msg_pack::{ - ExternalBatchDeleteAckReq, ExternalInvalidateWeakIndexItem, ExternalInvalidateWeakIndexReq, - ExternalInvalidateWeakIndexResp, + ExternalBatchDeleteAckReq, ExternalExecutePlannedGetReq, ExternalExecutePlannedGetResp, + ExternalInvalidateWeakIndexItem, ExternalInvalidateWeakIndexReq, + ExternalInvalidateWeakIndexResp, ExternalPlannedGetItem, }; use crate::client_seg_pool::{ClientSegPool, SideTransferPeerFileMeta}; use crate::client_transfer_engine::{ClientTransferEngine, GpuMemoryGuard}; @@ -15,24 +16,26 @@ use crate::cluster_manager::{ META_KEY_SHARED_STORAGE_NODE_ID, META_KEY_SHARED_STORAGE_NODE_START_TIME, }; use crate::master_kv_router::msg_pack::{ - BatchGetDoneReq, BatchGetDoneResp, BatchGetRevokeReq, BatchGetRevokeResp, - BatchGetStartItemResp, BatchGetStartReq, BatchGetStartResp, GetAllocationMode, + BatchGetBindItemReq, BatchGetBindReq, BatchGetBindResp, BatchGetDoneReq, BatchGetDoneResp, + BatchGetPlanItemResp, BatchGetPlanReq, BatchGetPlanResp, BatchGetRevokeReq, BatchGetRevokeResp, + BatchGetStartItemResp, BatchGetStartReq, BatchGetStartResp, GetAllocationMode, GetBindTarget, GetExternalSinkTarget, }; use crate::rpcresp_kvresult_convert::ToResult; use crate::{ client_kv_api::msg_pack::{ ExternalBatchGetCancelPlan, ExternalBatchGetCancelReq, ExternalBatchGetItemResp, - ExternalBatchGetReq, ExternalBatchGetStartReq, ExternalBatchGetStartResp, - ExternalBatchGetStartTransferPlan, ExternalBatchGetTransferReq, - ExternalBatchGetTransferResp, ExternalBatchIsExistReq, ExternalBatchPutCommitItemReq, - ExternalBatchPutCommitReq, ExternalBatchPutCommitResp, ExternalBatchPutStartItemReq, - ExternalBatchPutStartReq, ExternalBatchPutStartResp, ExternalBatchPutTransferEndItemReq, - ExternalBatchPutTransferEndReq, ExternalBatchPutTransferEndResp, ExternalDeleteAckReq, - ExternalDeleteReq, ExternalGetReq, ExternalIsExistReq, ExternalObservabilitySnapshotReq, - ExternalPutCommitReq, ExternalPutCommitResp, ExternalPutRevokeReq, ExternalPutRevokeResp, - ExternalPutStartReq, ExternalPutStartResp, ExternalPutTransferEndReq, - ExternalPutTransferEndResp, SyncKvToFileReq, SyncKvToFileResp, TestPutPhaseTrace, + ExternalBatchGetLocalProbeReq, ExternalBatchGetLocalProbeResp, ExternalBatchGetReq, + ExternalBatchGetStartReq, ExternalBatchGetStartResp, ExternalBatchGetStartTransferPlan, + ExternalBatchGetTransferReq, ExternalBatchGetTransferResp, ExternalBatchIsExistReq, + ExternalBatchPutCommitItemReq, ExternalBatchPutCommitReq, ExternalBatchPutCommitResp, + ExternalBatchPutStartItemReq, ExternalBatchPutStartReq, ExternalBatchPutStartResp, + ExternalBatchPutTransferEndItemReq, ExternalBatchPutTransferEndReq, + ExternalBatchPutTransferEndResp, ExternalDeleteAckReq, ExternalDeleteReq, ExternalGetReq, + ExternalIsExistReq, ExternalObservabilitySnapshotReq, ExternalPutCommitReq, + ExternalPutCommitResp, ExternalPutRevokeReq, ExternalPutRevokeResp, ExternalPutStartReq, + ExternalPutStartResp, ExternalPutTransferEndReq, ExternalPutTransferEndResp, + SyncKvToFileReq, SyncKvToFileResp, TestPutPhaseTrace, }, cluster_manager::{ ClusterManager, ClusterManagerAccessTrait, IpcBandwidthAttributorHandle, NodeRole, @@ -90,6 +93,13 @@ const EXTERNAL_PUT_TRANSFER_END_RPC_TIMEOUT_SECS: u64 = 30; const EXTERNAL_RPC_P2P_RECOVER_MAX_ATTEMPTS: usize = 3; const EXTERNAL_PUT_TRACE_LOG_WINDOW_SECS: u64 = 10; const EXTERNAL_OWNER_INTRA_RPC_READY_TIMEOUT_SECS: u64 = 30; +// This is a foreground scheduler wait, not the owner operation lifetime. +// Owner finish is cancellation-safe and the uncertain replay below keeps its +// longer timeout. Fail the foreground request at the P2P minimum so SGLang +// can fall back to compute instead of parking a TP scheduler for 300 seconds. +const EXTERNAL_PLANNED_CPU_GET_FOREGROUND_RPC_TIMEOUT_SECS: u64 = + crate::p2p::msg_pack::MIN_EXPLICIT_RPC_TIMEOUT_SECS; +const EXTERNAL_PLANNED_CPU_GET_REPLAY_RPC_TIMEOUT_SECS: u64 = 300; #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub(crate) enum ExternalDeleteAckBatchSendResult { @@ -117,9 +127,29 @@ pub struct ExternalGpuGetStartResp { } #[derive(Clone, Debug, PartialEq, Eq)] +pub struct ExternalGetPlanResp { + pub handle: u64, + pub raw_prefix_hit_len: usize, + pub gpu_raw_prefix_hit_len: usize, + /// Original key positions that need remote GPU destinations. Owner-local + /// positions remain CPU-backed and are absent from this vector. + pub gpu_remote_indices: Vec, +} + pub struct ExternalGpuGetTransferResp { pub transferred_prefix_len: usize, pub consumed_prefix_len: usize, + pub value_ptrs: Vec, + pub local_holders: Vec>, + /// Wall time from publishing the live GPU Get handle until the transfer, + /// cleanup, and master Done path reached a terminal state. + pub transfer_wall_us: i64, + /// Time spent by the consuming call waiting for that terminal state. + pub finish_wait_us: i64, + /// Whether the terminal state was already available when consumption began. + pub terminal_before_consume: bool, + /// Ready-but-unconsumed residence when the terminal preceded consumption. + pub terminal_to_consume_us: i64, } fn external_gpu_transfer_plan_geometry_is_valid( @@ -135,6 +165,34 @@ fn external_gpu_transfer_plan_geometry_is_valid( && registered_generation == destination.registration_id } +fn external_get_plan_raw_prefixes(items: &[BatchGetPlanItemResp]) -> (usize, usize) { + external_get_plan_raw_prefixes_from_statuses( + items + .iter() + .map(|item| (item.error_code == OK, item.gpu_direct_eligible)), + ) +} + +fn external_get_plan_raw_prefixes_from_statuses( + statuses: impl IntoIterator, +) -> (usize, usize) { + let mut cpu_prefix = 0usize; + let mut gpu_prefix = 0usize; + let mut gpu_prefix_open = true; + for (hit, gpu_eligible) in statuses { + if !hit { + break; + } + cpu_prefix += 1; + if gpu_prefix_open && gpu_eligible { + gpu_prefix += 1; + } else { + gpu_prefix_open = false; + } + } + (cpu_prefix, gpu_prefix) +} + #[derive(Clone, Debug)] enum ExternalGpuGetTerminal { Completed, @@ -142,11 +200,90 @@ enum ExternalGpuGetTerminal { Failed { detail: String }, } +#[derive(Clone, Debug)] +struct ExternalGpuGetTerminalEvent { + outcome: ExternalGpuGetTerminal, + terminal_at: Instant, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +struct ExternalGpuGetConsumeTiming { + transfer_wall_us: i64, + finish_wait_us: i64, + terminal_before_consume: bool, + terminal_to_consume_us: i64, +} + +fn observe_external_gpu_get_consume_timing( + transfer_started_at: Instant, + terminal_at: Instant, + consume_started_at: Instant, + finish_wait: Duration, +) -> ExternalGpuGetConsumeTiming { + let terminal_to_consume = consume_started_at.checked_duration_since(terminal_at); + ExternalGpuGetConsumeTiming { + transfer_wall_us: duration_to_i64_us( + terminal_at + .checked_duration_since(transfer_started_at) + .unwrap_or_default(), + ), + finish_wait_us: duration_to_i64_us(finish_wait), + terminal_before_consume: terminal_to_consume.is_some(), + terminal_to_consume_us: duration_to_i64_us(terminal_to_consume.unwrap_or_default()), + } +} + struct PendingExternalGpuGet { + transferable_len: usize, + atomic_group_lens: Vec, + value_ptrs: Vec, + local_holders: Vec<(usize, Arc)>, + cancel_requested: Arc, + transfer_started_at: Instant, + terminal_rx: watch::Receiver>, +} + +enum PendingExternalGetPlanItem { + Local { + holder: Arc, + }, + Remote { + key: String, + plan: BatchGetPlanItemResp, + }, +} + +struct PendingExternalGetPlan { + items: Vec, + transferable_len: usize, + gpu_transferable_len: usize, + gpu_remote_indices: Vec, + atomic_group_lens: Vec, +} + +#[derive(Clone, Debug)] +enum ExternalPlannedCpuGetTerminal { + Completed { + items: Vec, + owner_start_time: i64, + }, + Revoked, + Failed { + detail: String, + }, +} + +struct PendingExternalPlannedCpuGet { + sources: Vec, transferable_len: usize, atomic_group_lens: Vec, cancel_requested: Arc, - terminal_rx: watch::Receiver>, + terminal_rx: watch::Receiver>, +} + +enum PendingExternalCpuSource { + Local { holder: Arc }, + Remote { key: String }, } struct PendingExternalGetStart { @@ -156,6 +293,47 @@ struct PendingExternalGetStart { first_miss_index: Option, } +/// Keeps ownership in a pending registry across cancellation points. A +/// future that is dropped while waiting automatically restores the exact +/// entry, so a later transfer/cancel call can still drive its terminal +/// cleanup. `take()` disarms the guard once no further await can lose the +/// entry. +struct PendingRegistryEntryGuard<'a, T> { + registry: &'a DashMap, + handle: u64, + entry: Option, +} + +impl<'a, T> PendingRegistryEntryGuard<'a, T> { + fn new(registry: &'a DashMap, handle: u64, entry: T) -> Self { + Self { + registry, + handle, + entry: Some(entry), + } + } + + fn entry(&self) -> &T { + self.entry + .as_ref() + .expect("pending registry guard must be armed") + } + + fn take(mut self) -> T { + self.entry + .take() + .expect("pending registry guard must be armed") + } +} + +impl Drop for PendingRegistryEntryGuard<'_, T> { + fn drop(&mut self) { + if let Some(entry) = self.entry.take() { + self.registry.insert(self.handle, entry); + } + } +} + #[derive(Clone)] struct PendingInlineExternalGetStart { keys: Vec, @@ -204,6 +382,86 @@ fn validate_inline_external_get_owner_generation( })) } +#[allow(clippy::too_many_arguments)] +fn validate_external_local_holder_geometry( + index: usize, + holder_owner_start_time: i64, + holder_offset: u64, + holder_len: u32, + holder_addr: u64, + current_owner_start_time: i64, + base_ptr: u64, + mapped_len: u64, +) -> KvResult<()> { + validate_inline_external_get_owner_generation( + holder_owner_start_time, + current_owner_start_time, + )?; + let end = holder_offset + .checked_add(u64::from(holder_len)) + .ok_or_else(|| { + KvError::Api(ApiError::Unknown { + detail: format!( + "mixed Get local holder range overflow: index={} offset={} len={}", + index, holder_offset, holder_len + ), + }) + })?; + let pointer = base_ptr.checked_add(holder_offset).ok_or_else(|| { + KvError::Api(ApiError::Unknown { + detail: format!( + "mixed Get local holder pointer overflow: index={} base={:#x} offset={}", + index, base_ptr, holder_offset + ), + }) + })?; + if end > mapped_len || pointer != holder_addr { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "mixed Get local holder no longer matches owner mapping: index={} end={} mapped_len={} pointer={:#x} expected={:#x}", + index, end, mapped_len, pointer, holder_addr + ), + })); + } + Ok(()) +} + +fn validate_external_local_holder_mapping( + index: usize, + holder: &ExternalMemHolder, + current_owner_start_time: i64, + base_ptr: u64, + mapped_len: u64, +) -> KvResult<()> { + validate_external_local_holder_geometry( + index, + holder.owner_start_time, + holder.offset, + holder.len, + holder.addr, + current_owner_start_time, + base_ptr, + mapped_len, + ) +} + +fn validate_external_local_holders_mapping( + holders: &[(usize, Arc)], + current_owner_start_time: i64, + base_ptr: u64, + mapped_len: u64, +) -> KvResult<()> { + holders.iter().try_for_each(|(index, holder)| { + validate_external_local_holder_mapping( + *index, + holder, + current_owner_start_time, + base_ptr, + mapped_len, + ) + }) +} + fn inline_external_get_tail_holder_ids( items: &[ExternalBatchGetItemResp], consume_prefix_len: usize, @@ -239,14 +497,20 @@ fn inline_external_get_tail_holder_ids( #[cfg(test)] mod inline_external_get_start_tests { use super::{ - ExternalGpuDestination, external_gpu_transfer_plan_geometry_is_valid, - inline_external_get_tail_holder_ids, validate_inline_external_get_owner_generation, + EXTERNAL_PLANNED_CPU_GET_FOREGROUND_RPC_TIMEOUT_SECS, + EXTERNAL_PLANNED_CPU_GET_REPLAY_RPC_TIMEOUT_SECS, ExternalGpuDestination, + PendingRegistryEntryGuard, external_get_plan_raw_prefixes, + external_get_plan_raw_prefixes_from_statuses, external_gpu_transfer_plan_geometry_is_valid, + inline_external_get_tail_holder_ids, observe_external_gpu_get_consume_timing, + validate_external_local_holder_geometry, validate_inline_external_get_owner_generation, validate_inline_external_get_start_plan, }; use crate::client_kv_api::msg_pack::ExternalBatchGetItemResp; - use crate::master_kv_router::msg_pack::BatchGetStartItemResp; + use crate::master_kv_router::msg_pack::{BatchGetPlanItemResp, BatchGetStartItemResp}; use crate::memholder::ExternalMemHolderInfo; use crate::rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, OK}; + use dashmap::DashMap; + use std::time::{Duration, Instant}; fn inline_hit(holder_id: u64) -> ExternalBatchGetItemResp { ExternalBatchGetItemResp { @@ -271,6 +535,18 @@ mod inline_external_get_start_tests { assert!(validate_inline_external_get_start_plan(2, &missing).is_err()); } + #[test] + fn planned_cpu_get_foreground_timeout_is_bounded_below_replay_cleanup() { + assert_eq!( + EXTERNAL_PLANNED_CPU_GET_FOREGROUND_RPC_TIMEOUT_SECS, + crate::p2p::msg_pack::MIN_EXPLICIT_RPC_TIMEOUT_SECS, + ); + assert!( + EXTERNAL_PLANNED_CPU_GET_FOREGROUND_RPC_TIMEOUT_SECS + < EXTERNAL_PLANNED_CPU_GET_REPLAY_RPC_TIMEOUT_SECS + ); + } + #[test] fn inline_plan_rejects_a_stale_owner_generation() { assert!(validate_inline_external_get_owner_generation(17, 17).is_ok()); @@ -285,6 +561,41 @@ mod inline_external_get_start_tests { )); } + #[test] + fn mixed_source_local_holder_requires_the_exact_live_mapping() { + assert!( + validate_external_local_holder_geometry( + 2, 17, 0x1000, 0x1000, 0x11_000, 17, 0x10_000, 0x4000, + ) + .is_ok() + ); + + let stale = validate_external_local_holder_geometry( + 2, 16, 0x1000, 0x1000, 0x11_000, 17, 0x10_000, 0x4000, + ) + .expect_err("an old owner generation must be rejected before GPU Bind"); + assert!(matches!( + stale, + KvError::Api(ApiError::OwnerStartTimeMismatch { + expected: 17, + got: 16 + }) + )); + + assert!( + validate_external_local_holder_geometry( + 2, 17, 0x3800, 0x1000, 0x13_800, 17, 0x10_000, 0x4000, + ) + .is_err() + ); + assert!( + validate_external_local_holder_geometry( + 2, 17, 0x1000, 0x1000, 0x21_000, 17, 0x10_000, 0x4000, + ) + .is_err() + ); + } + #[test] fn inline_partial_consume_returns_only_tail_holder_ids() { let items = vec![inline_hit(11), inline_hit(12), inline_hit(13)]; @@ -322,6 +633,140 @@ mod inline_external_get_start_tests { destination.registration_id, )); } + + #[test] + fn gpu_prefix_stops_without_shortening_the_cpu_plan() { + let items = vec![ + BatchGetPlanItemResp { + error_code: OK, + gpu_direct_eligible: true, + ..Default::default() + }, + BatchGetPlanItemResp { + error_code: OK, + gpu_direct_eligible: false, + ..Default::default() + }, + BatchGetPlanItemResp { + error_code: OK, + gpu_direct_eligible: true, + ..Default::default() + }, + ]; + assert_eq!(external_get_plan_raw_prefixes(&items), (3, 1)); + } + + #[test] + fn owner_local_positions_do_not_consume_remote_gpu_destinations() { + // local, remote-GPU, local stays a three-page GPU-capable source + // prefix, while only the middle page needs a GPU destination. + assert_eq!( + external_get_plan_raw_prefixes_from_statuses([ + (true, true), + (true, true), + (true, true), + ]), + (3, 3) + ); + // A remote source that cannot bind a GPU sink stops only the mixed + // GPU prefix; the CPU plan can still consume later local pages. + assert_eq!( + external_get_plan_raw_prefixes_from_statuses([ + (true, true), + (true, false), + (true, true), + ]), + (3, 1) + ); + assert_eq!( + external_get_plan_raw_prefixes_from_statuses([ + (true, true), + (false, false), + (true, true), + ]), + (1, 1) + ); + } + + #[test] + fn gpu_get_timing_separates_ready_residence_from_real_wait() { + let transfer_started_at = Instant::now(); + let terminal_at = transfer_started_at + Duration::from_millis(20); + let consume_after_terminal = terminal_at + Duration::from_millis(30); + let ready = observe_external_gpu_get_consume_timing( + transfer_started_at, + terminal_at, + consume_after_terminal, + Duration::from_micros(7), + ); + assert_eq!(ready.transfer_wall_us, 20_000); + assert!(ready.terminal_before_consume); + assert_eq!(ready.terminal_to_consume_us, 30_000); + assert_eq!(ready.finish_wait_us, 7); + + let consume_before_terminal = transfer_started_at + Duration::from_millis(5); + let waiting = observe_external_gpu_get_consume_timing( + transfer_started_at, + terminal_at, + consume_before_terminal, + Duration::from_millis(15), + ); + assert_eq!(waiting.transfer_wall_us, 20_000); + assert!(!waiting.terminal_before_consume); + assert_eq!(waiting.terminal_to_consume_us, 0); + assert_eq!(waiting.finish_wait_us, 15_000); + } + + #[test] + fn pending_registry_guard_reinserts_on_drop_and_disarms_on_take() { + let registry = DashMap::new(); + let handle = 17; + + { + let guard = PendingRegistryEntryGuard::new(®istry, handle, "pending-a"); + assert_eq!(guard.entry(), &"pending-a"); + assert!(!registry.contains_key(&handle)); + } + assert_eq!( + registry.remove(&handle).map(|(_, value)| value), + Some("pending-a") + ); + + let guard = PendingRegistryEntryGuard::new(®istry, handle, "pending-b"); + assert_eq!(guard.take(), "pending-b"); + assert!(!registry.contains_key(&handle)); + } + + #[limit_thirdparty::tokio::test] + async fn aborted_terminal_waiter_restores_the_pending_entry() { + let registry = std::sync::Arc::new(DashMap::new()); + let handle = 23; + registry.insert(handle, "terminal-pending"); + let task_registry = registry.clone(); + let (armed_tx, armed_rx) = ::tokio::sync::oneshot::channel(); + let waiter = ::tokio::spawn(async move { + let (_, entry) = task_registry + .remove(&handle) + .expect("test pending entry must exist"); + let _guard = PendingRegistryEntryGuard::new(&task_registry, handle, entry); + let _ = armed_tx.send(()); + futures::future::pending::<()>().await; + }); + + armed_rx.await.expect("waiter armed its guard"); + assert!(!registry.contains_key(&handle)); + waiter.abort(); + assert!( + waiter + .await + .expect_err("waiter must be aborted") + .is_cancelled() + ); + assert_eq!( + registry.remove(&handle).map(|(_, value)| value), + Some("terminal-pending") + ); + } } fn duration_to_i64_us(duration: std::time::Duration) -> i64 { @@ -577,12 +1022,16 @@ pub struct ExternalInner { side_transfer_put_bindings: moka::sync::SegmentedCache<(u64, u32), (String, u16)>, rpc_caller_external_get: RPCCaller, rpc_caller_external_batch_get: RPCCaller, + rpc_caller_external_batch_get_local_probe: RPCCaller, rpc_caller_external_batch_get_start: RPCCaller, rpc_caller_external_batch_get_transfer: RPCCaller, rpc_caller_external_batch_get_cancel: RPCCaller, rpc_caller_master_batch_get_start: RPCCaller, + rpc_caller_master_batch_get_plan: RPCCaller, + rpc_caller_master_batch_get_bind: RPCCaller, rpc_caller_master_batch_get_done: RPCCaller, rpc_caller_master_batch_get_revoke: RPCCaller, + rpc_caller_external_execute_planned_get: RPCCaller, rpc_caller_external_put_commit: RPCCaller, rpc_caller_external_batch_put_commit: RPCCaller, rpc_caller_external_put_start: RPCCaller, @@ -605,7 +1054,9 @@ pub struct ExternalInner { /// Fully local plans consumed without a follow-up owner transfer RPC. pending_inline_external_get_start: DashMap, next_gpu_get_handle: AtomicU64, + pending_external_get_plan: DashMap, pending_external_gpu_get: DashMap, + pending_external_planned_cpu_get: DashMap, /// per-key semaphore (permits=1) to ensure single inflight per key inflight1_per_key: SemaphoreMap, put_trace_log_window: Mutex, @@ -615,8 +1066,8 @@ pub struct ExternalInner { pub struct ExternalClientApi(ExternalInner); async fn wait_external_gpu_get_terminal( - mut terminal_rx: watch::Receiver>, -) -> KvResult { + mut terminal_rx: watch::Receiver>, +) -> KvResult { loop { if let Some(terminal) = terminal_rx.borrow().clone() { return Ok(terminal); @@ -630,104 +1081,447 @@ async fn wait_external_gpu_get_terminal( } } -async fn run_external_gpu_get_transfer( - view: ExternalClientApiView, - transfer_items: Vec<(BatchGetStartItemResp, GpuMemoryGuard)>, - skipped_get_ids: Vec, - transfer_concurrency: usize, - cancel_requested: Arc, -) -> ExternalGpuGetTerminal { - let transfer_get_ids = transfer_items - .iter() - .map(|(item, _)| item.get_id) - .collect::>(); - let mut all_get_ids = skipped_get_ids.clone(); - all_get_ids.extend(transfer_get_ids.iter().copied()); - - let skipped_revoke_error = view - .external_client_api() - .inner() - .master_batch_gpu_get_revoke(skipped_get_ids) - .await - .err() - .map(|err| err.to_string()); - - if transfer_items.is_empty() { - return match skipped_revoke_error { - Some(detail) => ExternalGpuGetTerminal::Failed { - detail: format!("GPU Get could not revoke non-transferable starts: {detail}"), - }, - None => ExternalGpuGetTerminal::Revoked { - transfer_error: None, - }, - }; - } - - let transfer_futures = transfer_items.into_iter().map(|(item, gpu_guard)| { - let transfer_view = view.clone(); - let cancel_requested = cancel_requested.clone(); - async move { - if cancel_requested.load(Ordering::Acquire) { - return None; - } - transfer_view - .client_transfer_engine() - .transfer_data_no_copy_to_gpu( - item.node_id.clone(), - item.src_addr, - item.target_addr, - item.len, - gpu_guard, - ) - .await - .err() - .map(|err| { - format!( - "GPU Get transfer failed: get_id={} source={} src={:#x} target={:#x} len={} error={}", - item.get_id, - item.node_id, - item.src_addr, - item.target_addr, - item.len, - err - ) - }) +async fn wait_external_planned_cpu_get_terminal( + mut terminal_rx: watch::Receiver>, +) -> KvResult { + loop { + if let Some(terminal) = terminal_rx.borrow().clone() { + return Ok(terminal); } - }); - let mut transfer_stream = - stream::iter(transfer_futures).buffer_unordered(transfer_concurrency.max(1)); - let mut transfer_error = None; - while let Some(item_error) = transfer_stream.next().await { - if transfer_error.is_none() { - transfer_error = item_error; + if terminal_rx.changed().await.is_err() { + return Err(KvError::Api(ApiError::Unknown { + detail: "planned CPU Get task ended without publishing a terminal state" + .to_string(), + })); } } +} - let cancelled = cancel_requested.load(Ordering::Acquire); - if cancelled || transfer_error.is_some() || skipped_revoke_error.is_some() { - if let Err(err) = view +async fn run_planned_get_revoke_cleanup( + view: ExternalClientApiView, + get_ids: Vec, + context: &'static str, +) -> KvResult<()> { + if get_ids.is_empty() { + return Ok(()); + } + let mut attempt = 1u32; + let mut shutdown = view.register_shutdown_waiter(); + loop { + match view .external_client_api() .inner() - .master_batch_gpu_get_revoke(all_get_ids) + .master_batch_gpu_get_revoke(get_ids.clone()) .await { - return ExternalGpuGetTerminal::Failed { - detail: format!( - "GPU Get cleanup failed after transfer/cancel: transfer_error={:?} skipped_revoke_error={:?} revoke_error={}", - transfer_error, skipped_revoke_error, err - ), - }; - } - if let Some(detail) = skipped_revoke_error { - return ExternalGpuGetTerminal::Failed { - detail: format!( - "GPU Get initially failed to revoke non-transferable starts: {detail}" - ), - }; + Ok(()) => return Ok(()), + Err(err) if matches!(&err, KvError::Api(ApiError::SystemShutdown { .. })) => { + return Err(err); + } + Err(err) => { + tracing::warn!( + "{} planned Get Revoke uncertain; retaining cleanup ownership: items={} attempt={} err={}", + context, + get_ids.len(), + attempt, + err + ); + } } - return ExternalGpuGetTerminal::Revoked { transfer_error }; - } - + attempt = attempt.saturating_add(1); + tokio::select! { + _ = tokio::time::sleep(Duration::from_millis( + (50u64.saturating_mul(1u64 << attempt.min(6))).min(2_000), + )) => {} + _ = shutdown.wait() => { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: format!( + "{} planned Get Revoke cleanup stopped during shutdown", + context + ), + })); + } + } + } +} + +fn spawn_planned_get_revoke_cleanup( + view: ExternalClientApiView, + get_ids: Vec, + context: &'static str, +) -> ::tokio::sync::oneshot::Receiver> { + let (done_tx, done_rx) = ::tokio::sync::oneshot::channel(); + let spawn_view = view.clone(); + let worker_view = view; + spawn_view.spawn("planned_get_revoke_cleanup", async move { + let result = run_planned_get_revoke_cleanup(worker_view, get_ids, context).await; + let _ = done_tx.send(result); + }); + done_rx +} + +async fn finish_planned_get_revoke_cleanup( + view: ExternalClientApiView, + get_ids: Vec, + context: &'static str, +) -> KvResult<()> { + spawn_planned_get_revoke_cleanup(view, get_ids, context) + .await + .map_err(|_| { + KvError::Api(ApiError::Unknown { + detail: format!( + "{} planned Get Revoke task ended without publishing a terminal", + context + ), + }) + })? +} + +/// Owns master plan identities until a durable local pending entry or a +/// registered cleanup task takes over. This closes the cancellation window +/// around late Bind RPCs without adding a normal-path RPC. +struct PlannedGetRevokeGuard { + view: ExternalClientApiView, + get_ids: Option>, + context: &'static str, +} + +impl PlannedGetRevokeGuard { + fn new(view: ExternalClientApiView, get_ids: Vec, context: &'static str) -> Self { + Self { + view, + get_ids: Some(get_ids), + context, + } + } + + fn disarm(&mut self) { + self.get_ids = None; + } +} + +impl Drop for PlannedGetRevokeGuard { + fn drop(&mut self) { + let Some(get_ids) = self.get_ids.take() else { + return; + }; + if get_ids.is_empty() { + return; + } + drop(spawn_planned_get_revoke_cleanup( + self.view.clone(), + get_ids, + self.context, + )); + } +} + +fn release_planned_cpu_response_holders( + inner: &ExternalInner, + response: &ExternalExecutePlannedGetResp, + owner_start_time: i64, +) { + let external_client_id = inner.view.cluster_manager().get_self_info().id; + for holder_id in response.items.iter().filter_map(|item| { + item.external_memholder_info + .as_ref() + .map(|info| info.holder_id) + }) { + if let Err(err) = inner.enqueue_external_delete_ack( + external_client_id.clone(), + holder_id, + owner_start_time, + ) { + tracing::warn!( + "planned CPU Get could not enqueue unused holder release: holder_id={} err={}", + holder_id, + err + ); + } + } +} + +fn spawn_uncertain_planned_cpu_get_cleanup( + view: ExternalClientApiView, + owner: String, + request: MsgPack, + owner_start_time: i64, +) { + let spawn_view = view.clone(); + let task_view = view.clone(); + spawn_view.spawn("uncertain_planned_cpu_get_cleanup", async move { + let mut shutdown = task_view.register_shutdown_waiter(); + loop { + let inner = task_view.external_client_api().inner(); + if inner.current_owner_start_time().await != owner_start_time { + return; + } + let attempt = inner + .rpc_caller_external_execute_planned_get + .call( + inner.view.p2p_module(), + owner.clone().into(), + request.clone(), + Some(Duration::from_secs( + EXTERNAL_PLANNED_CPU_GET_REPLAY_RPC_TIMEOUT_SECS, + )), + 0, + ) + .await; + if let Ok(response) = attempt { + release_planned_cpu_response_holders( + inner, + &response.serialize_part, + owner_start_time, + ); + return; + } + tokio::select! { + _ = tokio::time::sleep(Duration::from_secs(1)) => {} + _ = shutdown.wait() => return, + } + } + }); +} + +async fn run_external_planned_cpu_get( + view: ExternalClientApiView, + plan_handle: u64, + plan_items: Vec<(String, u64)>, + skipped_get_ids: Vec, + transfer_concurrency: usize, + cancel_requested: Arc, +) -> ExternalPlannedCpuGetTerminal { + let inner = view.external_client_api().inner(); + let mut all_plan_get_ids = skipped_get_ids.clone(); + all_plan_get_ids.extend(plan_items.iter().map(|(_, get_id)| *get_id)); + if let Err(err) = inner.master_batch_gpu_get_revoke(skipped_get_ids).await { + let cleanup = finish_planned_get_revoke_cleanup( + view.clone(), + all_plan_get_ids, + "planned CPU tail failure", + ) + .await + .err() + .map(|cleanup_err| cleanup_err.to_string()); + return ExternalPlannedCpuGetTerminal::Failed { + detail: format!( + "planned CPU Get could not revoke its unconsumed tail: {err}; cleanup_error={cleanup:?}" + ), + }; + } + if cancel_requested.load(Ordering::Acquire) { + let get_ids = plan_items.iter().map(|(_, get_id)| *get_id).collect(); + return match finish_planned_get_revoke_cleanup( + view.clone(), + get_ids, + "planned CPU pre-owner cancel", + ) + .await + { + Ok(()) => ExternalPlannedCpuGetTerminal::Revoked, + Err(err) => ExternalPlannedCpuGetTerminal::Failed { + detail: format!("planned CPU Get cancel cleanup failed: {err}"), + }, + }; + } + + if plan_items.is_empty() { + return ExternalPlannedCpuGetTerminal::Completed { + items: Vec::new(), + owner_start_time: inner.current_owner_start_time().await, + }; + } + + let Some(owner) = inner.shared_storage_node_id().await else { + let get_ids = plan_items.iter().map(|(_, get_id)| *get_id).collect(); + let cleanup = + finish_planned_get_revoke_cleanup(view.clone(), get_ids, "planned CPU missing owner") + .await + .err() + .map(|cleanup_err| cleanup_err.to_string()); + return ExternalPlannedCpuGetTerminal::Failed { + detail: format!( + "planned CPU Get has no current share-group owner; cleanup_error={cleanup:?}" + ), + }; + }; + let owner_start_time = inner.current_owner_start_time().await; + let external_client_id = inner.view.cluster_manager().get_self_info().id; + let request = MsgPack { + serialize_part: ExternalExecutePlannedGetReq { + plan_handle, + items: plan_items + .iter() + .map(|(key, get_id)| ExternalPlannedGetItem { + key: key.clone(), + get_id: *get_id, + }) + .collect(), + req_node_id: external_client_id, + started_time: owner_start_time, + transfer_concurrency, + }, + raw_bytes: Vec::new(), + }; + let response = match inner + .rpc_caller_external_execute_planned_get + .call( + inner.view.p2p_module(), + owner.clone().into(), + request.clone(), + Some(Duration::from_secs( + EXTERNAL_PLANNED_CPU_GET_FOREGROUND_RPC_TIMEOUT_SECS, + )), + 0, + ) + .await + { + Ok(response) => response.serialize_part, + Err(err) => { + spawn_uncertain_planned_cpu_get_cleanup(view.clone(), owner, request, owner_start_time); + return ExternalPlannedCpuGetTerminal::Failed { + detail: format!( + "planned CPU Get owner RPC failed; replay cleanup continues in background: error={}", + KvError::from(err) + ), + }; + } + }; + if response.error_code != OK || response.items.len() != plan_items.len() { + release_planned_cpu_response_holders(inner, &response, owner_start_time); + return ExternalPlannedCpuGetTerminal::Failed { + detail: format!( + "planned CPU Get owner response failed or changed shape: error_code={} expected={} got={} error_json={}", + response.error_code, + plan_items.len(), + response.items.len(), + response.error_json + ), + }; + } + if let Some((index, item)) = response + .items + .iter() + .enumerate() + .find(|(_, item)| item.error_code != OK || item.external_memholder_info.is_none()) + { + release_planned_cpu_response_holders(inner, &response, owner_start_time); + return ExternalPlannedCpuGetTerminal::Failed { + detail: format!( + "planned CPU Get item failed: index={} error_code={} error_json={}", + index, item.error_code, item.error_json + ), + }; + } + if cancel_requested.load(Ordering::Acquire) { + release_planned_cpu_response_holders(inner, &response, owner_start_time); + return ExternalPlannedCpuGetTerminal::Revoked; + } + ExternalPlannedCpuGetTerminal::Completed { + items: response.items, + owner_start_time, + } +} + +async fn run_external_gpu_get_transfer( + view: ExternalClientApiView, + transfer_items: Vec<(BatchGetStartItemResp, GpuMemoryGuard)>, + skipped_get_ids: Vec, + transfer_concurrency: usize, + cancel_requested: Arc, +) -> ExternalGpuGetTerminal { + let transfer_get_ids = transfer_items + .iter() + .map(|(item, _)| item.get_id) + .collect::>(); + let mut all_get_ids = skipped_get_ids.clone(); + all_get_ids.extend(transfer_get_ids.iter().copied()); + + let skipped_revoke_error = view + .external_client_api() + .inner() + .master_batch_gpu_get_revoke(skipped_get_ids) + .await + .err() + .map(|err| err.to_string()); + + if transfer_items.is_empty() { + return match skipped_revoke_error { + Some(detail) => ExternalGpuGetTerminal::Failed { + detail: format!("GPU Get could not revoke non-transferable starts: {detail}"), + }, + None => ExternalGpuGetTerminal::Revoked { + transfer_error: None, + }, + }; + } + + let transfer_futures = transfer_items.into_iter().map(|(item, gpu_guard)| { + let transfer_view = view.clone(); + let cancel_requested = cancel_requested.clone(); + async move { + if cancel_requested.load(Ordering::Acquire) { + return None; + } + transfer_view + .client_transfer_engine() + .transfer_data_no_copy_to_gpu( + item.node_id.clone(), + item.src_addr, + item.target_addr, + item.len, + gpu_guard, + ) + .await + .err() + .map(|err| { + format!( + "GPU Get transfer failed: get_id={} source={} src={:#x} target={:#x} len={} error={}", + item.get_id, + item.node_id, + item.src_addr, + item.target_addr, + item.len, + err + ) + }) + } + }); + let mut transfer_stream = + stream::iter(transfer_futures).buffer_unordered(transfer_concurrency.max(1)); + let mut transfer_error = None; + while let Some(item_error) = transfer_stream.next().await { + if transfer_error.is_none() { + transfer_error = item_error; + } + } + + let cancelled = cancel_requested.load(Ordering::Acquire); + if cancelled || transfer_error.is_some() || skipped_revoke_error.is_some() { + if let Err(err) = view + .external_client_api() + .inner() + .master_batch_gpu_get_revoke(all_get_ids) + .await + { + return ExternalGpuGetTerminal::Failed { + detail: format!( + "GPU Get cleanup failed after transfer/cancel: transfer_error={:?} skipped_revoke_error={:?} revoke_error={}", + transfer_error, skipped_revoke_error, err + ), + }; + } + if let Some(detail) = skipped_revoke_error { + return ExternalGpuGetTerminal::Failed { + detail: format!( + "GPU Get initially failed to revoke non-transferable starts: {detail}" + ), + }; + } + return ExternalGpuGetTerminal::Revoked { transfer_error }; + } + match view .external_client_api() .inner() @@ -741,6 +1535,27 @@ async fn run_external_gpu_get_transfer( } } +async fn run_external_gpu_get_transfer_timed( + view: ExternalClientApiView, + transfer_items: Vec<(BatchGetStartItemResp, GpuMemoryGuard)>, + skipped_get_ids: Vec, + transfer_concurrency: usize, + cancel_requested: Arc, +) -> ExternalGpuGetTerminalEvent { + let outcome = run_external_gpu_get_transfer( + view, + transfer_items, + skipped_get_ids, + transfer_concurrency, + cancel_requested, + ) + .await; + ExternalGpuGetTerminalEvent { + outcome, + terminal_at: Instant::now(), + } +} + impl ExternalClientApi { /// Access inner external-only API. Safe to unwrap in external role. pub fn inner(&self) -> &ExternalInner { @@ -778,12 +1593,18 @@ impl ExternalClientApi { .build(), rpc_caller_external_get: RPCCaller::::new(), rpc_caller_external_batch_get: RPCCaller::::new(), + rpc_caller_external_batch_get_local_probe: + RPCCaller::::new(), rpc_caller_external_batch_get_start: RPCCaller::::new(), rpc_caller_external_batch_get_transfer: RPCCaller::::new(), rpc_caller_external_batch_get_cancel: RPCCaller::::new(), rpc_caller_master_batch_get_start: RPCCaller::::new(), + rpc_caller_master_batch_get_plan: RPCCaller::::new(), + rpc_caller_master_batch_get_bind: RPCCaller::::new(), rpc_caller_master_batch_get_done: RPCCaller::::new(), rpc_caller_master_batch_get_revoke: RPCCaller::::new(), + rpc_caller_external_execute_planned_get: RPCCaller::::new( + ), rpc_caller_external_put_commit: RPCCaller::::new(), rpc_caller_external_batch_put_commit: RPCCaller::::new(), rpc_caller_external_put_start: RPCCaller::::new(), @@ -805,7 +1626,9 @@ impl ExternalClientApi { pending_external_get_start: DashMap::new(), pending_inline_external_get_start: DashMap::new(), next_gpu_get_handle: AtomicU64::new(1), + pending_external_get_plan: DashMap::new(), pending_external_gpu_get: DashMap::new(), + pending_external_planned_cpu_get: DashMap::new(), inflight1_per_key: SemaphoreMap::new(1, std::time::Duration::from_secs(120)), put_trace_log_window: Mutex::new(ExternalPutTraceLogWindow::new()), external_delete_ack_batch: ExternalDeleteAckBatchHandle::new(), @@ -879,6 +1702,8 @@ impl ExternalClientApi { ext.rpc_caller_external_get.regist(ext.view.p2p_module()); ext.rpc_caller_external_batch_get .regist(ext.view.p2p_module()); + ext.rpc_caller_external_batch_get_local_probe + .regist(ext.view.p2p_module()); ext.rpc_caller_external_batch_get_start .regist(ext.view.p2p_module()); ext.rpc_caller_external_batch_get_transfer @@ -887,10 +1712,16 @@ impl ExternalClientApi { .regist(ext.view.p2p_module()); ext.rpc_caller_master_batch_get_start .regist(ext.view.p2p_module()); + ext.rpc_caller_master_batch_get_plan + .regist(ext.view.p2p_module()); + ext.rpc_caller_master_batch_get_bind + .regist(ext.view.p2p_module()); ext.rpc_caller_master_batch_get_done .regist(ext.view.p2p_module()); ext.rpc_caller_master_batch_get_revoke .regist(ext.view.p2p_module()); + ext.rpc_caller_external_execute_planned_get + .regist(ext.view.p2p_module()); ext.rpc_caller_external_put_commit .regist(ext.view.p2p_module()); ext.rpc_caller_external_batch_put_commit @@ -1147,8 +1978,7 @@ impl ExternalClientApi { ); loop { let snapshot = ext.view.p2p_module().tier_snapshot(); - let self_binding_ready = snapshot - .share_group_owner(&snapshot.self_peer_gen.peer_id) + let self_binding_ready = snapshot.share_group_owner(&snapshot.self_peer_gen.peer_id) == Some(&expected_binding); if self_binding_ready && let Some(peer_gen) = snapshot.peer_gen(&owner_node_id) @@ -2366,82 +3196,806 @@ impl ExternalInner { ), })); } - for (expected_get_id, item) in expected_get_ids - .into_iter() - .zip(resp.serialize_part.items.into_iter()) + for (expected_get_id, item) in expected_get_ids + .into_iter() + .zip(resp.serialize_part.items.into_iter()) + { + if item.get_id != expected_get_id { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "GPU Get BatchRevoke response identity mismatch: expected={} got={}", + expected_get_id, item.get_id + ), + })); + } + crate::rpcresp_kvresult_convert::try_from_code(item.error_code, item.error_json)?; + } + Ok(()) + } + + async fn master_batch_gpu_get_done(&self, get_ids: Vec) -> KvResult<()> { + if get_ids.is_empty() { + return Ok(()); + } + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let expected_get_ids = get_ids.clone(); + let resp: MsgPack = self + .rpc_caller_master_batch_get_done + .call( + self.view.p2p_module(), + master_node_id.into(), + MsgPack { + serialize_part: BatchGetDoneReq { get_ids }, + raw_bytes: Vec::new(), + }, + None, + 0, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + if resp.serialize_part.items.len() != expected_get_ids.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "GPU Get BatchDone response length mismatch: expected={} got={}", + expected_get_ids.len(), + resp.serialize_part.items.len() + ), + })); + } + for (expected_get_id, item) in expected_get_ids + .into_iter() + .zip(resp.serialize_part.items.into_iter()) + { + if item.get_id != expected_get_id { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "GPU Get BatchDone response identity mismatch: expected={} got={}", + expected_get_id, item.get_id + ), + })); + } + crate::rpcresp_kvresult_convert::try_from_code(item.error_code, item.error_json)?; + if item.holder_id != 0 || item.allocation_mode != GetAllocationMode::ExternalSink { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "GPU Get BatchDone returned a cache-owned target: get_id={} holder_id={} allocation_mode={:?}", + item.get_id, item.holder_id, item.allocation_mode + ), + })); + } + } + Ok(()) + } + + async fn master_batch_get_bind_external( + &self, + plan_items: &[BatchGetPlanItemResp], + destinations: &[ExternalGpuDestination], + requester_node_start_time: i64, + ) -> KvResult> { + if plan_items.len() != destinations.len() { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "external GetBind plan/destination length mismatch: plan={} destinations={}", + plan_items.len(), + destinations.len() + ), + })); + } + let items = plan_items + .iter() + .zip(destinations) + .map(|(plan, destination)| BatchGetBindItemReq { + get_id: plan.get_id, + target: GetBindTarget::ExternalSink(GetExternalSinkTarget { + addr: destination.addr, + capacity: destination.capacity, + registration_id: destination.registration_id, + requester_node_start_time, + }), + }) + .collect(); + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let response: MsgPack = self + .rpc_caller_master_batch_get_bind + .call( + self.view.p2p_module(), + master_node_id.into(), + MsgPack { + serialize_part: BatchGetBindReq { items }, + raw_bytes: Vec::new(), + }, + None, + 0, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + response.serialize_part.error_code, + response.serialize_part.error_json.clone(), + )?; + if response.serialize_part.items.len() != plan_items.len() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external GetBind response length mismatch: expected={} got={}", + plan_items.len(), + response.serialize_part.items.len() + ), + })); + } + for (plan, bound) in plan_items.iter().zip(&response.serialize_part.items) { + if bound.get_id != plan.get_id { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "external GetBind response identity mismatch: expected={} got={}", + plan.get_id, bound.get_id + ), + })); + } + crate::rpcresp_kvresult_convert::try_from_code( + bound.error_code, + bound.error_json.clone(), + )?; + } + Ok(response.serialize_part.items) + } + + async fn probe_owner_local_gets( + &self, + plan_handle: u64, + keys: &[String], + ) -> KvResult>>> { + let mut previous_owner_start_time = self.current_owner_start_time().await; + let mut recover_attempts = 0usize; + loop { + let (owner, owner_start_time, _, base_ptr, mapped_len) = + self.wait_current_owner_mapped_range().await?; + let request = MsgPack { + serialize_part: ExternalBatchGetLocalProbeReq { + plan_handle, + keys: keys.to_vec(), + req_node_id: self.view.cluster_manager().get_self_info().id.clone(), + started_time: owner_start_time, + }, + raw_bytes: Vec::new(), + }; + let response: MsgPack = match self + .rpc_caller_external_batch_get_local_probe + .call(self.view.p2p_module(), owner.into(), request, None, 0) + .await + { + Ok(response) => response, + Err(error) => { + let error = KvError::from(error); + if matches!(&error, KvError::P2p(_)) + && recover_attempts < EXTERNAL_RPC_P2P_RECOVER_MAX_ATTEMPTS + { + recover_attempts += 1; + let _ = self + .recover_after_p2p_error(&mut previous_owner_start_time) + .await?; + continue; + } + return Err(error); + } + }; + if response.serialize_part.error_code != OK { + let error = KvError::from_json( + response.serialize_part.error_code, + &response.serialize_part.error_json, + ); + if matches!( + &error, + KvError::Api(ApiError::OwnerStartTimeMismatch { .. }) + ) { + let _ = self + .recover_after_owner_start_time_mismatch(&mut previous_owner_start_time) + .await?; + continue; + } + return Err(error); + } + let infos = response.serialize_part.items; + let release_infos = |infos: &[Option]| { + let external_client_id = self.view.cluster_manager().get_self_info().id.clone(); + for info in infos.iter().flatten() { + if let Err(error) = self.enqueue_external_delete_ack( + external_client_id.clone(), + info.holder_id, + owner_start_time, + ) { + tracing::warn!( + plan_handle, + holder_id = info.holder_id, + %error, + "owner-local Get probe cleanup enqueue failed" + ); + } + } + }; + if infos.len() != keys.len() { + release_infos(&infos); + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "owner-local Get probe length mismatch: expected={} got={}", + keys.len(), + infos.len() + ), + })); + } + let mut holders = Vec::with_capacity(keys.len()); + for (index, (key, info)) in keys.iter().zip(&infos).enumerate() { + let Some(info) = info else { + holders.push(None); + continue; + }; + let Some(end) = info.offset.checked_add(u64::from(info.len)) else { + release_infos(&infos); + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "owner-local Get probe range overflow: index={} offset={} len={}", + index, info.offset, info.len + ), + })); + }; + if end > mapped_len { + release_infos(&infos); + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "owner-local Get probe exceeds owner mapping: index={} end={} mapped_len={}", + index, end, mapped_len + ), + })); + } + let Some(pointer) = base_ptr.checked_add(info.offset) else { + release_infos(&infos); + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "owner-local Get probe pointer overflow: index={} base={:#x} offset={}", + index, base_ptr, info.offset + ), + })); + }; + let holder = Arc::new(ExternalMemHolder::new( + info.offset, + pointer, + info.len, + info.holder_id, + key.clone(), + self.view.cluster_manager().get_self_info().id.clone(), + self.view.clone(), + owner_start_time, + )); + self.key_weak_memholder_index + .insert(key.clone(), Arc::downgrade(&holder)); + holders.push(Some(holder)); + } + return Ok(holders); + } + } + + pub async fn get_plan( + &self, + keys: Vec, + prefix_best_effort: bool, + atomic_group_lens: Option>, + ) -> KvResult { + if keys.is_empty() { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: "get_plan requires at least one key".to_string(), + })); + } + let group_lens = normalize_external_get_start_group_lens(keys.len(), atomic_group_lens)?; + let self_info = self.view.cluster_manager().get_self_info(); + if self_info.node_role() != NodeRole::External { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: "get_plan is supported only in external-client mode".to_string(), + })); + } + let handle = self.next_gpu_get_handle.fetch_add(1, Ordering::Relaxed); + if handle == 0 { + return Err(KvError::Api(ApiError::Unknown { + detail: "get_plan local handle space exhausted".to_string(), + })); + } + + // Resolve and pin owner-local pages before consulting the cluster + // directory. Only the remaining positions are remote plan work. + let local_holders = self.probe_owner_local_gets(handle, &keys).await?; + let remote_keys = keys + .iter() + .zip(&local_holders) + .filter_map(|(key, local)| local.is_none().then_some(key.clone())) + .collect::>(); + let plan_items = if remote_keys.is_empty() { + Vec::new() + } else { + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let response: MsgPack = self + .rpc_caller_master_batch_get_plan + .call( + self.view.p2p_module(), + master_node_id.into(), + MsgPack { + serialize_part: BatchGetPlanReq { + keys: remote_keys.clone(), + }, + raw_bytes: Vec::new(), + }, + None, + 0, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + response.serialize_part.error_code, + response.serialize_part.error_json.clone(), + )?; + response.serialize_part.items + }; + let started_get_ids = plan_items + .iter() + .filter(|item| item.error_code == OK) + .map(|item| item.get_id) + .collect::>(); + let mut cleanup_guard = PlannedGetRevokeGuard::new( + self.view.clone_view(), + started_get_ids.clone(), + "get_plan abandoned", + ); + if plan_items.len() != remote_keys.len() { + let cleanup = finish_planned_get_revoke_cleanup( + self.view.clone_view(), + started_get_ids, + "get_plan shape failure", + ) + .await + .err() + .map(|err| err.to_string()); + if cleanup.is_none() { + cleanup_guard.disarm(); + } + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "get_plan response length mismatch: expected={} got={} cleanup_error={cleanup:?}", + remote_keys.len(), + plan_items.len() + ), + })); + } + for item in &plan_items { + if item.error_code != OK + && item.error_code + != crate::rpcresp_kvresult_convert::msg_and_error::codes_api::API_KEY_NOT_FOUND + { + let error = crate::rpcresp_kvresult_convert::try_from_code( + item.error_code, + item.error_json.clone(), + ) + .expect_err("non-OK GetPlan item must decode as an error"); + let cleanup = finish_planned_get_revoke_cleanup( + self.view.clone_view(), + started_get_ids, + "get_plan item failure", + ) + .await + .err() + .map(|err| err.to_string()); + if cleanup.is_none() { + cleanup_guard.disarm(); + } + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "get_plan item failed: error={} cleanup_error={cleanup:?}", + error + ), + })); + } + } + let mut remote_items = plan_items.into_iter(); + let mut combined_items = Vec::with_capacity(keys.len()); + for (key, local) in keys.iter().cloned().zip(local_holders) { + if let Some(holder) = local { + combined_items.push(PendingExternalGetPlanItem::Local { holder }); + } else { + let plan = remote_items + .next() + .expect("validated remote plan shape must cover every remote key"); + combined_items.push(PendingExternalGetPlanItem::Remote { key, plan }); + } + } + assert!(remote_items.next().is_none()); + let (raw_prefix_hit_len, gpu_raw_prefix_hit_len) = + external_get_plan_raw_prefixes_from_statuses(combined_items.iter().map( + |item| match item { + PendingExternalGetPlanItem::Local { .. } => (true, true), + PendingExternalGetPlanItem::Remote { plan, .. } => { + (plan.error_code == OK, plan.gpu_direct_eligible) + } + }, + )); + let transferable_len = compute_external_get_start_transfer_prefix( + raw_prefix_hit_len, + &group_lens, + prefix_best_effort, + ); + let gpu_transferable_len = compute_external_get_start_transfer_prefix( + gpu_raw_prefix_hit_len, + &group_lens, + prefix_best_effort, + ); + let kept_ids = combined_items[..transferable_len] + .iter() + .filter_map(|item| match item { + PendingExternalGetPlanItem::Remote { plan, .. } => Some(plan.get_id), + PendingExternalGetPlanItem::Local { .. } => None, + }) + .collect::>(); + let skipped_get_ids = started_get_ids + .iter() + .copied() + .filter(|get_id| !kept_ids.contains(get_id)) + .collect::>(); + if let Err(err) = self.master_batch_gpu_get_revoke(skipped_get_ids).await { + return Err(err); + } + combined_items.truncate(transferable_len); + let gpu_remote_indices = combined_items + .iter() + .take(gpu_transferable_len) + .enumerate() + .filter_map(|(index, item)| { + matches!(item, PendingExternalGetPlanItem::Remote { .. }).then_some(index) + }) + .collect::>(); + self.pending_external_get_plan.insert( + handle, + PendingExternalGetPlan { + items: combined_items, + transferable_len, + gpu_transferable_len, + gpu_remote_indices: gpu_remote_indices.clone(), + atomic_group_lens: group_lens, + }, + ); + cleanup_guard.disarm(); + Ok(ExternalGetPlanResp { + handle, + raw_prefix_hit_len, + gpu_raw_prefix_hit_len, + gpu_remote_indices, + }) + } + + pub async fn cancel_get_plan(&self, handle: u64) -> KvResult<()> { + let Some((_handle, plan)) = self.pending_external_get_plan.remove(&handle) else { + return Ok(()); + }; + finish_planned_get_revoke_cleanup( + self.view.clone_view(), + plan.items + .into_iter() + .filter_map(|item| match item { + PendingExternalGetPlanItem::Remote { plan, .. } => Some(plan.get_id), + PendingExternalGetPlanItem::Local { .. } => None, + }) + .collect(), + "cancel_get_plan", + ) + .await + } + + pub async fn execute_get_plan_gpu( + &self, + handle: u64, + destinations: Vec, + consume_prefix_len: usize, + transfer_concurrency: usize, + ) -> KvResult<()> { + let Some((_handle, plan)) = self.pending_external_get_plan.remove(&handle) else { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!("execute_get_plan_gpu requires a live plan: {handle}"), + })); + }; + let expected_remote_destinations = plan + .gpu_remote_indices + .iter() + .take_while(|index| **index < consume_prefix_len) + .count(); + if transfer_concurrency == 0 + || expected_remote_destinations == 0 + || destinations.len() != expected_remote_destinations + || validate_external_get_consume_prefix( + consume_prefix_len, + plan.gpu_transferable_len, + &plan.atomic_group_lens, + ) + .is_err() + { + self.pending_external_get_plan.insert(handle, plan); + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "execute_get_plan_gpu invalid consume/remote-destinations/concurrency: consume={} destinations={} expected_remote={} concurrency={}", + consume_prefix_len, + destinations.len(), + expected_remote_destinations, + transfer_concurrency + ), + })); + } + let self_info = self.view.cluster_manager().get_self_info(); + let mut guards = Vec::with_capacity(destinations.len()); + for destination in &destinations { + match self.view.client_transfer_engine().validate_gpu_destination( + destination.registration_id, + destination.addr, + destination.capacity, + ) { + Ok(guard) => guards.push(guard), + Err(err) => { + self.pending_external_get_plan.insert(handle, plan); + return Err(err); + } + } + } + let all_get_ids = plan + .items + .iter() + .filter_map(|item| match item { + PendingExternalGetPlanItem::Remote { plan, .. } => Some(plan.get_id), + PendingExternalGetPlanItem::Local { .. } => None, + }) + .collect::>(); + let mut cleanup_guard = PlannedGetRevokeGuard::new( + self.view.clone_view(), + all_get_ids.clone(), + "execute_get_plan_gpu abandoned", + ); + if plan + .items + .iter() + .any(|item| matches!(item, PendingExternalGetPlanItem::Local { .. })) + { + let (_, current_owner_start_time, _, base_ptr, mapped_len) = + self.wait_current_owner_mapped_range().await?; + for (index, item) in plan.items.iter().enumerate() { + if let PendingExternalGetPlanItem::Local { holder } = item { + validate_external_local_holder_mapping( + index, + holder, + current_owner_start_time, + base_ptr, + mapped_len, + )?; + } + } + } + let PendingExternalGetPlan { + mut items, + atomic_group_lens, + .. + } = plan; + let tail_items = items.split_off(consume_prefix_len); + let skipped_get_ids = tail_items + .into_iter() + .filter_map(|item| match item { + PendingExternalGetPlanItem::Remote { plan, .. } => Some(plan.get_id), + PendingExternalGetPlanItem::Local { .. } => None, + }) + .collect::>(); + let mut remote_plans = Vec::with_capacity(destinations.len()); + let mut local_holders = Vec::new(); + let mut value_ptrs = Vec::with_capacity(consume_prefix_len); + let mut destination_index = 0usize; + for (source_index, item) in items.into_iter().enumerate() { + match item { + PendingExternalGetPlanItem::Local { holder, .. } => { + // The exact owner mapping was validated immediately above. + // Keep the saved address opaque until SGLang submits the + // restore; constructing a slice here would dereference a + // mapping that could become stale after an owner restart. + value_ptrs.push(holder.addr); + local_holders.push((source_index, holder)); + } + PendingExternalGetPlanItem::Remote { plan, .. } => { + let destination = &destinations[destination_index]; + value_ptrs.push(destination.addr); + remote_plans.push(plan); + destination_index += 1; + } + } + } + assert_eq!(destination_index, destinations.len()); + let bound_items = match self + .master_batch_get_bind_external(&remote_plans, &destinations, self_info.node_start_time) + .await { - if item.get_id != expected_get_id { + Ok(items) => items, + Err(err) => { + let cleanup = finish_planned_get_revoke_cleanup( + self.view.clone_view(), + all_get_ids, + "execute_get_plan_gpu bind failure", + ) + .await + .err() + .map(|cleanup_err| cleanup_err.to_string()); + if cleanup.is_none() { + cleanup_guard.disarm(); + } return Err(KvError::Api(ApiError::Unknown { detail: format!( - "GPU Get BatchRevoke response identity mismatch: expected={} got={}", - expected_get_id, item.get_id + "execute_get_plan_gpu bind failed: error={} cleanup_error={cleanup:?}", + err ), })); } - crate::rpcresp_kvresult_convert::try_from_code(item.error_code, item.error_json)?; + }; + let mut transfer_items = Vec::with_capacity(destinations.len()); + for (index, (((planned, bound), destination), guard)) in remote_plans + .iter() + .zip(bound_items) + .zip(destinations.iter()) + .zip(guards) + .enumerate() + { + if bound.node_id != planned.node_id + || bound.src_addr != planned.src_addr + || bound.src_base_addr != planned.src_base_addr + || bound.len != planned.len + || !external_gpu_transfer_plan_geometry_is_valid( + &bound, + destination, + guard.registration().registration_id, + ) + || bound.node_id == self_info.id + { + let cleanup = finish_planned_get_revoke_cleanup( + self.view.clone_view(), + all_get_ids, + "execute_get_plan_gpu changed bind", + ) + .await + .err() + .map(|cleanup_err| cleanup_err.to_string()); + if cleanup.is_none() { + cleanup_guard.disarm(); + } + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "execute_get_plan_gpu received a changed bind plan at index={index}; cleanup_error={cleanup:?}" + ), + })); + } + transfer_items.push((bound, guard)); } + let cancel_requested = Arc::new(AtomicBool::new(false)); + let (terminal_tx, terminal_rx) = watch::channel(None); + let transfer_started_at = Instant::now(); + self.pending_external_gpu_get.insert( + handle, + PendingExternalGpuGet { + transferable_len: consume_prefix_len, + atomic_group_lens, + value_ptrs, + local_holders, + cancel_requested: cancel_requested.clone(), + transfer_started_at, + terminal_rx, + }, + ); + let view = self.view.clone_view(); + let task_view = view.clone(); + view.spawn(format!("external_gpu_get_execute_{handle}"), async move { + let terminal = run_external_gpu_get_transfer_timed( + task_view, + transfer_items, + skipped_get_ids, + transfer_concurrency, + cancel_requested, + ) + .await; + let _ = terminal_tx.send(Some(terminal)); + }); + cleanup_guard.disarm(); Ok(()) } - async fn master_batch_gpu_get_done(&self, get_ids: Vec) -> KvResult<()> { - if get_ids.is_empty() { - return Ok(()); - } - let master_node_id = self - .view - .cluster_manager() - .find_or_wait_master_node() - .await?; - let expected_get_ids = get_ids.clone(); - let resp: MsgPack = self - .rpc_caller_master_batch_get_done - .call( - self.view.p2p_module(), - master_node_id.into(), - MsgPack { - serialize_part: BatchGetDoneReq { get_ids }, - raw_bytes: Vec::new(), - }, - None, - 0, + pub async fn execute_get_plan_cpu( + &self, + handle: u64, + consume_prefix_len: usize, + transfer_concurrency: usize, + ) -> KvResult<()> { + let Some((_handle, plan)) = self.pending_external_get_plan.remove(&handle) else { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!("execute_get_plan_cpu requires a live plan: {handle}"), + })); + }; + if transfer_concurrency == 0 + || validate_external_get_consume_prefix( + consume_prefix_len, + plan.transferable_len, + &plan.atomic_group_lens, ) - .await - .map_err(KvError::from)?; - crate::rpcresp_kvresult_convert::try_from_code( - resp.serialize_part.error_code, - resp.serialize_part.error_json.clone(), - )?; - if resp.serialize_part.items.len() != expected_get_ids.len() { - return Err(KvError::Api(ApiError::Unknown { + .is_err() + { + self.pending_external_get_plan.insert(handle, plan); + return Err(KvError::Api(ApiError::InvalidArgument { detail: format!( - "GPU Get BatchDone response length mismatch: expected={} got={}", - expected_get_ids.len(), - resp.serialize_part.items.len() + "execute_get_plan_cpu invalid consume/concurrency: consume={} concurrency={}", + consume_prefix_len, transfer_concurrency ), })); } - for (expected_get_id, item) in expected_get_ids + let PendingExternalGetPlan { + mut items, + atomic_group_lens, + .. + } = plan; + let tail_items = items.split_off(consume_prefix_len); + let skipped_get_ids = tail_items .into_iter() - .zip(resp.serialize_part.items.into_iter()) - { - if item.get_id != expected_get_id { - return Err(KvError::Api(ApiError::Unknown { - detail: format!( - "GPU Get BatchDone response identity mismatch: expected={} got={}", - expected_get_id, item.get_id - ), - })); - } - crate::rpcresp_kvresult_convert::try_from_code(item.error_code, item.error_json)?; - if item.holder_id != 0 || item.allocation_mode != GetAllocationMode::ExternalSink { - return Err(KvError::Api(ApiError::Unknown { - detail: format!( - "GPU Get BatchDone returned a cache-owned target: get_id={} holder_id={} allocation_mode={:?}", - item.get_id, item.holder_id, item.allocation_mode - ), - })); + .filter_map(|item| match item { + PendingExternalGetPlanItem::Remote { plan, .. } => Some(plan.get_id), + PendingExternalGetPlanItem::Local { .. } => None, + }) + .collect(); + let mut plan_items = Vec::new(); + let mut sources = Vec::with_capacity(consume_prefix_len); + for item in items { + match item { + PendingExternalGetPlanItem::Local { holder, .. } => { + sources.push(PendingExternalCpuSource::Local { holder }); + } + PendingExternalGetPlanItem::Remote { key, plan } => { + plan_items.push((key.clone(), plan.get_id)); + sources.push(PendingExternalCpuSource::Remote { key }); + } } } + let cancel_requested = Arc::new(AtomicBool::new(false)); + let (terminal_tx, terminal_rx) = watch::channel(None); + self.pending_external_planned_cpu_get.insert( + handle, + PendingExternalPlannedCpuGet { + sources, + transferable_len: consume_prefix_len, + atomic_group_lens, + cancel_requested: cancel_requested.clone(), + terminal_rx, + }, + ); + let view = self.view.clone_view(); + let task_view = view.clone(); + view.spawn(format!("external_cpu_get_execute_{handle}"), async move { + let terminal = run_external_planned_cpu_get( + task_view, + handle, + plan_items, + skipped_get_ids, + transfer_concurrency, + cancel_requested, + ) + .await; + let _ = terminal_tx.send(Some(terminal)); + }); Ok(()) } @@ -2647,19 +4201,27 @@ impl ExternalInner { } let cancel_requested = Arc::new(AtomicBool::new(false)); let (terminal_tx, terminal_rx) = watch::channel(None); + let transfer_started_at = Instant::now(); self.pending_external_gpu_get.insert( handle, PendingExternalGpuGet { transferable_len, atomic_group_lens: group_lens, + value_ptrs: destinations + .into_iter() + .take(transferable_len) + .map(|destination| destination.addr) + .collect(), + local_holders: Vec::new(), cancel_requested: cancel_requested.clone(), + transfer_started_at, terminal_rx, }, ); let view = self.view.clone_view(); let view_task = view.clone(); view.spawn(format!("external_gpu_get_transfer_{handle}"), async move { - let terminal = run_external_gpu_get_transfer( + let terminal = run_external_gpu_get_transfer_timed( view_task, transfer_items, skipped_get_ids, @@ -2680,26 +4242,95 @@ impl ExternalInner { handle: u64, consume_prefix_len: Option, ) -> KvResult { + let consume_started_at = Instant::now(); let Some((_, pending)) = self.pending_external_gpu_get.remove(&handle) else { return Err(KvError::Api(ApiError::InvalidArgument { detail: format!("get_transfer_gpu requires a live handle: {handle}"), })); }; - let consumed_prefix_len = consume_prefix_len.unwrap_or(pending.transferable_len); + let pending_guard = + PendingRegistryEntryGuard::new(&self.pending_external_gpu_get, handle, pending); + let consumed_prefix_len = + consume_prefix_len.unwrap_or(pending_guard.entry().transferable_len); if let Err(err) = validate_external_get_consume_prefix( consumed_prefix_len, - pending.transferable_len, - &pending.atomic_group_lens, + pending_guard.entry().transferable_len, + &pending_guard.entry().atomic_group_lens, ) { - self.pending_external_gpu_get.insert(handle, pending); return Err(err); } - let terminal = wait_external_gpu_get_terminal(pending.terminal_rx).await?; - match terminal { - ExternalGpuGetTerminal::Completed => Ok(ExternalGpuGetTransferResp { - transferred_prefix_len: pending.transferable_len, - consumed_prefix_len, - }), + let finish_wait_started_at = Instant::now(); + let terminal_event = + match wait_external_gpu_get_terminal(pending_guard.entry().terminal_rx.clone()).await { + Ok(terminal) => terminal, + Err(err) => { + let _ = pending_guard.take(); + return Err(err); + } + }; + let finish_wait = finish_wait_started_at.elapsed(); + let pending = pending_guard.take(); + let timing = observe_external_gpu_get_consume_timing( + pending.transfer_started_at, + terminal_event.terminal_at, + consume_started_at, + finish_wait, + ); + let outcome = match &terminal_event.outcome { + ExternalGpuGetTerminal::Completed => "completed", + ExternalGpuGetTerminal::Revoked { .. } => "revoked", + ExternalGpuGetTerminal::Failed { .. } => "failed", + }; + tracing::info!( + "external GPU Get consume lifecycle: handle={} transferred={} consumed={} outcome={} transfer_wall_us={} terminal_before_consume={} terminal_to_consume_us={} finish_wait_us={}", + handle, + pending.transferable_len, + consumed_prefix_len, + outcome, + timing.transfer_wall_us, + timing.terminal_before_consume, + timing.terminal_to_consume_us, + timing.finish_wait_us, + ); + match terminal_event.outcome { + ExternalGpuGetTerminal::Completed => { + assert_eq!(pending.value_ptrs.len(), pending.transferable_len); + if !pending.local_holders.is_empty() { + let (_, current_owner_start_time, _, base_ptr, mapped_len) = + self.wait_current_owner_mapped_range().await?; + validate_external_local_holders_mapping( + &pending.local_holders, + current_owner_start_time, + base_ptr, + mapped_len, + )?; + } + let bandwidth_handle = self + .view + .cluster_manager() + .ipc_bandwidth_attributor_handle() + .expect("GPU get_transfer expects an IPC bandwidth handle"); + let local_holders = pending + .local_holders + .into_iter() + .filter_map(|(index, holder)| { + (index < consumed_prefix_len).then(|| { + bandwidth_handle.record_tx_bytes(u64::from(holder.len)); + holder + }) + }) + .collect(); + Ok(ExternalGpuGetTransferResp { + transferred_prefix_len: pending.transferable_len, + consumed_prefix_len, + value_ptrs: pending.value_ptrs[..consumed_prefix_len].to_vec(), + local_holders, + transfer_wall_us: timing.transfer_wall_us, + finish_wait_us: timing.finish_wait_us, + terminal_before_consume: timing.terminal_before_consume, + terminal_to_consume_us: timing.terminal_to_consume_us, + }) + } ExternalGpuGetTerminal::Revoked { transfer_error } => { Err(KvError::Api(ApiError::Unknown { detail: format!( @@ -2719,7 +4350,10 @@ impl ExternalInner { return Ok(()); }; pending.cancel_requested.store(true, Ordering::Release); - match wait_external_gpu_get_terminal(pending.terminal_rx).await? { + match wait_external_gpu_get_terminal(pending.terminal_rx) + .await? + .outcome + { ExternalGpuGetTerminal::Completed | ExternalGpuGetTerminal::Revoked { .. } => Ok(()), ExternalGpuGetTerminal::Failed { detail } => { Err(KvError::Api(ApiError::Unknown { detail })) @@ -3241,6 +4875,212 @@ impl ExternalInner { handle: u64, consume_prefix_len: Option, ) -> KvResult>>>> { + if let Some((_handle, pending)) = self.pending_external_planned_cpu_get.remove(&handle) { + let pending_guard = PendingRegistryEntryGuard::new( + &self.pending_external_planned_cpu_get, + handle, + pending, + ); + let consumed_prefix_len = + consume_prefix_len.unwrap_or(pending_guard.entry().transferable_len); + if let Err(err) = validate_external_get_consume_prefix( + consumed_prefix_len, + pending_guard.entry().transferable_len, + &pending_guard.entry().atomic_group_lens, + ) { + return Err(err); + } + let terminal = match wait_external_planned_cpu_get_terminal( + pending_guard.entry().terminal_rx.clone(), + ) + .await + { + Ok(terminal) => terminal, + Err(err) => { + let _ = pending_guard.take(); + return Err(err); + } + }; + let ExternalPlannedCpuGetTerminal::Completed { + items, + owner_start_time, + } = terminal + else { + let _ = pending_guard.take(); + return Err(KvError::Api(ApiError::Unknown { + detail: match terminal { + ExternalPlannedCpuGetTerminal::Revoked => { + format!("planned CPU Get was revoked: handle={handle}") + } + ExternalPlannedCpuGetTerminal::Failed { detail } => detail, + ExternalPlannedCpuGetTerminal::Completed { .. } => unreachable!(), + }, + })); + }; + let response = ExternalExecutePlannedGetResp { + items: items.clone(), + error_code: OK, + error_json: String::new(), + }; + let expected_remote_items = pending_guard + .entry() + .sources + .iter() + .filter(|source| matches!(source, PendingExternalCpuSource::Remote { .. })) + .count(); + if items.len() != expected_remote_items { + release_planned_cpu_response_holders(self, &response, owner_start_time); + let _ = pending_guard.take(); + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "planned CPU Get terminal remote length mismatch: expected={} got={}", + expected_remote_items, + items.len() + ), + })); + } + let owner_snapshot = match self.wait_current_owner_mapped_range().await { + Ok(snapshot) => snapshot, + Err(err) => { + release_planned_cpu_response_holders(self, &response, owner_start_time); + let _ = pending_guard.take(); + return Err(err); + } + }; + let (_, current_owner_start_time, _, base_ptr, mapped_len) = owner_snapshot; + if let Err(err) = validate_inline_external_get_owner_generation( + owner_start_time, + current_owner_start_time, + ) { + release_planned_cpu_response_holders(self, &response, owner_start_time); + let _ = pending_guard.take(); + return Err(err); + } + if let Some(local) = + pending_guard + .entry() + .sources + .iter() + .find_map(|source| match source { + PendingExternalCpuSource::Local { holder } + if holder.owner_start_time != current_owner_start_time => + { + Some(holder.owner_start_time) + } + _ => None, + }) + { + release_planned_cpu_response_holders(self, &response, owner_start_time); + let _ = pending_guard.take(); + return Err(KvError::Api(ApiError::OwnerStartTimeMismatch { + expected: current_owner_start_time, + got: local, + })); + } + for (index, item) in items.iter().enumerate() { + let Some(info) = item.external_memholder_info.as_ref() else { + release_planned_cpu_response_holders(self, &response, owner_start_time); + let _ = pending_guard.take(); + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "planned CPU Get terminal remote item has no holder: index={index}" + ), + })); + }; + let Some(end) = info.offset.checked_add(u64::from(info.len)) else { + release_planned_cpu_response_holders(self, &response, owner_start_time); + let _ = pending_guard.take(); + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "planned CPU Get holder range overflow: index={} offset={} len={}", + index, info.offset, info.len + ), + })); + }; + if end > mapped_len { + release_planned_cpu_response_holders(self, &response, owner_start_time); + let _ = pending_guard.take(); + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "planned CPU Get holder exceeds owner mapping: index={} end={} mapped_len={}", + index, end, mapped_len + ), + })); + } + if base_ptr.checked_add(info.offset).is_none() { + release_planned_cpu_response_holders(self, &response, owner_start_time); + let _ = pending_guard.take(); + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "planned CPU Get holder pointer overflow: index={} base={:#x} offset={}", + index, base_ptr, info.offset + ), + })); + } + } + let mut pending = pending_guard.take(); + let consumed_remote_items = pending.sources[..consumed_prefix_len] + .iter() + .filter(|source| matches!(source, PendingExternalCpuSource::Remote { .. })) + .count(); + for item in items.iter().skip(consumed_remote_items) { + let info = item + .external_memholder_info + .as_ref() + .expect("validated planned CPU remote item must have a holder"); + if let Err(detail) = self.enqueue_external_delete_ack( + self.view.cluster_manager().get_self_info().id.clone(), + info.holder_id, + owner_start_time, + ) { + release_planned_cpu_response_holders(self, &response, owner_start_time); + return Err(KvError::Api(ApiError::Unknown { detail })); + } + } + pending.sources.truncate(consumed_prefix_len); + let bandwidth_handle = self + .view + .cluster_manager() + .ipc_bandwidth_attributor_handle() + .expect("planned CPU get_transfer expects an IPC bandwidth handle"); + let external_client_id = self.view.cluster_manager().get_self_info().id.clone(); + let mut remote_items = items.into_iter(); + let mut results = Vec::with_capacity(consumed_prefix_len); + for source in pending.sources { + match source { + PendingExternalCpuSource::Local { holder } => { + bandwidth_handle.record_tx_bytes(u64::from(holder.len)); + results.push(Ok(Some(holder))); + } + PendingExternalCpuSource::Remote { key } => { + let item = remote_items + .next() + .expect("validated remote terminal must match source positions"); + let info = item + .external_memholder_info + .expect("validated planned CPU remote item must have a holder"); + let holder_ptr = base_ptr + .checked_add(info.offset) + .expect("validated planned CPU holder pointer must not overflow"); + bandwidth_handle.record_tx_bytes(u64::from(info.len)); + let holder = Arc::new(ExternalMemHolder::new( + info.offset, + holder_ptr, + info.len, + info.holder_id, + key.clone(), + external_client_id.clone(), + self.view.clone(), + owner_start_time, + )); + self.key_weak_memholder_index + .insert(key, Arc::downgrade(&holder)); + results.push(Ok(Some(holder))); + } + } + } + return Ok(results); + } let Some((_handle, entry)) = self.pending_external_get_start.remove(&handle) else { return Err(KvError::Api(ApiError::InvalidArgument { detail: format!("get_transfer requires a live get-start handle: {}", handle), @@ -3281,6 +5121,33 @@ impl ExternalInner { } pub async fn cancel_get_transfer(&self, handle: u64) -> KvResult<()> { + if self.pending_external_get_plan.contains_key(&handle) { + return self.cancel_get_plan(handle).await; + } + if let Some((_handle, pending)) = self.pending_external_planned_cpu_get.remove(&handle) { + pending.cancel_requested.store(true, Ordering::Release); + return match wait_external_planned_cpu_get_terminal(pending.terminal_rx).await? { + ExternalPlannedCpuGetTerminal::Revoked => Ok(()), + ExternalPlannedCpuGetTerminal::Completed { + items, + owner_start_time, + } => { + release_planned_cpu_response_holders( + self, + &ExternalExecutePlannedGetResp { + items, + error_code: OK, + error_json: String::new(), + }, + owner_start_time, + ); + Ok(()) + } + ExternalPlannedCpuGetTerminal::Failed { detail } => { + Err(KvError::Api(ApiError::Unknown { detail })) + } + }; + } let removed = self.pending_external_get_start.remove(&handle); if removed.is_none() { return Err(KvError::Api(ApiError::InvalidArgument { diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs index 46c8e2f..533127d 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs @@ -3,12 +3,13 @@ use super::{ MasterKeyActivityCompletionGuard, MasterKvRouterView, OwnerHoldingGetInfo, ReservedCapacityReason, msg_pack::{ - BatchGetDoneItemResp, BatchGetDoneReq, BatchGetDoneResp, BatchGetRevokeItemResp, - BatchGetRevokeReq, BatchGetRevokeResp, BatchGetStartItemResp, BatchGetStartReq, - BatchGetStartResp, BatchIsExistReq, BatchIsExistResp, GetAllocationMode, GetDoneReq, - GetDoneResp, GetExternalSinkTarget, GetMetaReq, GetMetaResp, GetPreparedLocalReserveTarget, - GetRevokeReq, GetRevokeResp, GetStartReq, GetStartResp, MemHolderKeepAliveReq, - MemHolderKeepAliveResp, MemHolderReleaseReq, MemHolderReleaseResp, + BatchGetBindItemReq, BatchGetBindReq, BatchGetBindResp, BatchGetDoneItemResp, + BatchGetDoneReq, BatchGetDoneResp, BatchGetPlanItemResp, BatchGetPlanReq, BatchGetPlanResp, + BatchGetRevokeItemResp, BatchGetRevokeReq, BatchGetRevokeResp, BatchGetStartItemResp, + BatchGetStartReq, BatchGetStartResp, BatchIsExistReq, BatchIsExistResp, GetAllocationMode, + GetBindTarget, GetDoneReq, GetDoneResp, GetExternalSinkTarget, GetMetaReq, GetMetaResp, + GetPreparedLocalReserveTarget, GetRevokeReq, GetRevokeResp, GetStartReq, GetStartResp, + MemHolderKeepAliveReq, MemHolderKeepAliveResp, MemHolderReleaseReq, MemHolderReleaseResp, }, node_generation_is_current_live, publish_route_replica_tomb_fenced, route_maintenance::{RoutePublishEvent, apply_post_route_maintenance_batch}, @@ -240,6 +241,631 @@ fn validate_external_sink_target( Ok(()) } +fn get_plan_item_error(err: &msg_and_error::KvError) -> BatchGetPlanItemResp { + let response: GetStartResp = crate::rpcresp_kvresult_convert::FromError::from_error(err); + BatchGetPlanItemResp { + error_code: response.error_code, + error_json: response.error_json, + ..Default::default() + } +} + +fn get_bind_item_error(get_id: u64, err: &msg_and_error::KvError) -> BatchGetStartItemResp { + let response: GetStartResp = crate::rpcresp_kvresult_convert::FromError::from_error(err); + BatchGetStartItemResp { + get_id, + error_code: response.error_code, + error_json: response.error_json, + ..Default::default() + } +} + +#[derive(Clone)] +struct PlannedGetSourceSnapshot { + node_id: NodeID, + tomb_tag: crate::master_seg_manager::NodeTombTag, + len: u64, + addr: u64, + base_addr: u64, +} + +fn snapshot_live_get_sources(route: &OneKvNodesRoutes) -> Vec { + route + .nodes_replicas + .read() + .values() + .filter(|replica| !replica.tomb_tag.is_tomb()) + .map(|replica| PlannedGetSourceSnapshot { + node_id: replica.node_id.clone(), + tomb_tag: replica.tomb_tag.clone(), + len: replica.backing.len(), + addr: replica.backing.abs_addr(), + base_addr: replica.backing.base_addr(), + }) + .collect() +} + +fn planned_get_source_is_current( + planned: &super::PlannedGetInfo, + route: &Arc, +) -> bool { + if planned.src_tomb_tag.is_tomb() || route.put_id != planned.put_id { + return false; + } + route + .nodes_replicas + .read() + .get(&planned.src_node_id) + .is_some_and(|replica| { + !replica.tomb_tag.is_tomb() + && replica.tomb_tag.same_generation(&planned.src_tomb_tag) + && replica.backing.abs_addr() == planned.src_addr + && replica.backing.base_addr() == planned.src_base_addr + && replica.backing.len() == planned.len + }) +} + +#[cfg(test)] +mod planned_get_tests { + use super::{planned_get_source_is_current, snapshot_live_get_sources}; + use crate::cluster_manager::NodeID; + use crate::master_kv_router::{ + CommittedSlotReplica, KvReplicaBacking, KvRouteInfo, OneKvNodesRoutes, PlannedGetInfo, + }; + use crate::master_seg_manager::NodeTombTag; + use parking_lot::RwLock; + use std::collections::HashMap; + use std::sync::Arc; + use std::sync::atomic::AtomicU32; + + fn planned_route() -> (PlannedGetInfo, Arc, NodeTombTag) { + let source: NodeID = "source".to_string().into(); + let source_tag = NodeTombTag::new(); + let route = Arc::new(OneKvNodesRoutes { + put_id: (7, 3), + lease_id: None, + atomic_group: None, + nodes_replicas: RwLock::new(HashMap::from([( + source.clone(), + KvRouteInfo { + node_id: source.clone(), + backing: KvReplicaBacking::CommittedSlot(CommittedSlotReplica { + owner_node_id: source.clone(), + grant_id: 11, + slot_index: 2, + slot_size: 8192, + addr: 0x3000, + len: 4096, + base_addr: 0x1000, + }), + owner_local_indexed: true, + get_durable_reservation: None, + capacity_reservation: None, + tomb_tag: source_tag.clone(), + }, + )])), + get_durable_slots_used: AtomicU32::new(0), + }); + let planned = PlannedGetInfo { + put_id: route.put_id, + src_node_id: source, + src_tomb_tag: source_tag.clone(), + key: "key".to_string(), + controller_node_id: "external".to_string().into(), + controller_node_start_time: 17, + len: 4096, + src_addr: 0x3000, + src_base_addr: 0x1000, + atomic_group: None, + }; + (planned, route, source_tag) + } + + #[test] + fn bind_revalidation_accepts_only_the_exact_source_generation() { + let (planned, route, source_tag) = planned_route(); + assert!(planned_get_source_is_current(&planned, &route)); + + route + .nodes_replicas + .write() + .get_mut(&planned.src_node_id) + .unwrap() + .backing = KvReplicaBacking::CommittedSlot(CommittedSlotReplica { + owner_node_id: planned.src_node_id.clone(), + grant_id: 11, + slot_index: 2, + slot_size: 8192, + addr: 0x4000, + len: 4096, + base_addr: 0x1000, + }); + assert!(!planned_get_source_is_current(&planned, &route)); + + route + .nodes_replicas + .write() + .get_mut(&planned.src_node_id) + .unwrap() + .backing = KvReplicaBacking::CommittedSlot(CommittedSlotReplica { + owner_node_id: planned.src_node_id.clone(), + grant_id: 11, + slot_index: 2, + slot_size: 8192, + addr: 0x3000, + len: 4096, + base_addr: 0x1000, + }); + source_tag.set_tomb(); + assert!(!planned_get_source_is_current(&planned, &route)); + } + + #[test] + fn bind_revalidation_rejects_a_replacement_route_generation() { + let (planned, route, _) = planned_route(); + let replacement_tag = NodeTombTag::new(); + route + .nodes_replicas + .write() + .get_mut(&planned.src_node_id) + .unwrap() + .tomb_tag = replacement_tag; + assert!(!planned_get_source_is_current(&planned, &route)); + } + + #[test] + fn metadata_plan_does_not_retain_the_route() { + let (planned, route, _) = planned_route(); + let weak_route = Arc::downgrade(&route); + let sources = snapshot_live_get_sources(&route); + drop(route); + assert!(weak_route.upgrade().is_none()); + assert_eq!(sources.len(), 1); + assert_eq!(planned.key, "key"); + } +} + +async fn handle_get_plan_item( + view: MasterKvRouterView, + key: String, + controller_node_id: NodeID, +) -> BatchGetPlanItemResp { + view.master_kv_router() + .inner() + .planned_get_counters + .plan_items + .fetch_add(1, Ordering::Relaxed); + let Some(controller) = view + .cluster_manager() + .get_member_info_cached(controller_node_id.as_ref()) + else { + return get_plan_item_error(&msg_and_error::KvError::Api( + msg_and_error::ApiError::InvalidArgument { + detail: format!( + "GetPlan controller is not a current member: {}", + controller_node_id + ), + }, + )); + }; + if controller.node_role() != NodeRole::External { + return get_plan_item_error(&msg_and_error::KvError::Api( + msg_and_error::ApiError::InvalidArgument { + detail: format!( + "GetPlan is supported only for external controllers: {}", + controller_node_id + ), + }, + )); + } + + let Some(route) = view + .master_kv_router() + .inner() + .kv_routes + .get(&key) + .map(|route| route.clone()) + else { + view.master_kv_router() + .inner() + .planned_get_counters + .plan_misses + .fetch_add(1, Ordering::Relaxed); + return get_plan_item_error(&msg_and_error::KvError::Api( + msg_and_error::ApiError::KeyNotFound { key }, + )); + }; + + let local_owner = + external_sink_local_owner_id(&view, &controller_node_id, controller.node_start_time); + let mut candidates = snapshot_live_get_sources(&route); + candidates.shuffle(&mut rand::thread_rng()); + candidates.sort_by_key(|replica| { + local_owner + .as_deref() + .is_some_and(|owner| replica.node_id.as_ref() == owner) + }); + let Some(source) = candidates.into_iter().next() else { + view.master_kv_router() + .inner() + .planned_get_counters + .plan_misses + .fetch_add(1, Ordering::Relaxed); + return get_plan_item_error(&msg_and_error::KvError::Api( + msg_and_error::ApiError::KeyNotFound { key }, + )); + }; + + let get_id = view + .master_kv_router() + .inner() + .next_get_id + .fetch_add(1, Ordering::Relaxed); + let gpu_direct_eligible = local_owner + .as_deref() + .is_none_or(|owner| source.node_id.as_ref() != owner); + let planned = super::PlannedGetInfo { + put_id: route.put_id, + src_node_id: source.node_id.clone(), + src_tomb_tag: source.tomb_tag.clone(), + key: key.clone(), + controller_node_id: controller_node_id.clone(), + controller_node_start_time: controller.node_start_time, + len: source.len, + src_addr: source.addr, + src_base_addr: source.base_addr, + atomic_group: route.atomic_group.as_deref().cloned(), + }; + drop(route); + view.master_kv_router() + .inner() + .planned_gets + .insert(get_id, planned.clone()) + .await; + view.master_kv_router() + .inner() + .planned_get_counters + .plan_hits + .fetch_add(1, Ordering::Relaxed); + BatchGetPlanItemResp { + get_id, + node_id: source.node_id.into(), + put_id: planned.put_id, + src_addr: planned.src_addr, + src_base_addr: planned.src_base_addr, + len: planned.len, + atomic_group: planned.atomic_group, + gpu_direct_eligible, + error_code: msg_and_error::OK, + error_json: String::new(), + } +} + +fn bound_get_matches_target(info: &InflightGetInfo, target: &GetBindTarget) -> bool { + match (target, &info.target) { + (GetBindTarget::ExternalSink(expected), InflightGetTarget::ExternalSink(actual)) => { + expected == actual + } + ( + GetBindTarget::PreparedLocalReserve(expected), + InflightGetTarget::PreparedLocalReserveSlot(actual), + ) => { + expected.grant_id == actual.grant_id + && expected.slot_index == actual.slot_index + && expected.slot_size == actual.slot_size + && expected.addr == actual.addr + && expected.base_addr == actual.base_addr + } + _ => false, + } +} + +fn bound_get_start_item(get_id: u64, info: &InflightGetInfo) -> BatchGetStartItemResp { + BatchGetStartItemResp { + get_id, + node_id: info.src_node_id.to_string().into(), + put_id: info.put_id, + target_addr: info.target.abs_addr(), + src_addr: info.src_addr, + target_base_addr: info.target.base_addr(), + src_base_addr: info.src_base_addr, + len: info.len, + prepared_target: match &info.target { + InflightGetTarget::PreparedLocalReserveSlot(slot) => { + Some(GetPreparedLocalReserveTarget { + grant_id: slot.grant_id, + slot_index: slot.slot_index, + slot_size: slot.slot_size, + addr: slot.addr, + base_addr: slot.base_addr, + }) + } + _ => None, + }, + atomic_group: info.atomic_group.clone(), + error_code: msg_and_error::OK, + error_json: String::new(), + } +} + +async fn handle_get_bind_item( + view: MasterKvRouterView, + request: BatchGetBindItemReq, + req_node_id: NodeID, +) -> BatchGetStartItemResp { + let get_id = request.get_id; + let operation_lock = view + .master_kv_router() + .inner() + .get_done_locks + .get_lock(get_id); + let _operation_guard = operation_lock.lock().await; + + if let Some(bound) = view + .master_kv_router() + .inner() + .inflight_gets + .get(&get_id) + .await + { + if bound.req_node_id != req_node_id || !bound_get_matches_target(&bound, &request.target) { + return get_bind_item_error( + get_id, + &msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { + detail: format!( + "GetBind replay identity/target mismatch: get_id={} requester={}", + get_id, req_node_id + ), + }), + ); + } + return bound_get_start_item(get_id, &bound); + } + + let Some(planned) = view + .master_kv_router() + .inner() + .planned_gets + .get(&get_id) + .await + else { + return get_bind_item_error( + get_id, + &msg_and_error::KvError::Api(msg_and_error::ApiError::KeyNotFound { + key: format!("planned_get_id:{get_id}"), + }), + ); + }; + let (target, target_tomb_tag, allocation_mode, prepared_requester_lease) = match &request.target + { + GetBindTarget::ExternalSink(target) => { + if req_node_id != planned.controller_node_id { + return get_bind_item_error( + get_id, + &msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { + detail: format!( + "external GetBind controller mismatch: get_id={} expected={} got={}", + get_id, planned.controller_node_id, req_node_id + ), + }), + ); + } + if let Err(err) = + validate_external_sink_target(&view, &req_node_id, target, planned.len) + { + return get_bind_item_error(get_id, &err); + } + ( + InflightGetTarget::ExternalSink(target.clone()), + None, + GetAllocationMode::ExternalSink, + None, + ) + } + GetBindTarget::PreparedLocalReserve(target) => { + let expected_owner = external_sink_local_owner_id( + &view, + &planned.controller_node_id, + planned.controller_node_start_time, + ); + if expected_owner.as_deref() != Some(req_node_id.as_ref()) { + return get_bind_item_error( + get_id, + &msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { + detail: format!( + "prepared GetBind executor is not the controller's owner: get_id={} controller={} expected_owner={:?} got={}", + get_id, planned.controller_node_id, expected_owner, req_node_id + ), + }), + ); + } + let requester_lease = match view.master_kv_router().reserve_prepared_get_requester( + &planned.key, + &req_node_id, + get_id, + ) { + Ok(lease) => lease, + Err(err) => return get_bind_item_error(get_id, &err), + }; + let (slot, tomb_tag) = match validate_prepared_local_reserve_target( + &view, + &req_node_id, + target, + planned.len, + ) { + Ok(value) => value, + Err(err) => return get_bind_item_error(get_id, &err), + }; + ( + InflightGetTarget::PreparedLocalReserveSlot(slot), + Some(tomb_tag), + GetAllocationMode::LocalCommittedSlot, + Some(requester_lease), + ) + } + GetBindTarget::Invalid => { + return get_bind_item_error( + get_id, + &msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { + detail: format!("GetBind requires a concrete target: get_id={get_id}"), + }), + ); + } + }; + + let activity_lease = match view + .master_kv_router() + .reserve_inflight_get_key(&planned.key) + { + Ok(lease) => lease, + Err(err) => { + view.master_kv_router() + .inner() + .planned_get_counters + .bind_activity_busy + .fetch_add(1, Ordering::Relaxed); + return get_bind_item_error(get_id, &err); + } + }; + let current_route = view + .master_kv_router() + .inner() + .kv_routes + .get(&planned.key) + .map(|route| route.clone()); + let Some(current_route) = + current_route.filter(|route| planned_get_source_is_current(&planned, route)) + else { + view.master_kv_router() + .inner() + .planned_get_counters + .bind_stale + .fetch_add(1, Ordering::Relaxed); + return get_bind_item_error( + get_id, + &msg_and_error::KvError::Api(msg_and_error::ApiError::StaleGetPlan { + get_id, + key: planned.key.clone(), + detail: format!( + "source route changed before Bind: source={}", + planned.src_node_id + ), + }), + ); + }; + if matches!(&request.target, GetBindTarget::PreparedLocalReserve(_)) + && current_route + .nodes_replicas + .read() + .get(&req_node_id) + .is_some_and(|replica| !replica.tomb_tag.is_tomb()) + { + return get_bind_item_error( + get_id, + &msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { + detail: format!( + "prepared GetBind cannot replace a live owner replica: get_id={} key={} owner={}", + get_id, planned.key, req_node_id + ), + }), + ); + } + + let Some(planned) = view + .master_kv_router() + .inner() + .planned_gets + .remove(&get_id) + .await + else { + return get_bind_item_error( + get_id, + &msg_and_error::KvError::Api(msg_and_error::ApiError::KeyNotFound { + key: format!("planned_get_id:{get_id}"), + }), + ); + }; + let inflight = InflightGetInfo { + put_id: planned.put_id, + src_node_id: planned.src_node_id.clone(), + key: planned.key.clone(), + req_node_id: req_node_id.clone(), + controller_node_id: Some(planned.controller_node_id), + len: planned.len, + src_addr: planned.src_addr, + src_base_addr: planned.src_base_addr, + atomic_group: planned.atomic_group, + target, + target_tomb_tag, + route: current_route.clone(), + allocation_mode, + durable_reservation: None, + _activity_lease: activity_lease, + _prepared_requester_lease: prepared_requester_lease, + }; + let response = bound_get_start_item(get_id, &inflight); + view.master_kv_router().record_get_source_selection( + req_node_id.as_ref(), + inflight.src_node_id.as_ref(), + inflight.len, + allocation_mode, + ); + view.master_kv_router() + .inner() + .inflight_gets + .insert(get_id, inflight) + .await; + view.master_kv_router() + .inner() + .planned_get_counters + .bind_succeeded + .fetch_add(1, Ordering::Relaxed); + if current_route.lease_id.is_none() { + touch_moka_for_node(view, response.node_id.to_string(), planned.key); + } + response +} + +pub async fn handle_batch_get_plan( + view: MasterKvRouterView, + req: MsgPack, + req_node_id: NodeID, +) -> MsgPack { + let mut items = Vec::with_capacity(req.serialize_part.keys.len()); + for key in req.serialize_part.keys { + items.push(handle_get_plan_item(view.clone(), key, req_node_id.clone()).await); + } + MsgPack { + serialize_part: BatchGetPlanResp { + items, + error_code: msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + }, + raw_bytes: Vec::new(), + } +} + +pub async fn handle_batch_get_bind( + view: MasterKvRouterView, + req: MsgPack, + req_node_id: NodeID, +) -> MsgPack { + let mut items = Vec::with_capacity(req.serialize_part.items.len()); + for item in req.serialize_part.items { + items.push(handle_get_bind_item(view.clone(), item, req_node_id.clone()).await); + } + MsgPack { + serialize_part: BatchGetBindResp { + items, + error_code: msg_and_error::OK, + error_json: String::new(), + server_process_us: 0, + }, + raw_bytes: Vec::new(), + } +} + pub async fn handle_get_start( view: MasterKvRouterView, req: MsgPack, @@ -613,7 +1239,11 @@ pub async fn handle_get_start( src_node_id: src_node_id.clone(), key: req.serialize_part.key.clone(), req_node_id, + controller_node_id: None, len: src_len, + src_addr: resp_src_addr, + src_base_addr: resp_src_base, + atomic_group: one_kv_nodes_routes.atomic_group.as_deref().cloned(), target, target_tomb_tag, route: one_kv_nodes_routes.clone(), @@ -683,6 +1313,56 @@ pub async fn handle_get_revoke( .get_lock(get_id); let _done_guard = done_lock.lock().await; + if let Some(planned) = view + .master_kv_router() + .inner() + .planned_gets + .get(&get_id) + .await + { + let controller_owner = external_sink_local_owner_id( + &view, + &planned.controller_node_id, + planned.controller_node_start_time, + ); + let authorized = planned.controller_node_id == req_node_id + || controller_owner.as_deref() == Some(req_node_id.as_ref()); + if !authorized { + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { + detail: format!( + "GetRevoke planned-operation requester mismatch: get_id={} controller={} got={}", + get_id, planned.controller_node_id, req_node_id + ), + }); + return MsgPack { + serialize_part: crate::rpcresp_kvresult_convert::FromError::from_error(&err), + raw_bytes: Vec::new(), + }; + } + drop(planned); + if view + .master_kv_router() + .inner() + .planned_gets + .remove(&get_id) + .await + .is_some() + { + view.master_kv_router() + .inner() + .planned_get_counters + .plan_revoked + .fetch_add(1, Ordering::Relaxed); + } + return MsgPack { + serialize_part: GetRevokeResp { + error_code: msg_and_error::OK, + error_json: String::new(), + }, + raw_bytes: Vec::new(), + }; + } + if let Some(inflight_info) = view .master_kv_router() .inner() @@ -690,7 +1370,9 @@ pub async fn handle_get_revoke( .get(&get_id) .await { - if inflight_info.req_node_id != req_node_id { + if inflight_info.req_node_id != req_node_id + && inflight_info.controller_node_id.as_ref() != Some(&req_node_id) + { let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { detail: format!( "GetRevoke requester mismatch: get_id={} expected={} got={}", diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs index 9f927d9..d5c43ee 100644 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs @@ -15,20 +15,20 @@ use self::{ delete::handle_delete, delete::handle_delete_ack, get::{ - handle_batch_get_done, handle_batch_get_revoke, handle_batch_get_start, - handle_batch_is_exist, handle_get_done, handle_get_meta, handle_get_revoke, - handle_get_start, + handle_batch_get_bind, handle_batch_get_done, handle_batch_get_plan, + handle_batch_get_revoke, handle_batch_get_start, handle_batch_is_exist, handle_get_done, + handle_get_meta, handle_get_revoke, handle_get_start, }, msg_pack::{ BatchDeleteAckReq, BatchDeleteClientKvMetaCacheReq, BatchEnqueueReplicaTaskReq, - BatchEvictOwnerSourceReq, BatchGetDoneReq, BatchGetRevokeReq, BatchGetStartReq, - BatchIsExistReq, BatchOwnerReclaimReq, BatchPreparePutKeysReq, BatchPutAppendDoneReq, - BatchPutAppendStartReq, BatchPutDoneReq, BatchPutRevokeReq, BatchPutStartReq, - BatchReleasePutKeyReservationsReq, CountPrefixReq, CountPrefixResp, DeleteAckReq, - DeleteReq, GetAllocationMode, GetDoneReq, GetDoneResp, GetMetaReq, GetRevokeReq, - GetStartReq, GroupedBatchPutDoneReq, OwnerReclaimItem, PutAppendDoneReq, - PutAppendRevokeReq, PutAppendStartReq, PutAtomicGroup, PutDoneReq, PutRevokeReq, - PutStartReq, ReleaseLocalGrantReq, ReserveLocalGrantReq, + BatchEvictOwnerSourceReq, BatchGetBindReq, BatchGetDoneReq, BatchGetPlanReq, + BatchGetRevokeReq, BatchGetStartReq, BatchIsExistReq, BatchOwnerReclaimReq, + BatchPreparePutKeysReq, BatchPutAppendDoneReq, BatchPutAppendStartReq, BatchPutDoneReq, + BatchPutRevokeReq, BatchPutStartReq, BatchReleasePutKeyReservationsReq, CountPrefixReq, + CountPrefixResp, DeleteAckReq, DeleteReq, GetAllocationMode, GetDoneReq, GetDoneResp, + GetMetaReq, GetRevokeReq, GetStartReq, GroupedBatchPutDoneReq, OwnerReclaimItem, + PutAppendDoneReq, PutAppendRevokeReq, PutAppendStartReq, PutAtomicGroup, PutDoneReq, + PutRevokeReq, PutStartReq, ReleaseLocalGrantReq, ReserveLocalGrantReq, }, placement::{PlacementPolicy, build_placement_policy}, put::{ @@ -429,7 +429,13 @@ pub struct InflightGetInfo { pub src_node_id: NodeID, pub key: String, pub req_node_id: NodeID, + /// Optional external controller for a late-bound operation whose executor + /// is the share-group owner in `req_node_id`. + pub controller_node_id: Option, pub len: u64, + pub src_addr: u64, + pub src_base_addr: u64, + pub atomic_group: Option, pub target: InflightGetTarget, /// Exact requester segment-registration generation that owns an /// allocator-backed target. External sinks are caller-owned and instead @@ -445,6 +451,25 @@ pub struct InflightGetInfo { pub(crate) _prepared_requester_lease: Option>, } +/// A metadata-only Get source snapshot before caller-owned destination binding. +/// +/// This type must not own a route, allocation, activity lease, cache pin, or +/// destination resource. Bind re-reads the current route and installs the real +/// Get activity before accepting the snapshot. +#[derive(Clone)] +pub struct PlannedGetInfo { + pub put_id: PutIDForAKey, + pub src_node_id: NodeID, + pub src_tomb_tag: NodeTombTag, + pub key: String, + pub controller_node_id: NodeID, + pub controller_node_start_time: i64, + pub len: u64, + pub src_addr: u64, + pub src_base_addr: u64, + pub atomic_group: Option, +} + #[derive(Clone)] pub struct CompletedGetInfo { pub req_node_id: NodeID, @@ -568,6 +593,17 @@ struct MasterKeyActivityObserveSnapshot { inflight_replicas: u64, } +#[derive(Default)] +pub(crate) struct MasterPlannedGetCounters { + plan_items: AtomicU64, + plan_hits: AtomicU64, + plan_misses: AtomicU64, + bind_succeeded: AtomicU64, + bind_stale: AtomicU64, + bind_activity_busy: AtomicU64, + plan_revoked: AtomicU64, +} + #[derive(Clone, Copy, Debug)] enum MasterKeyActivityKind { Put, @@ -2272,6 +2308,10 @@ pub struct MasterKvRouterInner { /// queue or actor. pub replica_operation_locks: AMapLock<(String, u64, u32)>, pub inflight_gets: moka::future::Cache, + /// Target-free source plans. Bind atomically moves an entry into + /// `inflight_gets` after re-reading and validating the current route. + pub planned_gets: moka::future::Cache, + pub(crate) planned_get_counters: MasterPlannedGetCounters, /// Idempotent terminal GetDone results retained across response loss/retry. pub completed_gets: moka::future::Cache, pub get_done_locks: AMapLock, @@ -2490,6 +2530,9 @@ impl MasterKvRouter { } }) .build(); + let planned_gets: moka::future::Cache = moka::future::Cache::builder() + .time_to_live(Duration::from_secs(60)) + .build(); let completed_gets = moka::future::Cache::builder() .time_to_live(Duration::from_secs(120)) .build(); @@ -2524,6 +2567,8 @@ impl MasterKvRouter { completed_replica_tasks, replica_operation_locks: AMapLock::new(Duration::from_secs(10 * 60)), inflight_gets, + planned_gets, + planned_get_counters: MasterPlannedGetCounters::default(), completed_gets, get_done_locks: AMapLock::new(Duration::from_secs(10 * 60)), key_activity, @@ -3817,6 +3862,56 @@ impl MasterKvRouter { Ok(()) }); + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let view2 = view.clone(); + let cleanup_view = view.clone(); + let req_node_id = resp.node_id().clone(); + view.spawn("rpc_batch_get_plan", async move { + let t0 = Utc::now().timestamp_micros(); + let mut ack = handle_batch_get_plan(view2, msg, req_node_id).await; + ack.serialize_part.server_process_us = Utc::now().timestamp_micros() - t0; + let planned_get_ids = ack + .serialize_part + .items + .iter() + .filter(|item| { + item.error_code == crate::rpcresp_kvresult_convert::msg_and_error::OK + }) + .map(|item| item.get_id) + .collect::>(); + if let Err(e) = resp.send_resp(ack).await { + error!("Failed to send BatchGetPlanResp: {:?}", e); + for get_id in planned_get_ids { + cleanup_view + .master_kv_router() + .inner() + .planned_gets + .remove(&get_id) + .await; + } + } + }); + Ok(()) + }); + + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let view2 = view.clone(); + let req_node_id = resp.node_id().clone(); + view.spawn("rpc_batch_get_bind", async move { + let t0 = Utc::now().timestamp_micros(); + let mut ack = handle_batch_get_bind(view2, msg, req_node_id).await; + ack.serialize_part.server_process_us = Utc::now().timestamp_micros() - t0; + if let Err(e) = resp.send_resp(ack).await { + error!("Failed to send BatchGetBindResp: {:?}", e); + } + }); + Ok(()) + }); + let view = self.0.view().clone(); RPCHandler::::new().regist(p2p, move |resp, msg| { let view = view.clone(); @@ -5324,6 +5419,56 @@ impl MasterKvRouter { inflight_replicas = activity.inflight_replicas, "master key activity runtime" ); + tracing::info!( + active_plans = view_task + .master_kv_router() + .inner() + .planned_gets + .entry_count(), + plan_items = view_task + .master_kv_router() + .inner() + .planned_get_counters + .plan_items + .load(Ordering::Relaxed), + plan_hits = view_task + .master_kv_router() + .inner() + .planned_get_counters + .plan_hits + .load(Ordering::Relaxed), + plan_misses = view_task + .master_kv_router() + .inner() + .planned_get_counters + .plan_misses + .load(Ordering::Relaxed), + bind_succeeded = view_task + .master_kv_router() + .inner() + .planned_get_counters + .bind_succeeded + .load(Ordering::Relaxed), + bind_stale = view_task + .master_kv_router() + .inner() + .planned_get_counters + .bind_stale + .load(Ordering::Relaxed), + bind_activity_busy = view_task + .master_kv_router() + .inner() + .planned_get_counters + .bind_activity_busy + .load(Ordering::Relaxed), + plan_revoked = view_task + .master_kv_router() + .inner() + .planned_get_counters + .plan_revoked + .load(Ordering::Relaxed), + "master metadata-only Get plan runtime" + ); for node in snapshot.replica_cache_nodes { tracing::info!( "replica cache runtime: owner={} entries={} weighted_bytes={} effective_capacity_bytes={} base_capacity_bytes={} reserved_capacity_bytes={} pending_eviction_reclaim_bytes={} writeback_tier1_entries={} writeback_tier1_weighted_bytes={} writeback_tier1_capacity_bytes={} writeback_tier1_triggered={} writeback_tier1_owner_accepted={} writeback_tier1_failed={} reclaim_master_activity_deferred={} reclaim_owner_holder_deferred={} reclaim_owner_other_deferred={} reclaim_route_changed={} reclaim_retry_queued={} reclaim_retry_completed={} reclaim_retry_restored={} reclaim_completed={} source_evict_rpc_requests={} source_evict_victims={} source_evict_requested_bytes={} source_evict_accepted={} source_evict_in_progress={} source_evict_completed={} source_evict_retryable_busy={} source_evict_stale={} source_evict_rejected={} last_route_removed_members={} last_route_removed_bytes={} capacity_eviction_non_ring_b_entry_total={} capacity_eviction_hit_committed_slot={} eviction_reclaim_deduplicated={}", diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs index d21e39d..b873956 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs @@ -183,6 +183,143 @@ impl RPCReq for BatchGetStartReq { type Resp = BatchGetStartResp; } +/// Target-free Get planning. Successful items retain one exact source +/// generation until Bind, Revoke, or expiry. +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchGetPlanReq { + pub keys: Vec, +} +impl MsgPackSerializePart for BatchGetPlanReq { + fn msg_id(&self) -> u32 { + MsgId::BatchGetPlanReq as u32 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchGetPlanItemResp { + pub get_id: u64, + pub node_id: NodeIDString, + pub put_id: PutIDForAKey, + pub src_addr: u64, + pub src_base_addr: u64, + pub len: u64, + pub atomic_group: Option, + /// False when the selected source is the external requester's local + /// share-group owner and therefore cannot use the RDMA-only GPU sink. + pub gpu_direct_eligible: bool, + pub error_code: ErrorCode, + pub error_json: String, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchGetPlanResp { + pub items: Vec, + pub error_code: ErrorCode, + pub error_json: String, + pub server_process_us: i64, +} +impl MsgPackSerializePart for BatchGetPlanResp { + fn msg_id(&self) -> u32 { + MsgId::BatchGetPlanResp as u32 + } +} +impl RPCReq for BatchGetPlanReq { + type Resp = BatchGetPlanResp; +} + +#[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)] +pub enum GetBindTarget { + #[default] + Invalid, + PreparedLocalReserve(GetPreparedLocalReserveTarget), + ExternalSink(GetExternalSinkTarget), +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchGetBindItemReq { + pub get_id: u64, + pub target: GetBindTarget, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchGetBindReq { + pub items: Vec, +} +impl MsgPackSerializePart for BatchGetBindReq { + fn msg_id(&self) -> u32 { + MsgId::BatchGetBindReq as u32 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchGetBindResp { + pub items: Vec, + pub error_code: ErrorCode, + pub error_json: String, + pub server_process_us: i64, +} +impl MsgPackSerializePart for BatchGetBindResp { + fn msg_id(&self) -> u32 { + MsgId::BatchGetBindResp as u32 + } +} +impl RPCReq for BatchGetBindReq { + type Resp = BatchGetBindResp; +} + +#[cfg(test)] +mod planned_get_wire_tests { + use super::{ + BatchGetBindItemReq, BatchGetBindReq, BatchGetPlanItemResp, BatchGetPlanResp, + GetBindTarget, GetExternalSinkTarget, + }; + use crate::rpcresp_kvresult_convert::msg_and_error::OK; + + #[test] + fn first_get_id_and_late_gpu_binding_round_trip() { + let plan = BatchGetPlanResp { + items: vec![BatchGetPlanItemResp { + get_id: 0, + node_id: "source-a".to_string(), + src_addr: 0x1000, + src_base_addr: 0x800, + len: 4096, + gpu_direct_eligible: true, + error_code: OK, + ..Default::default() + }], + error_code: OK, + ..Default::default() + }; + let decoded: BatchGetPlanResp = + bitcode::decode(&bitcode::encode(&plan)).expect("decode GetPlan response"); + assert_eq!(decoded.items[0].get_id, 0); + assert!(decoded.items[0].gpu_direct_eligible); + assert_eq!(decoded.items[0].src_addr, 0x1000); + + let bind = BatchGetBindReq { + items: vec![BatchGetBindItemReq { + get_id: 0, + target: GetBindTarget::ExternalSink(GetExternalSinkTarget { + addr: 0x2000, + capacity: 4096, + registration_id: 7, + requester_node_start_time: 11, + }), + }], + }; + let decoded: BatchGetBindReq = + bitcode::decode(&bitcode::encode(&bind)).expect("decode GetBind request"); + assert!(matches!( + &decoded.items[0].target, + GetBindTarget::ExternalSink(target) + if decoded.items[0].get_id == 0 + && target.registration_id == 7 + && target.requester_node_start_time == 11 + )); + } +} + #[derive(Default, Debug, Clone, Encode, Decode)] pub struct BatchGetRevokeReq { pub get_ids: Vec, diff --git a/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/msg_and_error.rs b/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/msg_and_error.rs index 5f6e8ca..91558b6 100644 --- a/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/msg_and_error.rs +++ b/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/msg_and_error.rs @@ -83,6 +83,10 @@ pub enum MsgId { BatchPutAppendDoneResp = 3068, BatchEvictOwnerSourceReq = 3069, BatchEvictOwnerSourceResp = 3070, + BatchGetPlanReq = 3071, + BatchGetPlanResp = 3072, + BatchGetBindReq = 3073, + BatchGetBindResp = 3074, ExternalGetReq = 4001, ExternalGetResp = 4002, ExternalPutStartReq = 4003, @@ -749,6 +753,9 @@ crate::define_err_group! { , (123, KeyAlreadyExists { key: String }, msg: "Key already exists: key={key}") + , + (124, StaleGetPlan { get_id: u64, key: String, detail: String }, + msg: "Get plan is stale: get_id={get_id}, key={key}, detail={detail}") } } diff --git a/fluxon_rs/fluxon_pyo3/src/fixed_slab_allocator.rs b/fluxon_rs/fluxon_pyo3/src/fixed_slab_allocator.rs new file mode 100644 index 0000000..bbcd7df --- /dev/null +++ b/fluxon_rs/fluxon_pyo3/src/fixed_slab_allocator.rs @@ -0,0 +1,52 @@ +use fluxon_util::fixed_slab_allocator::FixedSlabAllocator as RustFixedSlabAllocator; +use pyo3::exceptions::PyValueError; +use pyo3::prelude::*; + +/// Thread-safe fixed-slot slab allocator. +/// +/// `try_reserve` is all-or-none. `release` rejects invalid input atomically. +#[pyclass(module = "fluxon_pyo3")] +pub struct FixedSlabAllocator { + inner: RustFixedSlabAllocator, +} + +#[pymethods] +impl FixedSlabAllocator { + #[new] + fn new(slot_count: u32) -> PyResult { + let inner = RustFixedSlabAllocator::new(slot_count) + .map_err(|error| PyValueError::new_err(error.to_string()))?; + Ok(Self { inner }) + } + + /// Reserve exactly `count` slots, returning `None` if capacity is unavailable. + fn try_reserve(&self, count: u32) -> Option> { + self.inner.try_reserve(count) + } + + /// Release all slots atomically after bounds, duplicate, and live-state checks. + fn release(&self, slots: Vec) -> PyResult<()> { + self.inner + .release(&slots) + .map_err(|error| PyValueError::new_err(error.to_string())) + } + + #[getter] + fn capacity(&self) -> u32 { + self.inner.capacity() + } + + #[getter] + fn free_count(&self) -> u32 { + self.inner.free_count() + } + + #[getter] + fn live_count(&self) -> u32 { + self.inner.live_count() + } + + fn is_empty(&self) -> bool { + self.inner.is_empty() + } +} diff --git a/fluxon_rs/fluxon_pyo3/src/lib.rs b/fluxon_rs/fluxon_pyo3/src/lib.rs index d849e62..a6453dc 100644 --- a/fluxon_rs/fluxon_pyo3/src/lib.rs +++ b/fluxon_rs/fluxon_pyo3/src/lib.rs @@ -77,6 +77,8 @@ include!(env!("FLUXON_PYO3_TEST_PYTHON_LINK_RS")); mod memholder; pub use memholder::{ExternalMemHolder, MemHolder}; +mod fixed_slab_allocator; +pub use fixed_slab_allocator::FixedSlabAllocator; mod flatdict_zerocopy; use flatdict_zerocopy::{FlatDictDataOwner, decode_flat_dict_to_wrapped_py_object}; mod kvfuture; @@ -4771,6 +4773,244 @@ impl KvClient { cancel_get_transfer_inner(self, handle, py).into_py_object(py) } + /// Plan one generation-fenced Get prefix without allocating a destination. + #[pyo3(signature = (keys, prefix_best_effort=true, atomic_group_lens=None))] + fn get_plan( + &self, + keys: Vec, + prefix_best_effort: bool, + atomic_group_lens: Option>, + py: Python, + ) -> PyObject { + fn get_plan_inner( + client: &KvClient, + keys: Vec, + prefix_best_effort: bool, + atomic_group_lens: Option>, + py: Python, + ) -> ApiResult { + if keys.is_empty() { + return ApiResult::new_error(new_invalid_argument_error( + py, + "get_plan requires at least one key", + )); + } + let framework = match require_kv_framework_api(client, py) { + Ok(value) => value, + Err(err) => return ApiResult::new_error(err), + }; + if !framework.is_external_mode() { + return ApiResult::new_error(new_invalid_argument_error( + py, + "get_plan is supported only in external-client mode", + )); + } + let Some(runtime) = client.runtime.as_ref() else { + return ApiResult::new_error(new_general_error(py, "Client runtime is missing")); + }; + let framework_for_plan = framework.clone(); + let result = match py.allow_threads(|| { + runtime.run_async_from_sync(async move { + framework_for_plan + .external_client_api_view() + .external_client_api() + .inner() + .get_plan(keys, prefix_best_effort, atomic_group_lens) + .await + }) + }) { + Ok(result) => result, + Err(err) => { + return ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {err}"), + )); + } + }; + match result { + Ok(plan) => { + let out = PyDict::new_bound(py); + out.set_item("handle", plan.handle).expect("set handle"); + out.set_item("raw_prefix_hit_len", plan.raw_prefix_hit_len as u64) + .expect("set raw_prefix_hit_len"); + out.set_item("gpu_raw_prefix_hit_len", plan.gpu_raw_prefix_hit_len as u64) + .expect("set gpu_raw_prefix_hit_len"); + out.set_item("gpu_remote_indices", plan.gpu_remote_indices) + .expect("set gpu_remote_indices"); + ApiResult::new_success(out.into_py(py)) + } + Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "get_plan failed", + )), + } + } + + get_plan_inner(self, keys, prefix_best_effort, atomic_group_lens, py).into_py_object(py) + } + + #[pyo3(signature = (handle, consume_prefix_len, concurrency=None))] + fn execute_get_plan_cpu( + &self, + handle: u64, + consume_prefix_len: usize, + concurrency: Option, + py: Python, + ) -> PyObject { + let batch_concurrency = concurrency.unwrap_or(DEFAULT_PYO3_BATCH_CONCURRENCY); + let framework = match require_kv_framework_api(self, py) { + Ok(value) => value, + Err(err) => return ApiResult::::new_error(err).into_py_object(py), + }; + if !framework.is_external_mode() || batch_concurrency == 0 { + return ApiResult::::new_error(new_invalid_argument_error( + py, + "execute_get_plan_cpu requires external mode and positive concurrency", + )) + .into_py_object(py); + } + let Some(runtime) = self.runtime.as_ref() else { + return ApiResult::::new_error(new_general_error( + py, + "Client runtime is missing", + )) + .into_py_object(py); + }; + let framework_for_execute = framework.clone(); + let result = py.allow_threads(|| { + runtime.run_async_from_sync(async move { + framework_for_execute + .external_client_api_view() + .external_client_api() + .inner() + .execute_get_plan_cpu(handle, consume_prefix_len, batch_concurrency) + .await + }) + }); + match result { + Ok(Ok(())) => ApiResult::new_success(0i32.into_py(py)), + Ok(Err(err)) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "execute_get_plan_cpu failed", + )), + Err(err) => ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {err}"), + )), + } + .into_py_object(py) + } + + #[pyo3(signature = (handle, destinations, consume_prefix_len, concurrency=None))] + fn execute_get_plan_gpu( + &self, + handle: u64, + destinations: Vec<(u64, u64, u64)>, + consume_prefix_len: usize, + concurrency: Option, + py: Python, + ) -> PyObject { + let batch_concurrency = concurrency.unwrap_or(DEFAULT_PYO3_BATCH_CONCURRENCY); + let framework = match require_kv_framework_api(self, py) { + Ok(value) => value, + Err(err) => return ApiResult::::new_error(err).into_py_object(py), + }; + if !framework.is_external_mode() || batch_concurrency == 0 { + return ApiResult::::new_error(new_invalid_argument_error( + py, + "execute_get_plan_gpu requires external mode and positive concurrency", + )) + .into_py_object(py); + } + let Some(runtime) = self.runtime.as_ref() else { + return ApiResult::::new_error(new_general_error( + py, + "Client runtime is missing", + )) + .into_py_object(py); + }; + let destinations = destinations + .into_iter() + .map(|(registration_id, addr, capacity)| { + fluxon_kv::external_client_api::ExternalGpuDestination { + registration_id, + addr, + capacity, + } + }) + .collect(); + let framework_for_execute = framework.clone(); + let result = py.allow_threads(|| { + runtime.run_async_from_sync(async move { + framework_for_execute + .external_client_api_view() + .external_client_api() + .inner() + .execute_get_plan_gpu( + handle, + destinations, + consume_prefix_len, + batch_concurrency, + ) + .await + }) + }); + match result { + Ok(Ok(())) => ApiResult::new_success(0i32.into_py(py)), + Ok(Err(err)) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "execute_get_plan_gpu failed", + )), + Err(err) => ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {err}"), + )), + } + .into_py_object(py) + } + + #[pyo3(signature = (handle))] + fn cancel_get_plan(&self, handle: u64, py: Python) -> PyObject { + let framework = match require_kv_framework_api(self, py) { + Ok(value) => value, + Err(err) => return ApiResult::::new_error(err).into_py_object(py), + }; + let Some(runtime) = self.runtime.as_ref() else { + return ApiResult::::new_error(new_general_error( + py, + "Client runtime is missing", + )) + .into_py_object(py); + }; + let framework_for_cancel = framework.clone(); + let result = py.allow_threads(|| { + runtime.run_async_from_sync(async move { + framework_for_cancel + .external_client_api_view() + .external_client_api() + .inner() + .cancel_get_plan(handle) + .await + }) + }); + match result { + Ok(Ok(())) => ApiResult::new_success(0i32.into_py(py)), + Ok(Err(err)) => ApiResult::new_error(crate::error::py_error_from_kv_error( + py, + &err, + "cancel_get_plan failed", + )), + Err(err) => ApiResult::new_error(new_general_error( + py, + &format!("runtime bridge failed: {err}"), + )), + } + .into_py_object(py) + } + /// Start background RDMA pulls directly into caller-owned GPU destinations. #[pyo3(signature = (keys, destinations, prefix_best_effort=true, atomic_group_lens=None, concurrency=None))] fn get_start_gpu( @@ -4948,6 +5188,30 @@ impl KvClient { }; match result { Ok(terminal) => { + if terminal.value_ptrs.len() != terminal.consumed_prefix_len { + return ApiResult::new_error(new_general_error( + py, + &format!( + "get_transfer_gpu source plan length mismatch: values={} consumed={}", + terminal.value_ptrs.len(), + terminal.consumed_prefix_len + ), + )); + } + let view_plan = Arc::new(FluxonGetViewsPlan { + blob: build_plan_blob(&terminal.value_ptrs), + _holders: terminal + .local_holders + .into_iter() + .map(|holder| StagedGetViewHolder::External { _holder: holder }) + .collect(), + }); + let plan_ptr = plan_ptr_from_blob(view_plan.blob.as_ref()); + client + .plan_registry + .write() + .expect("plan_registry poisoned") + .insert(plan_ptr, FluxonPlanRegistryEntry::Get(view_plan)); let out = PyDict::new_bound(py); out.set_item( "transferred_prefix_len", @@ -4956,6 +5220,16 @@ impl KvClient { .expect("set transferred_prefix_len"); out.set_item("consumed_prefix_len", terminal.consumed_prefix_len as u64) .expect("set consumed_prefix_len"); + out.set_item("transfer_wall_us", terminal.transfer_wall_us) + .expect("set transfer_wall_us"); + out.set_item("finish_wait_us", terminal.finish_wait_us) + .expect("set finish_wait_us"); + out.set_item("terminal_before_consume", terminal.terminal_before_consume) + .expect("set terminal_before_consume"); + out.set_item("terminal_to_consume_us", terminal.terminal_to_consume_us) + .expect("set terminal_to_consume_us"); + out.set_item("plan_ptr", plan_ptr as u64) + .expect("set plan_ptr"); ApiResult::new_success(out.into_py(py)) } Err(err) => ApiResult::new_error(crate::error::py_error_from_kv_error( @@ -7621,6 +7895,7 @@ fn fluxon_pyo3(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; + m.add_class::()?; m.add_class::()?; m.add_class::()?; m.add_class::()?; diff --git a/fluxon_rs/fluxon_util/src/fixed_slab_allocator.rs b/fluxon_rs/fluxon_util/src/fixed_slab_allocator.rs new file mode 100644 index 0000000..fe9c6ce --- /dev/null +++ b/fluxon_rs/fluxon_util/src/fixed_slab_allocator.rs @@ -0,0 +1,245 @@ +use parking_lot::Mutex; +use std::error::Error; +use std::fmt::{Display, Formatter}; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum FixedSlabAllocatorError { + ZeroCapacity, + DuplicateSlot { slot: u32 }, + SlotOutOfBounds { slot: u32, capacity: u32 }, + SlotNotAllocated { slot: u32 }, +} + +impl Display for FixedSlabAllocatorError { + fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::ZeroCapacity => write!(formatter, "fixed slab capacity must be positive"), + Self::DuplicateSlot { slot } => { + write!( + formatter, + "fixed slab release contains duplicate slot {slot}" + ) + } + Self::SlotOutOfBounds { slot, capacity } => write!( + formatter, + "fixed slab slot {slot} is outside capacity {capacity}" + ), + Self::SlotNotAllocated { slot } => { + write!( + formatter, + "fixed slab slot {slot} is not currently allocated" + ) + } + } + } +} + +impl Error for FixedSlabAllocatorError {} + +#[derive(Debug)] +struct FixedSlabState { + free_slots: Vec, + allocated: Vec, + validation_marks: Vec, + validation_epoch: u64, +} + +/// Thread-safe allocator for a fixed number of equally sized slab slots. +/// +/// Reservations are all-or-none. Releases validate every supplied slot before +/// changing allocator state, so an invalid release cannot partially free slots. +#[derive(Debug)] +pub struct FixedSlabAllocator { + capacity: u32, + state: Mutex, +} + +impl FixedSlabAllocator { + pub fn new(capacity: u32) -> Result { + if capacity == 0 { + return Err(FixedSlabAllocatorError::ZeroCapacity); + } + Ok(Self { + capacity, + state: Mutex::new(FixedSlabState { + free_slots: (0..capacity).rev().collect(), + allocated: vec![false; capacity as usize], + validation_marks: vec![0; capacity as usize], + validation_epoch: 0, + }), + }) + } + + /// Reserves exactly `count` slots, or returns `None` without changing state. + pub fn try_reserve(&self, count: u32) -> Option> { + let mut state = self.state.lock(); + let count = count as usize; + if count > state.free_slots.len() { + return None; + } + + let mut slots = Vec::with_capacity(count); + for _ in 0..count { + let slot = state + .free_slots + .pop() + .expect("fixed slab free count was checked before reservation"); + let was_allocated = std::mem::replace(&mut state.allocated[slot as usize], true); + assert!(!was_allocated, "fixed slab freelist contained a live slot"); + slots.push(slot); + } + Some(slots) + } + + /// Atomically releases all supplied slots after validating the full input. + pub fn release(&self, slots: &[u32]) -> Result<(), FixedSlabAllocatorError> { + let mut state = self.state.lock(); + state.validation_epoch = state.validation_epoch.wrapping_add(1); + if state.validation_epoch == 0 { + state.validation_marks.fill(0); + state.validation_epoch = 1; + } + let validation_epoch = state.validation_epoch; + + for &slot in slots { + if slot >= self.capacity { + return Err(FixedSlabAllocatorError::SlotOutOfBounds { + slot, + capacity: self.capacity, + }); + } + let slot_index = slot as usize; + if state.validation_marks[slot_index] == validation_epoch { + return Err(FixedSlabAllocatorError::DuplicateSlot { slot }); + } + state.validation_marks[slot_index] = validation_epoch; + } + for &slot in slots { + if !state.allocated[slot as usize] { + return Err(FixedSlabAllocatorError::SlotNotAllocated { slot }); + } + } + + for &slot in slots { + state.allocated[slot as usize] = false; + state.free_slots.push(slot); + } + Ok(()) + } + + pub fn capacity(&self) -> u32 { + self.capacity + } + + pub fn free_count(&self) -> u32 { + self.state.lock().free_slots.len() as u32 + } + + pub fn live_count(&self) -> u32 { + self.capacity - self.free_count() + } + + pub fn is_empty(&self) -> bool { + self.free_count() == self.capacity + } +} + +#[cfg(test)] +mod tests { + use super::{FixedSlabAllocator, FixedSlabAllocatorError}; + use std::collections::HashSet; + use std::sync::{Arc, Mutex}; + use std::thread; + + #[test] + fn rejects_zero_capacity() { + assert!(matches!( + FixedSlabAllocator::new(0), + Err(FixedSlabAllocatorError::ZeroCapacity) + )); + } + + #[test] + fn reserve_is_ordered_and_all_or_none() { + let allocator = FixedSlabAllocator::new(4).unwrap(); + assert_eq!(allocator.try_reserve(3), Some(vec![0, 1, 2])); + assert_eq!(allocator.free_count(), 1); + assert_eq!(allocator.live_count(), 3); + + assert_eq!(allocator.try_reserve(2), None); + assert_eq!(allocator.free_count(), 1); + assert_eq!(allocator.try_reserve(1), Some(vec![3])); + assert_eq!(allocator.try_reserve(0), Some(Vec::new())); + assert!(!allocator.is_empty()); + } + + #[test] + fn released_slots_are_reused_and_counts_close() { + let allocator = FixedSlabAllocator::new(4).unwrap(); + let slots = allocator.try_reserve(3).unwrap(); + allocator.release(&slots[2..]).unwrap(); + assert_eq!(allocator.try_reserve(1), Some(vec![2])); + allocator.release(&slots[..2]).unwrap(); + allocator.release(&[2]).unwrap(); + + assert_eq!(allocator.capacity(), 4); + assert_eq!(allocator.free_count(), 4); + assert_eq!(allocator.live_count(), 0); + assert!(allocator.is_empty()); + } + + #[test] + fn invalid_release_is_atomic() { + let allocator = FixedSlabAllocator::new(4).unwrap(); + assert_eq!(allocator.try_reserve(2), Some(vec![0, 1])); + + assert_eq!( + allocator.release(&[0, 0]), + Err(FixedSlabAllocatorError::DuplicateSlot { slot: 0 }) + ); + assert_eq!(allocator.live_count(), 2); + assert_eq!( + allocator.release(&[0, 4]), + Err(FixedSlabAllocatorError::SlotOutOfBounds { + slot: 4, + capacity: 4, + }) + ); + assert_eq!(allocator.live_count(), 2); + + allocator.release(&[0]).unwrap(); + assert_eq!( + allocator.release(&[0]), + Err(FixedSlabAllocatorError::SlotNotAllocated { slot: 0 }) + ); + assert_eq!(allocator.live_count(), 1); + allocator.release(&[1]).unwrap(); + assert!(allocator.is_empty()); + } + + #[test] + fn concurrent_single_slot_reservations_are_unique() { + let allocator = Arc::new(FixedSlabAllocator::new(64).unwrap()); + let reserved = Arc::new(Mutex::new(Vec::new())); + let workers = (0..8) + .map(|_| { + let allocator = Arc::clone(&allocator); + let reserved = Arc::clone(&reserved); + thread::spawn(move || { + while let Some(mut slots) = allocator.try_reserve(1) { + reserved.lock().unwrap().append(&mut slots); + } + }) + }) + .collect::>(); + for worker in workers { + worker.join().unwrap(); + } + + let slots = reserved.lock().unwrap(); + assert_eq!(slots.len(), 64); + assert_eq!(slots.iter().copied().collect::>().len(), 64); + allocator.release(&slots).unwrap(); + assert!(allocator.is_empty()); + } +} diff --git a/fluxon_rs/fluxon_util/src/lib.rs b/fluxon_rs/fluxon_util/src/lib.rs index 8d13b8e..b95ff96 100644 --- a/fluxon_rs/fluxon_util/src/lib.rs +++ b/fluxon_rs/fluxon_util/src/lib.rs @@ -1,5 +1,6 @@ pub mod dag_viz_html; pub mod dev_config; +pub mod fixed_slab_allocator; pub mod fs_statvfs; pub mod fs_watch; pub mod git_version_build_record; From b221a538777c28bdfb6068add57b9424f75ab2ce Mon Sep 17 00:00:00 2001 From: zTz01 <1773266173@qq.com> Date: Tue, 28 Jul 2026 13:47:01 +0800 Subject: [PATCH 10/10] ssd --- fluxon_py/config.py | 54 +- fluxon_py/tests/test_config.py | 82 + fluxon_rs/Cargo.lock | 326 +++- fluxon_rs/fluxon_kv/Cargo.toml | 1 + .../src/client_kv_api/external_api.rs | 126 +- fluxon_rs/fluxon_kv/src/client_kv_api/get.rs | 179 +- fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs | 1519 ++++++++++++++++- .../fluxon_kv/src/client_kv_api/msg_pack.rs | 32 + fluxon_rs/fluxon_kv/src/client_kv_api/put.rs | 958 +++++++++-- .../fluxon_kv/src/client_kv_api/reclaim.rs | 541 ++++-- .../fluxon_kv/src/cluster_manager/mod.rs | 2 + fluxon_rs/fluxon_kv/src/config.rs | 240 +++ .../external_client_test.rs | 2 + .../fluxon_kv/src/external_client_api/mod.rs | 477 +++++- fluxon_rs/fluxon_kv/src/kv_ssd_storage.rs | 1360 +++++++++++++++ fluxon_rs/fluxon_kv/src/kv_test.rs | 3 +- fluxon_rs/fluxon_kv/src/kvcore_test_lib.rs | 30 + fluxon_rs/fluxon_kv/src/lib.rs | 33 + .../fluxon_kv/src/master_kv_router/delete.rs | 8 +- .../fluxon_kv/src/master_kv_router/get.rs | 750 ++++++-- .../fluxon_kv/src/master_kv_router/mod.rs | 1200 ++++++++++--- .../src/master_kv_router/msg_pack.rs | 187 +- .../src/master_kv_router/placement.rs | 43 +- .../fluxon_kv/src/master_kv_router/put.rs | 255 ++- .../fluxon_kv/src/master_kv_router/reclaim.rs | 1272 +++++++++++--- .../src/master_kv_router/route_maintenance.rs | 2 +- .../fluxon_kv/src/master_seg_manager/mod.rs | 228 ++- .../master_seg_manager/one_seg_allocator.rs | 306 +++- fluxon_rs/fluxon_kv/src/memholder/lifetime.rs | 8 +- .../fluxon_kv/src/memholder/memholder_test.rs | 4 +- fluxon_rs/fluxon_kv/src/memholder/mod.rs | 57 +- .../rpcresp_kvresult_convert/msg_and_error.rs | 6 + fluxon_rs/fluxon_pyo3/src/lib.rs | 25 +- setup_and_pack/rather_no_git_submodule.yaml | 2 +- 34 files changed, 9187 insertions(+), 1131 deletions(-) create mode 100644 fluxon_rs/fluxon_kv/src/kv_ssd_storage.rs diff --git a/fluxon_py/config.py b/fluxon_py/config.py index 4eff497..7340d5f 100644 --- a/fluxon_py/config.py +++ b/fluxon_py/config.py @@ -83,6 +83,7 @@ def _yaml_template(): prefer_local_placement: false # Prefer placing new KV writes on the requester-local owner when possible (bool(optional)) short_circuit_put_payload_path: false # Keep large put_start allocation but skip payload memcpy + transfer (bool(optional)) skip_put_end_commit: false # Return success after payload transfer without put_done commit; inflight_put TTL cleanup only (bool(optional)) + ssd_read_source_policy: legacy_remote_first # legacy_remote_first|local_ssd_only_first (str(optional)) owner_local_reserve_soft_wait_timeout_ms: # Local-reserve polling interval, >0 (int(optional)) owner_local_reserve_hard_timeout_ms: # Local-reserve end-to-end claim timeout, > soft wait (int(optional)) owner_local_reserve_expected_capacity: # Owner-only local-reserve prewarm target (dict(optional)) @@ -117,6 +118,9 @@ def _yaml_template(): cluster_name: # Cluster name (str) share_mem_path: # Shared bundle path for mmap.file/shared.json/peer metadata (str) large_file_paths: # Owner-mode ordered large-file roots (['{str}'](optional)) + large_limit_size: # Optional per-root SSD capacity in bytes (list(optional)) + ssd_write_rate_limit_bytes_per_sec: # Optional non-queueing SSD write rate (int(optional)) + ssd_write_burst_bytes: # Paired immediate SSD write burst (int(optional)) p2p_listen_port: # P2P QUIC listen port override (int(optional)) redis_compat: # Enable Redis protocol shim (dict(optional)) listen_addr: # TCP listen addr, e.g. "127.0.0.1:16379" (str) @@ -142,6 +146,7 @@ def _normalize_test_spec_config(raw: Any, ctx: str) -> Dict[str, Any]: "prefer_local_placement", "short_circuit_put_payload_path", "skip_put_end_commit", + "ssd_read_source_policy", "owner_local_reserve_soft_wait_timeout_ms", "owner_local_reserve_hard_timeout_ms", "owner_local_reserve_expected_capacity", @@ -183,6 +188,21 @@ def _normalize_test_spec_config(raw: Any, ctx: str) -> Dict[str, Any]: raise ValueError(f"{ctx}.{key} must be a bool") out[key] = value + ssd_read_source_policy = raw.get("ssd_read_source_policy") + if ssd_read_source_policy is not None: + if not isinstance(ssd_read_source_policy, str): + raise ValueError(f"{ctx}.ssd_read_source_policy must be a string") + allowed_ssd_read_source_policies = { + "legacy_remote_first", + "local_ssd_only_first", + } + if ssd_read_source_policy not in allowed_ssd_read_source_policies: + raise ValueError( + f"{ctx}.ssd_read_source_policy must be one of " + f"{sorted(allowed_ssd_read_source_policies)}, got {ssd_read_source_policy!r}" + ) + out["ssd_read_source_policy"] = ssd_read_source_policy + transport_mode = raw.get("transport_mode") transport_mode_was_explicit = transport_mode is not None side_transfer_role_raw = raw.get("side_transfer_role") @@ -446,6 +466,9 @@ def _validate_fluxonkv_contract(cfg: Dict[str, Any]) -> None: "redis_compat", "sub_cluster", "large_file_paths", + "large_limit_size", + "ssd_write_rate_limit_bytes_per_sec", + "ssd_write_burst_bytes", ] for key in forbidden_spec_keys: if key in spec: @@ -502,6 +525,26 @@ def _validate_fluxonkv_contract(cfg: Dict[str, Any]) -> None: f"fluxonkv_spec.large_file_paths[{idx}] must be a non-empty string in owner mode" ) + write_rate = spec.get("ssd_write_rate_limit_bytes_per_sec") + write_burst = spec.get("ssd_write_burst_bytes") + if (write_rate is None) != (write_burst is None): + raise ValueError( + "fluxonkv_spec.ssd_write_rate_limit_bytes_per_sec and " + "ssd_write_burst_bytes must be configured together" + ) + if write_rate is not None: + if ( + isinstance(write_rate, bool) + or not isinstance(write_rate, int) + or write_rate <= 0 + or isinstance(write_burst, bool) + or not isinstance(write_burst, int) + or write_burst <= 0 + ): + raise ValueError("SSD write rate and burst must both be positive integers") + if "large_limit_size" not in spec: + raise ValueError("SSD write admission requires fluxonkv_spec.large_limit_size") + class FluxonKvClientConfig(): """Configuration class for KV Cache stores that reads from YAML config files.""" @@ -852,8 +895,8 @@ def parse_type_recursive(type_str: str) -> Optional[Tuple[str, Dict[str, Any]]]: return parsed_type_name, merged_params return type_name, {"constraint": constraint} - # 6) Primitive types: str, int, float, bool, None - if type_str in ["str", "int", "float", "bool", "None"]: + # 6) Primitive types: str, int, float, bool, list, None + if type_str in ["str", "int", "float", "bool", "list", "None"]: return type_str, {} debug_print("type_str ", type_str, "not matched to any type") @@ -989,6 +1032,13 @@ def raise_validation_error(msg: str): raise_validation_error(f"Expected bool, got {type(value).__name__}") else: return None + + elif type_name == "list": + if not isinstance(value, list): + if raise_err: + raise_validation_error(f"Expected list, got {type(value).__name__}") + else: + return None elif type_name == "dict": if not isinstance(value, dict): diff --git a/fluxon_py/tests/test_config.py b/fluxon_py/tests/test_config.py index 3ed2a5e..0b7cdc6 100644 --- a/fluxon_py/tests/test_config.py +++ b/fluxon_py/tests/test_config.py @@ -49,6 +49,7 @@ def _build_checks(selected_test_id: Optional[str]) -> List[Tuple[str, Callable[[ ("fluxonkv_owner_requires_sub_cluster", test_fluxonkv_owner_requires_sub_cluster), ("fluxonkv_owner_requires_large_file_paths", test_fluxonkv_owner_requires_large_file_paths), ("fluxonkv_external_forbids_large_file_paths", test_fluxonkv_external_forbids_large_file_paths), + ("fluxonkv_owner_ssd_capacity", test_fluxonkv_owner_ssd_capacity), ("fluxonkv_p2p_relay_removed", test_fluxonkv_p2p_relay_removed), ("fluxon_client_config_yaml_shape", test_fluxon_client_config_yaml_shape), ("fluxonkv_protocol_field", test_fluxonkv_protocol_field), @@ -334,6 +335,66 @@ def test_fluxonkv_external_forbids_large_file_paths(): print(f"❌ FAIL: test_fluxonkv_external_forbids_large_file_paths - {e}") +def test_fluxonkv_owner_ssd_capacity(): + """Ensure the Python schema forwards owner SSD capacity to Rust unchanged.""" + try: + owner = _owner_fluxonkv_base_config(tag="owner_ssd_capacity") + owner["fluxonkv_spec"]["large_limit_size"] = [67108864] + owner["fluxonkv_spec"]["ssd_write_rate_limit_bytes_per_sec"] = 268435456 + owner["fluxonkv_spec"]["ssd_write_burst_bytes"] = 67108864 + config = FluxonKvClientConfig(owner) + assert config.to_dict()["fluxonkv_spec"]["large_limit_size"] == [67108864] + assert ( + config.to_dict()["fluxonkv_spec"]["ssd_write_rate_limit_bytes_per_sec"] + == 268435456 + ) + assert config.to_dict()["fluxonkv_spec"]["ssd_write_burst_bytes"] == 67108864 + rendered = config.to_fluxon_kv_client_config_yaml_str() + assert "large_limit_size:" in rendered + assert "- 67108864" in rendered + assert "ssd_write_rate_limit_bytes_per_sec: 268435456" in rendered + assert "ssd_write_burst_bytes: 67108864" in rendered + + unpaired = _owner_fluxonkv_base_config(tag="owner_ssd_unpaired_limit") + unpaired["fluxonkv_spec"]["large_limit_size"] = [67108864] + unpaired["fluxonkv_spec"]["ssd_write_rate_limit_bytes_per_sec"] = 1 + try: + FluxonKvClientConfig(unpaired) + print("❌ FAIL: test_fluxonkv_owner_ssd_capacity - unpaired rate should be rejected") + return + except ValueError: + pass + + wrong_shape = _owner_fluxonkv_base_config(tag="owner_ssd_capacity_wrong_shape") + wrong_shape["fluxonkv_spec"]["large_limit_size"] = 67108864 + try: + FluxonKvClientConfig(wrong_shape) + print("❌ FAIL: test_fluxonkv_owner_ssd_capacity - non-list capacity should be rejected") + return + except ValueError: + pass + + external = { + "instance_key": "test_external_ssd_capacity", + "contribute_to_cluster_pool_size": {"dram": 0, "vram": {}}, + "fluxonkv_spec": { + "cluster_name": "test_cluster", + "share_mem_path": "/tmp/kvcache_shared_memory/test", + "large_limit_size": [67108864], + }, + } + try: + FluxonKvClientConfig(external) + print("❌ FAIL: test_fluxonkv_owner_ssd_capacity - external capacity should be rejected") + return + except ValueError: + pass + + print("✅ PASS: test_fluxonkv_owner_ssd_capacity") + except Exception as e: + print(f"❌ FAIL: test_fluxonkv_owner_ssd_capacity - {e}") + + def test_fluxonkv_p2p_relay_removed(): """Ensure removed fluxonkv_spec.p2p_relay is rejected as an unknown key.""" try: @@ -530,6 +591,9 @@ def test_fluxonkv_test_spec_config(): rdma_devices["test_spec_config"]["tcp_thread_bulk_lane_count"] = 4 rdma_devices["test_spec_config"]["tcp_thread_control_lane_count"] = 3 rdma_devices["test_spec_config"]["replica_task_max_inflight"] = 16 + rdma_devices["test_spec_config"]["ssd_read_source_policy"] = ( + "local_ssd_only_first" + ) rdma_devices["test_spec_config"][ "require_transfer_rpc_fast_path_ready_timeout_seconds" ] = 45 @@ -545,12 +609,30 @@ def test_fluxonkv_test_spec_config(): assert loaded["test_spec_config"]["tcp_thread_bulk_lane_count"] == 4 assert loaded["test_spec_config"]["tcp_thread_control_lane_count"] == 3 assert loaded["test_spec_config"]["replica_task_max_inflight"] == 16 + assert ( + loaded["test_spec_config"]["ssd_read_source_policy"] + == "local_ssd_only_first" + ) assert ( loaded["test_spec_config"]["require_transfer_rpc_fast_path_ready_timeout_seconds"] == 45 ) assert config.protocol_rdma_device_names == "mlx5_0,mlx5_4" + for removed_policy in ( + "local_ssd_after_memory", + "local_ssd_before_remote_memory", + ): + invalid_policy = copy.deepcopy(rdma_devices) + invalid_policy["test_spec_config"]["ssd_read_source_policy"] = removed_policy + try: + FluxonKvClientConfig(invalid_policy) + raise AssertionError( + f"removed SSD read policy must be rejected: {removed_policy}" + ) + except ValueError: + pass + expected_capacity = _owner_fluxonkv_base_config(tag="expected_capacity") expected_capacity["contribute_to_cluster_pool_size"]["dram"] = 137438953472 expected_capacity["test_spec_config"] = { diff --git a/fluxon_rs/Cargo.lock b/fluxon_rs/Cargo.lock index a4b0ecd..59b0cd0 100644 --- a/fluxon_rs/Cargo.lock +++ b/fluxon_rs/Cargo.lock @@ -485,6 +485,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d" dependencies = [ "find-msvc-tools", + "jobserver", + "libc", "shlex", ] @@ -575,6 +577,12 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +[[package]] +name = "cmsketch" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7ee2cfacbd29706479902b06d75ad8f1362900836aa32799eabc7e004bfd854" + [[package]] name = "cobs" version = "0.3.0" @@ -615,6 +623,17 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "core_affinity" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a034b3a7b624016c6e13f5df875747cc25f884156aad2abd12b6c46797971342" +dependencies = [ + "libc", + "num_cpus", + "winapi", +] + [[package]] name = "cpp_demangle" version = "0.4.5" @@ -960,6 +979,16 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" +[[package]] +name = "fastant" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e825441bfb2d831c47c97d05821552db8832479f44c571b97fededbf0099c07" +dependencies = [ + "small_ctor", + "web-time", +] + [[package]] name = "fastrand" version = "2.3.0" @@ -1232,6 +1261,7 @@ dependencies = [ "fluxon_framework_compiled", "fluxon_observability", "fluxon_util", + "foyer", "futures", "hex", "hyper 0.14.32", @@ -1447,6 +1477,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "foreign-types" version = "0.3.2" @@ -1471,6 +1507,130 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "foyer" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0abc0b87814989efa711f9becd9f26969820e2d3905db27d10969c4bd45890" +dependencies = [ + "anyhow", + "equivalent", + "foyer-common", + "foyer-memory", + "foyer-storage", + "foyer-tokio", + "futures-util", + "mea", + "mixtrics", + "pin-project", + "serde", + "tracing", +] + +[[package]] +name = "foyer-common" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3db80d5dece93adb7ad709c84578794724a9cba342a7e566c3551c7ec626789" +dependencies = [ + "anyhow", + "bincode", + "bytes", + "cfg-if", + "foyer-tokio", + "mixtrics", + "parking_lot", + "pin-project", + "serde", + "twox-hash", +] + +[[package]] +name = "foyer-intrusive-collections" +version = "0.10.0-dev" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4fee46bea69e0596130e3210e65d3424e0ac1e6df3bde6636304bdf1ca4a3b" +dependencies = [ + "memoffset", +] + +[[package]] +name = "foyer-memory" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db907f40a527ca2aa2f40a5f68b32ea58aa70f050cd233518e9ffd402cfba6ce" +dependencies = [ + "anyhow", + "bitflags 2.9.1", + "cmsketch", + "equivalent", + "foyer-common", + "foyer-intrusive-collections", + "foyer-tokio", + "futures-util", + "hashbrown 0.16.1", + "itertools 0.14.0", + "mea", + "mixtrics", + "parking_lot", + "paste", + "pin-project", + "serde", + "tracing", +] + +[[package]] +name = "foyer-storage" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1983f1db3d0710e9c9d5fc116d9202dccd41a2d1e032572224f1aff5520aa958" +dependencies = [ + "allocator-api2", + "anyhow", + "bytes", + "core_affinity", + "equivalent", + "fastant", + "foyer-common", + "foyer-memory", + "foyer-tokio", + "fs4", + "futures-core", + "futures-util", + "hashbrown 0.16.1", + "io-uring", + "itertools 0.14.0", + "libc", + "lz4", + "mea", + "parking_lot", + "pin-project", + "rand 0.9.2", + "serde", + "tracing", + "twox-hash", + "zstd", +] + +[[package]] +name = "foyer-tokio" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6577b05a7ffad0db555aedf00bfe52af818220fc4c1c3a7a12520896fc38627" +dependencies = [ + "tokio", +] + +[[package]] +name = "fs4" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8640e34b88f7652208ce9e88b1a37a2ae95227d84abec377ccd3c5cfeb141ed4" +dependencies = [ + "rustix 1.0.7", + "windows-sys 0.59.0", +] + [[package]] name = "futures" version = "0.3.31" @@ -1618,11 +1778,22 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "r-efi", + "r-efi 5.3.0", "wasi 0.14.2+wasi-0.2.4", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", +] + [[package]] name = "gimli" version = "0.31.1" @@ -1711,7 +1882,18 @@ checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", ] [[package]] @@ -2395,6 +2577,17 @@ dependencies = [ "str_stack", ] +[[package]] +name = "io-uring" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9080b15e63775b9a2ac7dca720f7050a8b955e092ea0f6020a4a80f69998cdc0" +dependencies = [ + "bitflags 2.9.1", + "cfg-if", + "libc", +] + [[package]] name = "ipnet" version = "2.11.0" @@ -2446,12 +2639,40 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "jobserver" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" +dependencies = [ + "getrandom 0.4.3", + "libc", +] + [[package]] name = "js-sys" version = "0.3.77" @@ -2586,6 +2807,25 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +[[package]] +name = "lz4" +version = "1.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a20b523e860d03443e98350ceaac5e71c6ba89aea7d960769ec3ce37f4de5af4" +dependencies = [ + "lz4-sys", +] + +[[package]] +name = "lz4-sys" +version = "1.11.1+lz4-1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "matchers" version = "0.1.0" @@ -2601,6 +2841,15 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +[[package]] +name = "mea" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2640d335e7273dacdcf51044026139b2e269c3bb0dfc3f8cb3496b85e3f6a42c" +dependencies = [ + "slab", +] + [[package]] name = "memchr" version = "2.7.5" @@ -2668,6 +2917,16 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "mixtrics" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c46b5adfb7a3ae4996d327a5bdc90e78fec025806dd312bdbe6f07a755e0ec9" +dependencies = [ + "itertools 0.15.0", + "parking_lot", +] + [[package]] name = "moka" version = "0.12.11" @@ -2831,6 +3090,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "object" version = "0.36.7" @@ -3498,6 +3767,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "rand" version = "0.7.3" @@ -4206,9 +4481,15 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "slab" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "small_ctor" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88414a5ca1f85d82cc34471e975f0f74f6aa54c40f062efa42c0080e7f763f81" [[package]] name = "smallvec" @@ -5080,6 +5361,15 @@ dependencies = [ "utf-8", ] +[[package]] +name = "twox-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8464ec13c3691491391d9fce00f6416c9a48e46972f72d7865688be2080192c9" +dependencies = [ + "rand 0.9.2", +] + [[package]] name = "typenum" version = "1.18.0" @@ -5902,3 +6192,31 @@ dependencies = [ "quote", "syn 2.0.104", ] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/fluxon_rs/fluxon_kv/Cargo.toml b/fluxon_rs/fluxon_kv/Cargo.toml index 22ff136..2d0208c 100644 --- a/fluxon_rs/fluxon_kv/Cargo.toml +++ b/fluxon_rs/fluxon_kv/Cargo.toml @@ -75,6 +75,7 @@ bytes = "1" pprof = { version = "0.15", features = ["flamegraph"] } hex = "0.4" sha2 = "0.10" +foyer = { version = "0.22.3", features = ["serde"] } tokio-tungstenite = { version = "0.21", default-features = false, features = ["connect", "handshake"], optional = true } sockudo-ws = { version = "^1.7.4", default-features = false, features = ["tokio-runtime", "fastrand"], optional = true } diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs index e6f3caa..c63a298 100755 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/external_api.rs @@ -1298,6 +1298,7 @@ mod external_get_start_batch_tests { external_pending_puts: 0, external_put: None, remote_put: None, + local_ssd_put: None, source_eviction_selection: None, reclaim: None, external_get: Some(old.clone()), @@ -1329,6 +1330,7 @@ mod external_get_start_batch_tests { external_pending_puts: 0, external_put: None, remote_put: None, + local_ssd_put: None, source_eviction_selection: None, reclaim: None, external_get: Some(op.clone()), @@ -3586,7 +3588,8 @@ impl HandlerForExternalClient for ClientKvApi { remote_offset }, len: req.len, - make_replica_task: req.make_replica_task && replica_admitted, + make_replica_task: req.make_replica_task, + remote_replica_admitted: replica_admitted, preferred_sub_cluster: req.preferred_sub_cluster.clone(), local_reserve_slot: None, local_reserve_slot_size: None, @@ -3838,6 +3841,7 @@ impl HandlerForExternalClient for ClientKvApi { target_offset: src_offset, len: req_item.len, make_replica_task: req_item.make_replica_task, + remote_replica_admitted: true, preferred_sub_cluster: req_item.preferred_sub_cluster.clone(), local_reserve_slot: Some(slot_ref.clone()), local_reserve_slot_size: Some(slot_size), @@ -3916,7 +3920,8 @@ impl HandlerForExternalClient for ClientKvApi { return Ok(ExternalPutTransferEndResp::from_error(&err)); } }; - let admitted_replica_task = pending_ctx.make_replica_task; + let admitted_replica_task = + pending_ctx.make_replica_task && pending_ctx.remote_replica_admitted; let self_node_id = inner.view.cluster_manager().get_self_info().id.clone(); let req_remote_target = req .peer_id @@ -4053,6 +4058,13 @@ impl HandlerForExternalClient for ClientKvApi { inner .external_pending_puts .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + if pending_ctx.make_replica_task { + inner.start_early_owner_local_ssd_put( + &req.key, + put_id, + u64::from(local_cache_publish.len), + ); + } if admitted_replica_task { if let Err(err) = inner .ensure_remote_put( @@ -4125,6 +4137,7 @@ impl HandlerForExternalClient for ClientKvApi { put_locality: Option<(bool, i64)>, local_cache_publish: LocalCommittedCachePublish, make_replica_task: bool, + remote_replica_admitted: bool, // Keep the per-key reclaim fence alive until the master's terminal // response has been applied to the owner-local index. _pending_ctx: ExternalPendingPutCtx, @@ -4214,6 +4227,7 @@ impl HandlerForExternalClient for ClientKvApi { lease_id: item.lease_id, committed_slot, make_replica_task: pending_ctx.make_replica_task, + remote_replica_admitted: pending_ctx.remote_replica_admitted, preferred_sub_cluster: pending_ctx.preferred_sub_cluster.clone(), atomic_group: pending_ctx.atomic_group.clone(), }); @@ -4288,6 +4302,7 @@ impl HandlerForExternalClient for ClientKvApi { put_locality: Some((false, 0)), local_cache_publish, make_replica_task: pending_ctx.make_replica_task, + remote_replica_admitted: pending_ctx.remote_replica_admitted, _pending_ctx: pending_ctx, }); } @@ -4380,6 +4395,8 @@ impl HandlerForExternalClient for ClientKvApi { })); } + let mut early_ssd_candidates = Vec::new(); + let mut remote_replica_pending = Vec::new(); for (pending, done_item) in done_pending.into_iter().zip(done_resp.items.into_iter()) { if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( done_item.error_code, @@ -4414,23 +4431,18 @@ impl HandlerForExternalClient for ClientKvApi { pending.put_id.1, )); if pending.make_replica_task { - if let Err(err) = inner - .ensure_remote_put( - &pending.key, - pending.put_id, - pending._pending_ctx.preferred_sub_cluster.clone(), - true, - ) - .await - { - tracing::warn!( - "external_batch_put_transfer_end make replica task failed after local commit: key={} put_id=({},{}) err={}", - pending.key, - pending.put_id.0, - pending.put_id.1, - err - ); - } + early_ssd_candidates.push(( + pending.key.clone(), + pending.put_id, + u64::from(pending.local_cache_publish.len), + )); + } + if pending.make_replica_task && pending.remote_replica_admitted { + remote_replica_pending.push(( + pending.key.clone(), + pending.put_id, + pending._pending_ctx.preferred_sub_cluster.clone(), + )); } results[pending.idx] = Some(ExternalBatchPutTransferEndItemResp { error_code: OK, @@ -4438,6 +4450,22 @@ impl HandlerForExternalClient for ClientKvApi { }); } + inner.start_early_owner_local_ssd_puts(early_ssd_candidates); + for (key, put_id, preferred_sub_cluster) in remote_replica_pending { + if let Err(err) = inner + .ensure_remote_put(&key, put_id, preferred_sub_cluster, true) + .await + { + tracing::warn!( + "external_batch_put_transfer_end make replica task failed after local commit: key={} put_id=({},{}) err={}", + key, + put_id.0, + put_id.1, + err + ); + } + } + Ok(ExternalBatchPutTransferEndResp { items: results .into_iter() @@ -4512,7 +4540,8 @@ impl HandlerForExternalClient for ClientKvApi { } return Ok(ExternalPutCommitResp::from_error(&err)); } - let admitted_replica_task = pending_ctx.make_replica_task; + let admitted_replica_task = + pending_ctx.make_replica_task && pending_ctx.remote_replica_admitted; let end_started_at = Instant::now(); let local_cache_publish = match local_committed_cache_publish( @@ -4587,6 +4616,13 @@ impl HandlerForExternalClient for ClientKvApi { inner .external_pending_puts .invalidate(&(req.key.clone(), put_id.0, put_id.1)); + if pending_ctx.make_replica_task { + inner.start_early_owner_local_ssd_put( + &req.key, + put_id, + u64::from(local_cache_publish.len), + ); + } if admitted_replica_task { if let Err(err) = inner .ensure_remote_put( @@ -4650,6 +4686,7 @@ impl HandlerForExternalClient for ClientKvApi { lease_id: Option, local_cache_publish: LocalCommittedCachePublish, make_replica_task: bool, + remote_replica_admitted: bool, _pending_ctx: ExternalPendingPutCtx, } @@ -4736,6 +4773,7 @@ impl HandlerForExternalClient for ClientKvApi { lease_id: item.lease_id, committed_slot, make_replica_task: pending_ctx.make_replica_task, + remote_replica_admitted: pending_ctx.remote_replica_admitted, preferred_sub_cluster: pending_ctx.preferred_sub_cluster.clone(), atomic_group: pending_ctx.atomic_group.clone(), }); @@ -4804,6 +4842,7 @@ impl HandlerForExternalClient for ClientKvApi { lease_id: item.lease_id, local_cache_publish, make_replica_task: pending_ctx.make_replica_task, + remote_replica_admitted: pending_ctx.remote_replica_admitted, _pending_ctx: pending_ctx, }); } @@ -4893,6 +4932,8 @@ impl HandlerForExternalClient for ClientKvApi { })); } + let mut early_ssd_candidates = Vec::new(); + let mut remote_replica_pending = Vec::new(); for (pending, done_item) in done_pending.into_iter().zip(done_resp.items.into_iter()) { if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( done_item.error_code, @@ -4924,23 +4965,18 @@ impl HandlerForExternalClient for ClientKvApi { pending.put_id.1, )); if pending.make_replica_task { - if let Err(err) = inner - .ensure_remote_put( - &pending.key, - pending.put_id, - pending._pending_ctx.preferred_sub_cluster.clone(), - true, - ) - .await - { - tracing::warn!( - "external_batch_put_commit make replica task failed after local commit: key={} put_id=({},{}) err={}", - pending.key, - pending.put_id.0, - pending.put_id.1, - err - ); - } + early_ssd_candidates.push(( + pending.key.clone(), + pending.put_id, + u64::from(pending.local_cache_publish.len), + )); + } + if pending.make_replica_task && pending.remote_replica_admitted { + remote_replica_pending.push(( + pending.key.clone(), + pending.put_id, + pending._pending_ctx.preferred_sub_cluster.clone(), + )); } results[pending.idx] = Some(ExternalBatchPutCommitItemResp { error_code: OK, @@ -4948,6 +4984,22 @@ impl HandlerForExternalClient for ClientKvApi { }); } + inner.start_early_owner_local_ssd_puts(early_ssd_candidates); + for (key, put_id, preferred_sub_cluster) in remote_replica_pending { + if let Err(err) = inner + .ensure_remote_put(&key, put_id, preferred_sub_cluster, true) + .await + { + tracing::warn!( + "external_batch_put_commit make replica task failed after local commit: key={} put_id=({},{}) err={}", + key, + put_id.0, + put_id.1, + err + ); + } + } + Ok(ExternalBatchPutCommitResp { items: results .into_iter() diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs index 35e2dd4..27d57ec 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/get.rs @@ -18,7 +18,7 @@ use crate::{ BatchGetRevokeReq, BatchGetRevokeResp, BatchGetStartItemResp, BatchGetStartReq, BatchGetStartResp, BatchIsExistReq, GetAllocationMode, GetBindTarget, GetDoneReq, GetDoneResp, GetMetaReq, GetMetaResp, GetPreparedLocalReserveTarget, GetRevokeReq, - GetStartReq, GetStartResp, + GetSourceKind, GetStartReq, GetStartResp, }, p2p::msg_pack::MsgPack, rpcresp_kvresult_convert::msg_and_error::codes_api, @@ -28,6 +28,7 @@ use ::tokio::sync::Semaphore; use chrono::Utc; use futures::stream::{self, StreamExt}; use limit_thirdparty::tokio; +use std::collections::HashSet; use std::sync::Arc; use std::sync::OnceLock; use std::time::Duration; @@ -287,6 +288,10 @@ impl ClientKvApiInner { let mut lifecycle_remote_transfer_items = 0usize; let mut lifecycle_transfer_bytes = 0u64; let mut lifecycle_remote_transfer_bytes = 0u64; + let mut lifecycle_local_ssd_items = 0usize; + let mut lifecycle_remote_ssd_items = 0usize; + let mut lifecycle_transfer_source_nodes = HashSet::new(); + let mut lifecycle_ssd_source_nodes = HashSet::new(); for (idx, (key, start_item)) in keys.into_iter().zip(start_items.into_iter()).enumerate() { if start_item.error_code == codes_api::API_KEY_NOT_FOUND { @@ -318,7 +323,20 @@ impl ClientKvApiInner { let target_addr = start_item.target_addr; let len = start_item.len; - if peer_id.is_none() && src_addr == target_addr { + lifecycle_transfer_source_nodes.insert(start_item.node_id.to_string()); + if start_item.source_kind == GetSourceKind::Ssd { + lifecycle_ssd_source_nodes.insert(start_item.node_id.to_string()); + if peer_is_remote { + lifecycle_remote_ssd_items = lifecycle_remote_ssd_items.saturating_add(1); + } else { + lifecycle_local_ssd_items = lifecycle_local_ssd_items.saturating_add(1); + } + } + + if start_item.source_kind == GetSourceKind::Memory + && peer_id.is_none() + && src_addr == target_addr + { lifecycle_zero_copy_items = lifecycle_zero_copy_items.saturating_add(1); done_pending.push(DonePending { idx, @@ -341,19 +359,33 @@ impl ClientKvApiInner { transfer_futures.push(async move { let transfer_started_at = Instant::now(); - let transfer_result = self - .view - .client_transfer_engine() - .transfer_data_no_copy(peer_id, true, src_addr, target_addr, len, None) + let transfer_result = if start_item.source_kind == GetSourceKind::Ssd { + self.stage_kv_from_ssd_source( + &start_item.node_id, + &key, + start_item.put_id, + get_id, + src_addr, + len, + target_addr, + len, + ) .await - .map_err(|err| { - KvError::Api(ApiError::Transfer { - from_addr: src_addr, - to_addr: target_addr, - len, - error: err.to_string(), + } else { + self.view + .client_transfer_engine() + .transfer_data_no_copy(peer_id, true, src_addr, target_addr, len, None) + .await + .map(|_| ()) + .map_err(|err| { + KvError::Api(ApiError::Transfer { + from_addr: src_addr, + to_addr: target_addr, + len, + error: err.to_string(), + }) }) - }); + }; let transfer_us = transfer_started_at .elapsed() .as_micros() @@ -702,12 +734,16 @@ impl ClientKvApiInner { .as_micros() .min(i64::MAX as u128) as i64; tracing::info!( - "external Get finish lifecycle: requested={} transfer_concurrency={} zero_copy_items={} transfer_items={} remote_transfer_items={} transfer_bytes={} remote_transfer_bytes={} plan_us={} transfer_wall_us={} transfer_sum_us={} transfer_max_us={} transfer_cleanup_us={} install_us={} done_items={} done_attempts={} done_us={} local_hot_admissions={} publish_us={} hits={} misses={} errors={} total_us={}", + "external Get finish lifecycle: requested={} transfer_concurrency={} zero_copy_items={} transfer_items={} remote_transfer_items={} local_ssd_items={} remote_ssd_items={} transfer_source_nodes={} ssd_source_nodes={} transfer_bytes={} remote_transfer_bytes={} plan_us={} transfer_wall_us={} transfer_sum_us={} transfer_max_us={} transfer_cleanup_us={} install_us={} done_items={} done_attempts={} done_us={} local_hot_admissions={} publish_us={} hits={} misses={} errors={} total_us={}", lifecycle_requested_keys, transfer_concurrency, lifecycle_zero_copy_items, lifecycle_transfer_items, lifecycle_remote_transfer_items, + lifecycle_local_ssd_items, + lifecycle_remote_ssd_items, + lifecycle_transfer_source_nodes.len(), + lifecycle_ssd_source_nodes.len(), lifecycle_transfer_bytes, lifecycle_remote_transfer_bytes, lifecycle_plan_us, @@ -847,7 +883,10 @@ impl ClientKvApiInner { let target_addr = start_item.target_addr; let len = start_item.len; - if peer_id.is_none() && src_addr == target_addr { + if start_item.source_kind == GetSourceKind::Memory + && peer_id.is_none() + && src_addr == target_addr + { done_pending.push(DonePending { idx, key, @@ -860,19 +899,33 @@ impl ClientKvApiInner { transfer_futures.push(async move { let transfer_started_at = Instant::now(); - let transfer_result = self - .view - .client_transfer_engine() - .transfer_data_no_copy(peer_id, true, src_addr, target_addr, len, None) + let transfer_result = if start_item.source_kind == GetSourceKind::Ssd { + self.stage_kv_from_ssd_source( + &start_item.node_id, + &key, + start_item.put_id, + get_id, + src_addr, + len, + target_addr, + len, + ) .await - .map_err(|err| { - KvError::Api(ApiError::Transfer { - from_addr: src_addr, - to_addr: target_addr, - len, - error: err.to_string(), + } else { + self.view + .client_transfer_engine() + .transfer_data_no_copy(peer_id, true, src_addr, target_addr, len, None) + .await + .map(|_| ()) + .map_err(|err| { + KvError::Api(ApiError::Transfer { + from_addr: src_addr, + to_addr: target_addr, + len, + error: err.to_string(), + }) }) - }); + }; let transfer_us = transfer_started_at .elapsed() .as_micros() @@ -1209,18 +1262,26 @@ impl ClientKvApiInner { ); } - // transfer data (skip if local and src==target to avoid redundant copy) - if peer_id.is_none() && abs_src == abs_target { + let transfer_result = if resp.source_kind == GetSourceKind::Ssd { + self.stage_kv_from_ssd_source( + &resp.node_id, + key, + put_id, + get_id, + abs_src, + data_len as u64, + abs_target, + data_len as u64, + ) + .await + } else if peer_id.is_none() && abs_src == abs_target { tracing::debug!( "kv get local no-op: src==target {:#x}, len={} (skip transfer)", abs_target, data_len ); + Ok(()) } else { - // tracing::debug!( - // "kv get transfer in transfer engine path from {}", - // peer_id.as_ref().map(|v| &**v).unwrap_or("self") - // ); tracing::debug!( "p2p get transfer: key={}, remote_src={:#x} -> local_target={:#x}, len={}, peer={:?}", key, @@ -1229,8 +1290,7 @@ impl ClientKvApiInner { data_len, peer_id ); - if let Err(e) = self - .view + self.view .client_transfer_engine() .transfer_data_no_copy( peer_id.clone(), @@ -1241,33 +1301,32 @@ impl ClientKvApiInner { None, ) .await - { - tracing::warn!("transfer data failed: {:?}", e); - - #[cfg(test)] - { - self.test_record.remove_transfering_get(get_id); - } - - obe_get_transfer_error(&metrics, &client_id, &node_role, key, data_len as u64); - self.get_revoke(get_id).await?; - return Err(KvError::Api(ApiError::Transfer { - from_addr: abs_src, - to_addr: abs_target, - len: data_len as u64, - error: e.to_string(), - })); - } else { - tracing::debug!( - "get_transfer success key={}, src_addr={:#x}, target_addr={:#x}, len={}, peer_id={:?}", - key, - abs_src, - abs_target, - data_len, - peer_id - ); - } + .map(|_| ()) + .map_err(|err| { + KvError::Api(ApiError::Transfer { + from_addr: abs_src, + to_addr: abs_target, + len: data_len as u64, + error: err.to_string(), + }) + }) + }; + if let Err(err) = transfer_result { + tracing::warn!("transfer data failed: {:?}", err); + #[cfg(test)] + self.test_record.remove_transfering_get(get_id); + obe_get_transfer_error(&metrics, &client_id, &node_role, key, data_len as u64); + self.get_revoke(get_id).await?; + return Err(err); } + tracing::debug!( + "get_transfer success key={}, src_addr={:#x}, target_addr={:#x}, len={}, peer_id={:?}", + key, + abs_src, + abs_target, + data_len, + peer_id + ); let t3 = Utc::now().timestamp_micros(); obe_get_transfer_success( &metrics, diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs index 6d59d5f..5ecf000 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/mod.rs @@ -15,17 +15,22 @@ use crate::client_kv_api::msg_pack::{ ExternalIsExistResp, ExternalObservabilitySnapshotReq, ExternalObservabilitySnapshotResp, ExternalPutCommitReq, ExternalPutCommitResp, ExternalPutRevokeReq, ExternalPutRevokeResp, ExternalPutStartReq, ExternalPutStartResp, ExternalPutTransferEndReq, - ExternalPutTransferEndResp, SyncKvToFileReq, SyncKvToFileResp, TestPutPhaseTrace, + ExternalPutTransferEndResp, SsdStageReadReq, SsdStageReadResp, SyncKvToFileReq, + SyncKvToFileResp, TestPutPhaseTrace, }; use crate::client_kv_api::reclaim::handle_batch_owner_reclaim; +use crate::cluster_manager::app_logic_ext::ClusterManagerAppLogicExt; use crate::cluster_manager::{NodeID, NodeIDString}; use crate::config::TestSpecConfig; +use crate::kv_ssd_storage::{ + KvSsdPersistBatchPermit, KvSsdPersistCopy, KvSsdPersistSource, KvSsdStorage, KvSsdStorageInit, +}; use crate::master_kv_router::msg_pack::{ BatchDeleteAckReq, BatchDeleteClientKvMetaCacheReq, BatchEnqueueReplicaTaskReq, BatchEvictOwnerSourceReq, BatchGetBindReq, BatchGetDoneReq, BatchGetRevokeReq, BatchGetStartItemResp, BatchGetStartReq, BatchIsExistReq, BatchOwnerReclaimReq, - BatchPreparePutKeysReq, BatchPutAppendDoneReq, BatchPutAppendStartReq, BatchPutDoneReq, - BatchPutRevokeReq, BatchPutStartReq, BatchReleasePutKeyReservationsReq, + BatchPreparePutKeysReq, BatchPublishOwnerSsdReq, BatchPutAppendDoneReq, BatchPutAppendStartReq, + BatchPutDoneReq, BatchPutRevokeReq, BatchPutStartReq, BatchReleasePutKeyReservationsReq, DeleteClientKvMetaCacheItem, GroupedBatchPutDoneReq, }; use crate::master_lease_manager::msg_pack::{AllocateClientLeaseReq, ClientLeaseKeepaliveReq}; @@ -41,13 +46,13 @@ use crate::{ master_kv_router::msg_pack::{ DeleteReq, GetDoneReq, GetMetaReq, GetRevokeReq, GetStartReq, PutAppendDoneReq, PutAppendRevokeReq, PutAppendStartReq, PutDoneReq, PutRevokeReq, PutStartReq, - ReleaseLocalGrantReq, ReserveLocalGrantReq, + ReleaseLocalGrantReq, ReserveLocalGrantReq, SsdStageBeginReq, SsdStageDoneReq, }, metric_reporter::{MetricReporter, MetricReporterAccessTrait}, metrics::{KvLocalitySnapshot, MetricsHandle, OperationKind, RequestStage}, p2p::{ msg_pack::{RPCCaller, RPCHandler}, - p2p_module::{P2pModule, P2pModuleAccessTrait}, + p2p_module::{P2pModule, P2pModuleAccessTrait, RpcTransportPolicy}, }, rpcresp_kvresult_convert::msg_and_error::{ApiError, ErrorCode, KvError, KvResult}, }; @@ -71,6 +76,129 @@ use tracing::warn; const OWNER_LOCAL_PUBLISH_QUEUE_CAPACITY: usize = 4096; const OWNER_LOCAL_PUBLISH_MAX_INFLIGHT: usize = 64; +const SSD_STAGE_RPC_TIMEOUT: Duration = Duration::from_secs(300); +const SSD_STAGE_TERMINAL_TTL: Duration = Duration::from_secs(10 * 60); +const SSD_STAGE_DONE_RETRY_INITIAL_BACKOFF: Duration = Duration::from_millis(50); +const SSD_STAGE_DONE_RETRY_MAX_BACKOFF: Duration = Duration::from_secs(5); + +#[derive(Clone, Debug)] +struct CompletedSsdStage { + request: SsdStageReadReq, + response: SsdStageReadResp, +} + +struct SsdStageSharedOp { + request: SsdStageReadReq, + terminal: watch::Sender>, + completed: AtomicBool, +} + +impl SsdStageSharedOp { + fn new(request: SsdStageReadReq) -> Arc { + let (terminal, _receiver) = watch::channel(None); + Arc::new(Self { + request, + terminal, + completed: AtomicBool::new(false), + }) + } + + fn complete(&self, response: SsdStageReadResp) -> bool { + if self + .completed + .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire) + .is_err() + { + return false; + } + self.terminal.send_replace(Some(response)); + true + } + + async fn wait(&self) -> SsdStageReadResp { + let mut terminal = self.terminal.subscribe(); + loop { + if let Some(response) = terminal.borrow_and_update().clone() { + return response; + } + if terminal.changed().await.is_err() { + let err = KvError::Api(ApiError::Unknown { + detail: format!( + "SSD stage singleflight closed without a terminal result: get_id={}", + self.request.get_id + ), + }); + return ssd_stage_error_response(err); + } + } + } +} + +fn ssd_stage_error_response(err: KvError) -> SsdStageReadResp { + SsdStageReadResp { + error_code: err.code(), + error_json: err.to_json(), + } +} + +fn ssd_stage_request_mismatch_response( + expected: &SsdStageReadReq, + actual: &SsdStageReadReq, +) -> SsdStageReadResp { + ssd_stage_error_response(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "SSD stage get_id was reused with a different operation identity: get_id={} expected={:?} actual={:?}", + actual.get_id, expected, actual + ), + })) +} + +#[cfg(test)] +mod ssd_stage_singleflight_tests { + use super::{SsdStageReadReq, SsdStageReadResp, SsdStageSharedOp}; + use crate::rpcresp_kvresult_convert::msg_and_error::OK; + use std::sync::Arc; + + fn request(get_id: u64) -> SsdStageReadReq { + SsdStageReadReq { + key: "ssd-key".to_string(), + put_id: (17, 2), + get_id, + stage_addr: 0x1000, + stage_capacity: 8192, + len: 4096, + } + } + + #[limit_thirdparty::tokio::test] + async fn all_ssd_stage_followers_reuse_one_terminal_result() { + let op = SsdStageSharedOp::new(request(91)); + let waiters = futures::future::join_all((0..64).map(|_| { + let waiter = op.clone(); + async move { waiter.wait().await } + })); + let leader = async { + assert!(op.complete(SsdStageReadResp { + error_code: OK, + error_json: String::new(), + })); + assert!( + !op.complete(SsdStageReadResp { + error_code: 1, + error_json: "second terminal".to_string(), + }), + "the source operation must publish only one terminal result" + ); + }; + let (responses, ()) = futures::future::join(waiters, leader).await; + + for response in responses { + assert_eq!(response.error_code, OK); + assert!(response.error_json.is_empty()); + } + assert_eq!(Arc::strong_count(&op), 1); + } +} /// Information about a memholder held by external client #[derive(Clone)] @@ -87,6 +215,60 @@ pub struct ExternalHoldingGetInfo { #[derive(Clone, Debug, Default)] pub struct OwnerRuntimeObserveSnapshot { + pub ssd_capacity_bytes: u64, + pub ssd_used_bytes: u64, + pub ssd_persist_requests: u64, + pub ssd_persist_successes: u64, + pub ssd_persist_failures: u64, + pub ssd_persist_bytes: u64, + pub ssd_persist_duration_us: u64, + pub ssd_persist_batch_requests: u64, + pub ssd_persist_batch_items: u64, + pub ssd_persist_flush_batches: u64, + pub ssd_persist_busy_batches: u64, + pub ssd_persist_admission_skips: u64, + pub ssd_persist_batch_duration_us: u64, + pub ssd_write_candidate_items: u64, + pub ssd_write_candidate_bytes: u64, + pub ssd_write_admitted_items: u64, + pub ssd_write_admitted_bytes: u64, + pub ssd_write_dropped_items: u64, + pub ssd_write_dropped_bytes: u64, + pub ssd_write_refunded_items: u64, + pub ssd_write_refunded_bytes: u64, + pub ssd_load_requests: u64, + pub ssd_load_successes: u64, + pub ssd_load_misses: u64, + pub ssd_load_failures: u64, + pub ssd_load_bytes: u64, + pub ssd_load_duration_us: u64, + pub ssd_memory_hits: u64, + pub ssd_disk_hits: u64, + pub ssd_outer_hits: u64, + pub ssd_removals: u64, + pub ssd_stage_flights: u64, + pub ssd_stage_terminals: u64, + pub ssd_stage_ready_requests: u64, + pub ssd_stage_ready_successes: u64, + pub ssd_stage_ready_failures: u64, + pub ssd_stage_ready_duration_us: u64, + pub ssd_stage_execute_completions: u64, + pub ssd_stage_terminal_published: u64, + pub ssd_stage_terminal_cache_inserts: u64, + pub ssd_stage_terminal_cache_duration_us: u64, + pub ssd_stage_response_send_attempts: u64, + pub ssd_stage_response_send_successes: u64, + pub ssd_stage_response_send_failures: u64, + pub ssd_stage_response_send_duration_us: u64, + pub ssd_source_ready_wait_requests: u64, + pub ssd_source_ready_wait_successes: u64, + pub ssd_source_ready_wait_failures: u64, + pub ssd_source_ready_wait_duration_us: u64, + pub ssd_target_pull_requests: u64, + pub ssd_target_pull_successes: u64, + pub ssd_target_pull_failures: u64, + pub ssd_target_pull_duration_us: u64, + pub ssd_stage_done_detached: u64, pub external_get_holding_entries: u64, pub external_get_holding_bytes: u64, pub external_get_start_handles: u64, @@ -117,6 +299,15 @@ pub struct OwnerRuntimeObserveSnapshot { pub remote_put_already_satisfied: u64, pub remote_put_obsolete: u64, pub remote_put_failed: u64, + pub local_ssd_put_flights_active: u64, + pub local_ssd_put_flight_leaders: u64, + pub local_ssd_put_flight_followers: u64, + pub local_ssd_put_source_unavailable: u64, + pub local_ssd_put_published: u64, + pub local_ssd_put_already_present: u64, + pub local_ssd_put_dropped: u64, + pub local_ssd_put_obsolete: u64, + pub local_ssd_put_failed: u64, pub local_reserve_slots_free: u64, pub local_reserve_slots_prepared: u64, pub local_reserve_slots_pending_visible: u64, @@ -956,6 +1147,20 @@ async fn handle_external_put_revoke( } } +async fn handle_ssd_stage_read( + view: &ClientKvApiView, + msg: &MsgPack, +) -> MsgPack { + MsgPack { + serialize_part: view + .client_kv_api() + .inner() + .execute_ssd_stage(&msg.serialize_part) + .await, + raw_bytes: Vec::new(), + } +} + async fn handle_external_delete_ack( view: &ClientKvApiView, msg: &MsgPack, @@ -1364,6 +1569,7 @@ pub struct ClientKvApiNewArg { pub test_spec_config: TestSpecConfig, /// Logical hot-tier capacity only. This does not resize the owner segment. pub owner_hot_cache_capacity_bytes: Option, + pub ssd_storage: Option, } pub struct ClientKvApi(ClientKvApiInner); @@ -1465,6 +1671,19 @@ struct OwnerRemotePutCounters { failed: AtomicU64, } +#[derive(Default)] +struct OwnerLocalSsdPutCounters { + active: AtomicU64, + leaders: AtomicU64, + followers: AtomicU64, + source_unavailable: AtomicU64, + published: AtomicU64, + already_present: AtomicU64, + dropped: AtomicU64, + obsolete: AtomicU64, + failed: AtomicU64, +} + #[derive(Default)] struct OwnerPlannedGetCounters { local_probe_batches: AtomicU64, @@ -1477,6 +1696,31 @@ struct OwnerPlannedGetCounters { follower_items: AtomicU64, } +#[derive(Default)] +struct OwnerSsdStageCounters { + ready_requests: AtomicU64, + ready_successes: AtomicU64, + ready_failures: AtomicU64, + ready_duration_us: AtomicU64, + execute_completions: AtomicU64, + terminal_published: AtomicU64, + terminal_cache_inserts: AtomicU64, + terminal_cache_duration_us: AtomicU64, + response_send_attempts: AtomicU64, + response_send_successes: AtomicU64, + response_send_failures: AtomicU64, + response_send_duration_us: AtomicU64, + source_ready_wait_requests: AtomicU64, + source_ready_wait_successes: AtomicU64, + source_ready_wait_failures: AtomicU64, + source_ready_wait_duration_us: AtomicU64, + target_pull_requests: AtomicU64, + target_pull_successes: AtomicU64, + target_pull_failures: AtomicU64, + target_pull_duration_us: AtomicU64, + done_detached: AtomicU64, +} + struct OwnerHotSelectionDebt { weight_bytes: u64, outstanding_bytes: Arc, @@ -1730,8 +1974,26 @@ impl OwnerHotRetryQueue { pub(crate) struct OwnerPreparedReclaim { item: crate::master_kv_router::msg_pack::OwnerReclaimItem, - cached_info: GetCachedInfo, - local_snapshot: Option, + source: OwnerPreparedReclaimSource, + ssd_prepare_lock: Arc>, + ssd_prepare_complete: bool, + ssd_backing: Option, +} + +pub(crate) enum OwnerPreparedReclaimSource { + /// An owner-indexed source detached from the local Moka while the reclaim fence is active. + Indexed { + cached_info: GetCachedInfo, + local_snapshot: Option, + }, + /// A master-owned allocation that has no owner-local key index. The master route owns the + /// physical allocation through Commit; the owner only reads it under the reclaim fence. + UnindexedAllocation { addr: u64, len: u64 }, +} + +pub(crate) struct OwnerPreparedSsdBacking { + len: u64, + _persist_guard: crate::kv_ssd_storage::KvSsdPersistGuard, } pub(crate) struct OwnerSourceEvictionSelection { @@ -1769,6 +2031,51 @@ pub(crate) enum OwnerRemotePutOutcome { Failed, } +/// Shared leader/follower terminal publication used by owner backing writes. +/// Target-specific requests and executors stay outside this type. +struct OwnerTargetPutFlight { + terminal: watch::Sender>, + completed: AtomicBool, +} + +impl OwnerTargetPutFlight { + fn new() -> Self { + let (terminal, _receiver) = watch::channel(None); + Self { + terminal, + completed: AtomicBool::new(false), + } + } + + fn terminal(&self) -> Option { + *self.terminal.borrow() + } + + fn complete(&self, terminal: T) -> bool { + if self + .completed + .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire) + .is_err() + { + return false; + } + self.terminal.send_replace(Some(terminal)); + true + } + + async fn wait(&self) -> Option { + let mut terminal = self.terminal.subscribe(); + loop { + if let Some(terminal) = *terminal.borrow_and_update() { + return Some(terminal); + } + if terminal.changed().await.is_err() { + return None; + } + } + } +} + #[derive(Clone, Debug)] pub(crate) struct OwnerRemotePutRequest { pub preferred_sub_cluster: Option, @@ -1784,8 +2091,7 @@ pub(crate) struct OwnerRemotePutSharedOp { pub key: String, pub put_id: crate::master_kv_router::put::PutIDForAKey, request: Mutex, - outcome: watch::Sender, - completed: AtomicBool, + flight: OwnerTargetPutFlight, } impl OwnerRemotePutSharedOp { @@ -1795,7 +2101,6 @@ impl OwnerRemotePutSharedOp { preferred_sub_cluster: Option, protect_source_on_remote_complete: bool, ) -> Arc { - let (outcome, _receiver) = watch::channel(OwnerRemotePutOutcome::InFlight); Arc::new(Self { key: key.to_string(), put_id, @@ -1803,8 +2108,7 @@ impl OwnerRemotePutSharedOp { preferred_sub_cluster, protect_source_on_remote_complete, }), - outcome, - completed: AtomicBool::new(false), + flight: OwnerTargetPutFlight::new(), }) } @@ -1825,33 +2129,21 @@ impl OwnerRemotePutSharedOp { } pub(crate) fn outcome(&self) -> OwnerRemotePutOutcome { - *self.outcome.borrow() + self.flight + .terminal() + .unwrap_or(OwnerRemotePutOutcome::InFlight) } fn complete(&self, outcome: OwnerRemotePutOutcome) -> bool { debug_assert_ne!(outcome, OwnerRemotePutOutcome::InFlight); - if self - .completed - .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire) - .is_err() - { - return false; - } - self.outcome.send_replace(outcome); - true + self.flight.complete(outcome) } pub(crate) async fn wait(&self) -> OwnerRemotePutOutcome { - let mut outcome = self.outcome.subscribe(); - loop { - let current = *outcome.borrow_and_update(); - if current != OwnerRemotePutOutcome::InFlight { - return current; - } - if outcome.changed().await.is_err() { - return OwnerRemotePutOutcome::Failed; - } - } + self.flight + .wait() + .await + .unwrap_or(OwnerRemotePutOutcome::Failed) } } @@ -1864,6 +2156,58 @@ pub(crate) enum OwnerRemotePutReservation { SourceUnavailable, } +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(crate) enum OwnerLocalSsdPutOutcome { + Published, + AlreadyPresent, + Dropped, + Obsolete, + Failed, +} + +/// One same-owner SSD write for an exact local generation. The common flight +/// owns only terminal publication; admission, copy, durability, and route +/// publication remain in the SSD executor. +pub(crate) struct OwnerLocalSsdPutSharedOp { + pub key: String, + pub put_id: crate::master_kv_router::put::PutIDForAKey, + flight: OwnerTargetPutFlight, +} + +impl OwnerLocalSsdPutSharedOp { + fn new(key: &str, put_id: crate::master_kv_router::put::PutIDForAKey) -> Arc { + Arc::new(Self { + key: key.to_string(), + put_id, + flight: OwnerTargetPutFlight::new(), + }) + } + + fn outcome(&self) -> Option { + self.flight.terminal() + } + + fn complete(&self, outcome: OwnerLocalSsdPutOutcome) -> bool { + self.flight.complete(outcome) + } + + pub(crate) async fn wait(&self) -> OwnerLocalSsdPutOutcome { + self.flight + .wait() + .await + .unwrap_or(OwnerLocalSsdPutOutcome::Failed) + } +} + +pub(crate) enum OwnerLocalSsdPutReservation { + Leader { + op: Arc, + memory_info: Arc, + }, + Follower(Arc), + SourceUnavailable, +} + impl ExternalPutKeySharedOp { fn new() -> Arc { let (outcome, _receiver) = watch::channel(ExternalPutKeyOutcome::InFlight); @@ -1916,6 +2260,9 @@ pub(crate) struct OwnerKeyControlState { /// `external_put`, this remains active after local publication until the /// remote Start/transfer/Done state machine reaches a terminal outcome. remote_put: Option>, + /// Exact-generation same-owner SSD write. This is independent from + /// `remote_put`, so both backing writes may run concurrently. + local_ssd_put: Option>, /// Owner-local pre-Prepare fence installed by the Moka source-eviction /// dispatcher. The matching committed index is moved into this record, /// so a new local Get cannot acquire the source between victim selection @@ -1942,6 +2289,7 @@ impl OwnerKeyControlState { && self.external_pending_puts == 0 && self.external_put.is_none() && self.remote_put.is_none() + && self.local_ssd_put.is_none() && self.source_eviction_selection.is_none() && self.reclaim.is_none() && self.external_get.is_none() @@ -1986,6 +2334,15 @@ impl OwnerKeyControlState { ); } } + + fn install_local_ssd_put_leader(&mut self, op: Arc) { + if let Some(displaced) = self.local_ssd_put.replace(op.clone()) { + assert_ne!( + displaced.put_id, op.put_id, + "a matching local SSD Put generation must join instead of being replaced" + ); + } + } } const OWNER_KEY_CONTROL_SHARDS: usize = 256; @@ -2421,6 +2778,7 @@ impl std::ops::Deref for ClientKvApiViewHolder { pub struct ClientKvApiInner { view: ClientKvApiViewHolder, test_spec_config: TestSpecConfig, + ssd_storage: Option>, metrics: OnceLock>, /// make sure each remote kv get run in order @@ -2460,7 +2818,9 @@ pub struct ClientKvApiInner { Arc>>, owner_hot_counters: Arc, owner_remote_put_counters: Arc, + owner_local_ssd_put_counters: Arc, planned_get_counters: OwnerPlannedGetCounters, + ssd_stage_counters: OwnerSsdStageCounters, owner_hot_retry_queue: Arc, owner_hot_eviction_tx: tokio::sync::ampsc::UnboundedSender, owner_hot_eviction_rx: @@ -2486,6 +2846,12 @@ pub struct ClientKvApiInner { planned_external_get_execute_locks: AMapLock<(String, i64, u64)>, completed_planned_external_get_executes: moka::future::Cache<(String, i64, u64), ExternalExecutePlannedGetResp>, + /// Exact `get_id` SSD source operations. RPC retransmits and concurrent + /// callers join one disk read plus one payload transfer. + ssd_stage_flights: DashMap>, + /// Short-lived terminal replay closes the active-map removal race and + /// prevents a lost response from re-reading or re-transferring the value. + completed_ssd_stages: moka::future::Cache, next_external_get_start_handle: AtomicU64, /// External holding identities are independent from upstream and resident holder ids. next_external_holding_id: AtomicU64, @@ -2523,6 +2889,7 @@ pub struct ClientKvApiInner { rpc_caller_put_append_done: RPCCaller, rpc_caller_batch_put_append_done: RPCCaller, rpc_caller_batch_evict_owner_source: RPCCaller, + rpc_caller_batch_publish_owner_ssd: RPCCaller, rpc_caller_reserve_local_grant: RPCCaller, rpc_caller_release_local_grant: RPCCaller, rpc_caller_delete: RPCCaller, @@ -2531,24 +2898,490 @@ pub struct ClientKvApiInner { rpc_caller_get_meta: RPCCaller, rpc_caller_allocate_client_lease: RPCCaller, rpc_caller_client_lease_keepalive: RPCCaller, + rpc_caller_ssd_stage_read: RPCCaller, + rpc_caller_ssd_stage_begin: RPCCaller, + rpc_caller_ssd_stage_done: RPCCaller, rpc_caller_external_put_commit: RPCCaller, rpc_caller_external_put_revoke: RPCCaller, rpc_caller_resolve_side_transfer_lane: RPCCaller, - /// Default lease id recorded for inspection/convenience, but NOT auto-applied. - /// Callers must explicitly pass `Some(lease_id)` to attach a put to a lease. - default_lease_id: parking_lot::RwLock>, - /// External put (remote target) pending context keyed by (key, put_time_ms, put_version). - /// 注意:put_id (time_ms,version) 在不同 key 上并不全局唯一,因此必须携带 key 作为索引的一部分,避免碰撞。 - /// 使用 moka::sync::SegmentedCache 并设置 30 分钟 TTL,避免异常路径未清理导致的泄漏;不设置容量上限,纯 TTL 控制。 - external_pending_puts: moka::sync::SegmentedCache<(String, u64, u32), ExternalPendingPutCtx>, - owner_local_publish_tx: tokio::sync::ampsc::Sender, - owner_local_publish_rx: Mutex>>, -} + /// Default lease id recorded for inspection/convenience, but NOT auto-applied. + /// Callers must explicitly pass `Some(lease_id)` to attach a put to a lease. + default_lease_id: parking_lot::RwLock>, + /// External put (remote target) pending context keyed by (key, put_time_ms, put_version). + /// 注意:put_id (time_ms,version) 在不同 key 上并不全局唯一,因此必须携带 key 作为索引的一部分,避免碰撞。 + /// 使用 moka::sync::SegmentedCache 并设置 30 分钟 TTL,避免异常路径未清理导致的泄漏;不设置容量上限,纯 TTL 控制。 + external_pending_puts: moka::sync::SegmentedCache<(String, u64, u32), ExternalPendingPutCtx>, + owner_local_publish_tx: tokio::sync::ampsc::Sender, + owner_local_publish_rx: Mutex>>, +} + +impl ClientKvApiInner { + fn view(&self) -> &ClientKvApiView { + &self.view + } + + pub(crate) async fn persist_local_kvs_to_ssd( + &self, + sources: &[KvSsdPersistSource], + ) -> KvResult>>> { + let Some(store) = self.ssd_storage.as_ref() else { + return Ok(sources.iter().map(|_| Ok(None)).collect()); + }; + let segment_guard = self.view.client_seg_pool().cpu_mem_read_guard().await?; + for source in sources { + if !segment_guard.contains_rw_or_ro(source.addr, source.len) { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "SSD persist source is outside the local segment: key={} put_id=({},{}) addr={:#x} len={}", + source.key, source.put_id.0, source.put_id.1, source.addr, source.len + ), + })); + } + } + let results = store.persist_batch_from_addrs(sources).await; + drop(segment_guard); + Ok(results) + } + + pub(crate) async fn copy_local_kvs_for_ssd( + &self, + sources: &[KvSsdPersistSource], + ) -> KvResult>> { + if self.ssd_storage.is_none() { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: "local SSD storage is disabled".to_string(), + })); + } + let segment_guard = self.view.client_seg_pool().cpu_mem_read_guard().await?; + for source in sources { + if !segment_guard.contains_rw_or_ro(source.addr, source.len) { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "SSD persist source is outside the local segment: key={} put_id=({},{}) addr={:#x} len={}", + source.key, source.put_id.0, source.put_id.1, source.addr, source.len + ), + })); + } + } + let copies = KvSsdStorage::copy_batch_from_addrs(sources); + drop(segment_guard); + Ok(copies) + } + + pub(crate) async fn persist_copied_local_kvs_to_ssd( + &self, + permit: KvSsdPersistBatchPermit, + copies: Vec>, + ) -> KvResult>>> { + let Some(store) = self.ssd_storage.as_ref() else { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: "local SSD storage is disabled".to_string(), + })); + }; + Ok(store + .persist_batch_from_copies_with_permit(permit, copies) + .await) + } + + pub(crate) fn try_acquire_local_ssd_persist_batch( + &self, + item_count: usize, + ) -> KvResult> { + let Some(store) = self.ssd_storage.as_ref() else { + return Ok(None); + }; + store.try_acquire_persist_batch(item_count) + } + + async fn discard_local_ssd_replica( + &self, + key: &str, + put_id: crate::master_kv_router::put::PutIDForAKey, + ) -> bool { + let Some(store) = self.ssd_storage.as_ref() else { + return false; + }; + store.remove_exact(key, put_id).await + } + + async fn begin_ssd_stage(&self, get_id: u64) -> KvResult { + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let response = self + .rpc_caller_ssd_stage_begin + .call( + self.view.p2p_module(), + master_node_id.into(), + MsgPack { + serialize_part: SsdStageBeginReq { get_id }, + raw_bytes: Vec::new(), + }, + Some(SSD_STAGE_RPC_TIMEOUT), + 2, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + response.serialize_part.error_code, + response.serialize_part.error_json, + )?; + Ok(response.serialize_part.started) + } + + async fn finish_ssd_stage_once(&self, get_id: u64, drop_ssd_source: bool) -> KvResult<()> { + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let response = self + .rpc_caller_ssd_stage_done + .call( + self.view.p2p_module(), + master_node_id.into(), + MsgPack { + serialize_part: SsdStageDoneReq { + get_id, + drop_ssd_source, + }, + raw_bytes: Vec::new(), + }, + Some(SSD_STAGE_RPC_TIMEOUT), + 2, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + response.serialize_part.error_code, + response.serialize_part.error_json, + ) + } + + async fn finish_ssd_stage_until_acked(&self, get_id: u64, drop_ssd_source: bool) { + let mut attempt = 0_u64; + let mut backoff = SSD_STAGE_DONE_RETRY_INITIAL_BACKOFF; + loop { + attempt = attempt.saturating_add(1); + match self.finish_ssd_stage_once(get_id, drop_ssd_source).await { + Ok(()) => return, + Err(err) => { + if attempt == 1 || attempt.is_power_of_two() { + tracing::warn!( + get_id, + drop_ssd_source, + attempt, + retry_delay_ms = backoff.as_millis(), + error = %err, + "SSD StageDone failed; retaining the source flight and retrying" + ); + } + } + } + tokio::time::sleep(backoff).await; + backoff = backoff + .saturating_mul(2) + .min(SSD_STAGE_DONE_RETRY_MAX_BACKOFF); + } + } + + fn finish_ssd_stage_detached(&self, get_id: u64) { + self.ssd_stage_counters + .done_detached + .fetch_add(1, Ordering::Relaxed); + let spawn_view = self.view.clone_view(); + let task_view = spawn_view.clone(); + spawn_view.spawn("ssd_stage_done_retry", async move { + task_view + .client_kv_api() + .inner() + .finish_ssd_stage_until_acked(get_id, false) + .await; + }); + } + + async fn run_ssd_stage_once(&self, req: &SsdStageReadReq) -> SsdStageReadResp { + self.ssd_stage_counters + .ready_requests + .fetch_add(1, Ordering::Relaxed); + let ready_started_at = Instant::now(); + match self.begin_ssd_stage(req.get_id).await { + Ok(true) => {} + Ok(false) => { + let response = ssd_stage_error_response(KvError::Api(ApiError::InvalidArgument { + detail: format!("SSD stage is not startable: get_id={}", req.get_id), + })); + self.ssd_stage_counters + .ready_failures + .fetch_add(1, Ordering::Relaxed); + self.ssd_stage_counters.ready_duration_us.fetch_add( + u64::try_from(ready_started_at.elapsed().as_micros()).unwrap_or(u64::MAX), + Ordering::Relaxed, + ); + return response; + } + Err(err) => { + let response = ssd_stage_error_response(err); + self.ssd_stage_counters + .ready_failures + .fetch_add(1, Ordering::Relaxed); + self.ssd_stage_counters.ready_duration_us.fetch_add( + u64::try_from(ready_started_at.elapsed().as_micros()).unwrap_or(u64::MAX), + Ordering::Relaxed, + ); + return response; + } + } + + let load_result = async { + let Some(store) = self.ssd_storage.as_ref() else { + return Err(KvError::Api(ApiError::KeyNotFound { + key: req.key.clone(), + })); + }; + let segment_guard = self.view.client_seg_pool().cpu_mem_read_guard().await?; + if !segment_guard.contains_rw(req.stage_addr, req.stage_capacity) { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "SSD stage is outside the local writable segment: get_id={} addr={:#x} capacity={}", + req.get_id, req.stage_addr, req.stage_capacity + ), + })); + } + store + .load_into_addr( + &req.key, + req.put_id, + req.stage_addr, + req.len, + req.stage_capacity, + ) + .await?; + drop(segment_guard); + Ok(()) + } + .await; + + let response = match load_result { + Ok(()) => SsdStageReadResp { + error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, + error_json: String::new(), + }, + Err(load_err) => { + let stale_ssd_source = + matches!(&load_err, KvError::Api(ApiError::KeyNotFound { .. })); + // A failed load never becomes pull-ready. The source owner is + // therefore the only side that can safely close the stage. A + // true miss also removes the exact stale SSD route. + self.finish_ssd_stage_until_acked(req.get_id, stale_ssd_source) + .await; + ssd_stage_error_response(load_err) + } + }; + self.ssd_stage_counters.ready_duration_us.fetch_add( + u64::try_from(ready_started_at.elapsed().as_micros()).unwrap_or(u64::MAX), + Ordering::Relaxed, + ); + if response.error_code == crate::rpcresp_kvresult_convert::msg_and_error::OK { + self.ssd_stage_counters + .ready_successes + .fetch_add(1, Ordering::Relaxed); + } else { + self.ssd_stage_counters + .ready_failures + .fetch_add(1, Ordering::Relaxed); + } + response + } + + async fn execute_ssd_stage(&self, req: &SsdStageReadReq) -> SsdStageReadResp { + if let Some(completed) = self.completed_ssd_stages.get(&req.get_id).await { + return if completed.request == *req { + completed.response + } else { + ssd_stage_request_mismatch_response(&completed.request, req) + }; + } + + let (op, is_leader) = match self.ssd_stage_flights.entry(req.get_id) { + DashMapEntry::Occupied(entry) => (entry.get().clone(), false), + DashMapEntry::Vacant(entry) => { + let op = SsdStageSharedOp::new(req.clone()); + entry.insert(op.clone()); + (op, true) + } + }; + if op.request != *req { + return ssd_stage_request_mismatch_response(&op.request, req); + } + + if is_leader { + let spawn_view = self.view.clone_view(); + let task_view = spawn_view.clone(); + let task_op = op.clone(); + spawn_view.spawn("ssd_stage_singleflight", async move { + let inner = task_view.client_kv_api().inner(); + let response = inner.run_ssd_stage_once(&task_op.request).await; + inner + .ssd_stage_counters + .execute_completions + .fetch_add(1, Ordering::Relaxed); + assert!( + task_op.complete(response.clone()), + "one SSD stage flight must publish exactly one terminal result" + ); + inner + .ssd_stage_counters + .terminal_published + .fetch_add(1, Ordering::Relaxed); + + // Wake the foreground RPC before maintaining the replay cache. + // The completed flight remains indexed until the cache insert + // finishes, so retransmits cannot start a second disk read. + let cache_started_at = Instant::now(); + inner + .completed_ssd_stages + .insert( + task_op.request.get_id, + CompletedSsdStage { + request: task_op.request.clone(), + response: response.clone(), + }, + ) + .await; + inner + .ssd_stage_counters + .terminal_cache_duration_us + .fetch_add( + u64::try_from(cache_started_at.elapsed().as_micros()).unwrap_or(u64::MAX), + Ordering::Relaxed, + ); + inner + .ssd_stage_counters + .terminal_cache_inserts + .fetch_add(1, Ordering::Relaxed); + inner + .ssd_stage_flights + .remove_if(&task_op.request.get_id, |_, current| { + Arc::ptr_eq(current, &task_op) + }); + }); + } + op.wait().await + } + + pub(crate) async fn stage_kv_from_ssd_source( + &self, + source_node_id: &NodeIDString, + key: &str, + put_id: crate::master_kv_router::put::PutIDForAKey, + get_id: u64, + stage_addr: u64, + stage_capacity: u64, + target_addr: u64, + len: u64, + ) -> KvResult<()> { + let req = SsdStageReadReq { + key: key.to_string(), + put_id, + get_id, + stage_addr, + stage_capacity, + len, + }; + let self_node_id = self.view.cluster_manager().get_self_info().id.clone(); + self.ssd_stage_counters + .source_ready_wait_requests + .fetch_add(1, Ordering::Relaxed); + let ready_wait_started_at = Instant::now(); + let response_result: KvResult = if source_node_id == &self_node_id { + Ok(self.execute_ssd_stage(&req).await) + } else { + self.rpc_caller_ssd_stage_read + .call_with_transport_policy( + self.view.p2p_module(), + source_node_id.clone().into(), + MsgPack { + serialize_part: req, + raw_bytes: Vec::new(), + }, + Some(SSD_STAGE_RPC_TIMEOUT), + RpcTransportPolicy::ForceTransport, + 1, + ) + .await + .map(|response| response.serialize_part) + .map_err(KvError::from) + }; + self.ssd_stage_counters + .source_ready_wait_duration_us + .fetch_add( + u64::try_from(ready_wait_started_at.elapsed().as_micros()).unwrap_or(u64::MAX), + Ordering::Relaxed, + ); + let ready_result = response_result.and_then(|response| { + crate::rpcresp_kvresult_convert::try_from_code(response.error_code, response.error_json) + }); + if ready_result.is_ok() { + self.ssd_stage_counters + .source_ready_wait_successes + .fetch_add(1, Ordering::Relaxed); + } else { + self.ssd_stage_counters + .source_ready_wait_failures + .fetch_add(1, Ordering::Relaxed); + } + ready_result?; + + self.ssd_stage_counters + .target_pull_requests + .fetch_add(1, Ordering::Relaxed); + let pull_started_at = Instant::now(); + let peer_id = (source_node_id != &self_node_id).then(|| source_node_id.clone()); + let transfer_result = self + .view + .client_transfer_engine() + .transfer_data_no_copy(peer_id, true, stage_addr, target_addr, len, None) + .await + .map(|_| ()) + .map_err(|err| { + KvError::Api(ApiError::Transfer { + from_addr: stage_addr, + to_addr: target_addr, + len, + error: err.to_string(), + }) + }); + self.ssd_stage_counters.target_pull_duration_us.fetch_add( + u64::try_from(pull_started_at.elapsed().as_micros()).unwrap_or(u64::MAX), + Ordering::Relaxed, + ); + if transfer_result.is_ok() { + self.ssd_stage_counters + .target_pull_successes + .fetch_add(1, Ordering::Relaxed); + } else { + self.ssd_stage_counters + .target_pull_failures + .fetch_add(1, Ordering::Relaxed); + } -impl ClientKvApiInner { - fn view(&self) -> &ClientKvApiView { - &self.view + // Payload completion is the ownership hand-off point: the target no + // longer reads the source stage, so master may release it. Do not put + // this control-plane ACK on the foreground Get latency path. + self.finish_ssd_stage_detached(get_id); + transfer_result + } + + pub(crate) fn kv_ssd_storage_usage_snapshot( + &self, + ) -> Option { + self.ssd_storage + .as_ref() + .map(|store| store.usage_snapshot()) } pub(crate) fn track_external_get_flight(&self, op: &Arc) { @@ -2690,6 +3523,7 @@ impl ClientKvApiInner { state.local_puts != 0 || state.external_pending_puts != 0 || state.remote_put.is_some() + || state.local_ssd_put.is_some() || state.external_get.is_some() || state.local_access_fenced() }); @@ -3207,6 +4041,140 @@ impl ClientKvApiInner { true } + pub(crate) fn begin_owner_local_ssd_put( + &self, + key: &str, + put_id: crate::master_kv_router::put::PutIDForAKey, + selected_victim: Option<&crate::master_kv_router::msg_pack::OwnerSourceEvictionVictim>, + ) -> OwnerLocalSsdPutReservation { + if self.ssd_storage.is_none() { + return OwnerLocalSsdPutReservation::SourceUnavailable; + } + let mut controls = self.owner_key_control.lock_key(key); + + if let Some(existing) = controls + .get(key) + .and_then(|state| state.local_ssd_put.clone()) + { + if existing.put_id == put_id && existing.outcome().is_none() { + self.owner_local_ssd_put_counters + .followers + .fetch_add(1, Ordering::Relaxed); + return OwnerLocalSsdPutReservation::Follower(existing); + } + if existing.outcome().is_some() { + let state = controls + .get_mut(key) + .expect("terminal local SSD Put control state disappeared"); + if state + .local_ssd_put + .as_ref() + .is_some_and(|current| Arc::ptr_eq(current, &existing)) + { + state.local_ssd_put = None; + } + } + } + + let memory_info = if let Some(victim) = selected_victim { + let selected = controls + .get(key) + .and_then(|state| state.source_eviction_selection.as_ref()) + .filter(|selection| selection.put_id == put_id) + .map(|selection| selection.cached_info.mem_holder.clone()); + selected.filter(|source| { + source.local_reserve_resident_slot_ref().is_some_and( + |(slot_size, grant_id, slot_index)| { + matches!( + &victim.backing, + crate::master_kv_router::msg_pack::OwnerReclaimBacking::CommittedSlot { + grant_id: expected_grant_id, + slot_index: expected_slot_index, + slot_size: expected_slot_size, + } if *expected_grant_id == grant_id + && *expected_slot_index == slot_index + && *expected_slot_size == slot_size + ) + }, + ) + }) + } else { + if controls + .get(key) + .is_some_and(|state| state.local_access_fenced()) + { + None + } else { + self.get_cached_info.get(key).and_then(|info| { + ((info.put_time_ms, info.put_version) == put_id) + .then(|| info.mem_holder.clone()) + }) + } + }; + let Some(memory_info) = memory_info else { + self.owner_local_ssd_put_counters + .source_unavailable + .fetch_add(1, Ordering::Relaxed); + return OwnerLocalSsdPutReservation::SourceUnavailable; + }; + + let op = OwnerLocalSsdPutSharedOp::new(key, put_id); + controls + .entry(key.to_string()) + .or_default() + .install_local_ssd_put_leader(op.clone()); + self.owner_local_ssd_put_counters + .active + .fetch_add(1, Ordering::Relaxed); + self.owner_local_ssd_put_counters + .leaders + .fetch_add(1, Ordering::Relaxed); + OwnerLocalSsdPutReservation::Leader { op, memory_info } + } + + pub(crate) fn finish_owner_local_ssd_put( + &self, + op: &Arc, + outcome: OwnerLocalSsdPutOutcome, + ) -> bool { + if !op.complete(outcome) { + return false; + } + + let mut controls = self.owner_key_control.lock_key(&op.key); + let remove_control = if let Some(state) = controls.get_mut(&op.key) { + if state + .local_ssd_put + .as_ref() + .is_some_and(|current| Arc::ptr_eq(current, op)) + { + state.local_ssd_put = None; + } + state.is_idle() + } else { + false + }; + if remove_control { + controls.remove(&op.key); + } + drop(controls); + + self.owner_local_ssd_put_counters + .active + .fetch_sub(1, Ordering::Relaxed); + let terminal_counter = match outcome { + OwnerLocalSsdPutOutcome::Published => &self.owner_local_ssd_put_counters.published, + OwnerLocalSsdPutOutcome::AlreadyPresent => { + &self.owner_local_ssd_put_counters.already_present + } + OwnerLocalSsdPutOutcome::Dropped => &self.owner_local_ssd_put_counters.dropped, + OwnerLocalSsdPutOutcome::Obsolete => &self.owner_local_ssd_put_counters.obsolete, + OwnerLocalSsdPutOutcome::Failed => &self.owner_local_ssd_put_counters.failed, + }; + terminal_counter.fetch_add(1, Ordering::Relaxed); + true + } + pub(crate) fn record_owner_remote_put_transfer(&self) { self.owner_remote_put_counters .transfers @@ -3691,7 +4659,11 @@ pub struct ExternalPendingPutCtx { pub target_base_addr: u64, pub target_offset: u64, pub len: u64, + /// Original content-selection signal from the caller/adapter. pub make_replica_task: bool, + /// A remote memory target was pre-reserved, or this local-first path may + /// perform normal append-time remote admission. + pub remote_replica_admitted: bool, pub preferred_sub_cluster: Option, pub local_reserve_slot: Option, pub local_reserve_slot_size: Option, @@ -4325,18 +5297,22 @@ mod owner_reclaim_slot_tests { OwnerHotRetryQueue, OwnerHotSelectionDebt, OwnerHotSelectionFenceOutcome, OwnerKeyControlState, OwnerKeyControlTable, OwnerLocalReserveGrantState, OwnerLocalReserveSlotLease, OwnerLocalReserveSlotRef, OwnerLocalReserveSlotState, - OwnerReclaimRecord, OwnerRemotePutOutcome, OwnerRemotePutReservation, - OwnerRemotePutSharedOp, acquire_external_pending_put_fence_for_key, - allocate_external_holding_id, build_owner_hot_cache, clone_if_owner_hot_entry_matches, + OwnerLocalSsdPutOutcome, OwnerLocalSsdPutSharedOp, OwnerReclaimRecord, + OwnerRemotePutOutcome, OwnerRemotePutReservation, OwnerRemotePutSharedOp, + acquire_external_pending_put_fence_for_key, allocate_external_holding_id, + build_owner_hot_cache, clone_if_owner_hot_entry_matches, owner_hot_source_has_active_holders, pin_current_owner_hot_source_from_index, }; use crate::config::TestSpecConfig; + use crate::kv_ssd_storage::{KvSsdStorageInit, KvSsdStorageRootLimit, MIN_CAPACITY_BYTES}; use crate::master_kv_router::msg_pack::{ BatchOwnerReclaimReq, OwnerReclaimBacking, OwnerReclaimItem, OwnerReclaimItemState, - OwnerReclaimPhase, OwnerReclaimReason, OwnerSourceEvictionVictim, + OwnerReclaimPhase, OwnerReclaimReason, OwnerSourceEvictionVictim, OwnerSourceSsdPolicy, }; use crate::p2p::msg_pack::MsgPack; use parking_lot::Mutex; + use std::fs; + use std::path::PathBuf; use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::{Arc, Weak}; use std::time::{Duration, Instant}; @@ -4392,6 +5368,7 @@ mod owner_reclaim_slot_tests { external_pending_puts: 1, external_put: None, remote_put: None, + local_ssd_put: None, source_eviction_selection: None, reclaim: None, external_get: None, @@ -4424,6 +5401,7 @@ mod owner_reclaim_slot_tests { external_pending_puts: 1, external_put: Some(op.clone()), remote_put: None, + local_ssd_put: None, source_eviction_selection: None, reclaim: None, external_get: None, @@ -4463,6 +5441,7 @@ mod owner_reclaim_slot_tests { external_pending_puts: 1, external_put: Some(op.clone()), remote_put: None, + local_ssd_put: None, source_eviction_selection: None, reclaim: None, external_get: None, @@ -4497,6 +5476,7 @@ mod owner_reclaim_slot_tests { let api = ClientKvApi::construct(ClientKvApiNewArg { test_spec_config: TestSpecConfig::default(), owner_hot_cache_capacity_bytes: None, + ssd_storage: None, }) .await .expect("construct test ClientKvApi"); @@ -4588,6 +5568,7 @@ mod owner_reclaim_slot_tests { let api = ClientKvApi::construct(ClientKvApiNewArg { test_spec_config: TestSpecConfig::default(), owner_hot_cache_capacity_bytes: None, + ssd_storage: None, }) .await .expect("construct test ClientKvApi"); @@ -4666,6 +5647,136 @@ mod owner_reclaim_slot_tests { ); } + #[limit_thirdparty::tokio::test] + async fn remote_and_local_ssd_flights_publish_independent_terminals() { + let key = "parallel-backing-flights"; + let put_id = (82, 4); + let api = ClientKvApi::construct(ClientKvApiNewArg { + test_spec_config: TestSpecConfig::default(), + owner_hot_cache_capacity_bytes: None, + ssd_storage: None, + }) + .await + .expect("construct test ClientKvApi"); + let remote = OwnerRemotePutSharedOp::new(key, put_id, None, false); + let local_ssd = OwnerLocalSsdPutSharedOp::new(key, put_id); + api.inner().owner_key_control.lock_key(key).insert( + key.to_string(), + OwnerKeyControlState { + remote_put: Some(remote.clone()), + local_ssd_put: Some(local_ssd.clone()), + ..Default::default() + }, + ); + api.inner() + .owner_remote_put_counters + .active + .store(1, Ordering::Relaxed); + api.inner() + .owner_local_ssd_put_counters + .active + .store(1, Ordering::Relaxed); + + assert!( + api.inner() + .finish_owner_remote_put(&remote, OwnerRemotePutOutcome::Published) + ); + { + let controls = api.inner().owner_key_control.lock_key(key); + let state = controls.get(key).expect("SSD flight must remain installed"); + assert!(state.remote_put.is_none()); + assert!( + state + .local_ssd_put + .as_ref() + .is_some_and(|current| Arc::ptr_eq(current, &local_ssd)) + ); + } + assert_eq!( + local_ssd.outcome(), + None, + "remote completion must not publish the SSD terminal" + ); + assert!( + api.inner() + .finish_owner_local_ssd_put(&local_ssd, OwnerLocalSsdPutOutcome::Published) + ); + assert_eq!(local_ssd.wait().await, OwnerLocalSsdPutOutcome::Published); + assert!( + api.inner() + .owner_key_control + .lock_key(key) + .get(key) + .is_none() + ); + } + + #[limit_thirdparty::tokio::test] + async fn early_ssd_byte_rejection_does_not_install_generation_flight() { + let target = std::env::var_os("CARGO_TARGET_DIR") + .map(PathBuf::from) + .unwrap_or_else(|| PathBuf::from("/mnt/nvme0/mjq_build/push_sglang_fluxon_target")); + let root = target.join("kv_ssd_tests").join(format!( + "early-pre-admission-{}-{}", + std::process::id(), + uuid::Uuid::new_v4() + )); + let api = ClientKvApi::construct(ClientKvApiNewArg { + test_spec_config: TestSpecConfig::default(), + owner_hot_cache_capacity_bytes: None, + ssd_storage: Some(KvSsdStorageInit { + roots: vec![KvSsdStorageRootLimit { + root_dir: root.clone(), + limit_bytes: MIN_CAPACITY_BYTES, + }], + write_rate_limit_bytes_per_sec: Some(1), + write_burst_bytes: Some(4), + }), + }) + .await + .expect("construct SSD-enabled test ClientKvApi"); + let key = "early-pre-admission-drop"; + + api.inner() + .start_early_owner_local_ssd_puts(vec![(key.to_string(), (83, 1), 8)]); + + let usage = api + .inner() + .ssd_storage + .as_ref() + .expect("SSD store") + .usage_snapshot(); + assert_eq!(usage.write_candidate_items, 1); + assert_eq!(usage.write_admitted_items, 0); + assert_eq!(usage.write_dropped_items, 1); + assert_eq!( + api.inner() + .owner_local_ssd_put_counters + .leaders + .load(Ordering::Relaxed), + 0, + "a byte-rejected early candidate must never enter singleflight" + ); + assert!( + api.inner() + .owner_key_control + .lock_key(key) + .get(key) + .is_none(), + "a byte-rejected early candidate must not create per-key state" + ); + + api.inner() + .ssd_storage + .as_ref() + .expect("SSD store") + .close() + .await + .expect("close SSD store"); + drop(api); + fs::remove_dir_all(root).expect("remove SSD test root"); + } + #[test] fn failed_local_slot_release_keeps_key_fence_closed() { let controls = controls_with_state( @@ -4675,6 +5786,7 @@ mod owner_reclaim_slot_tests { external_pending_puts: 1, external_put: None, remote_put: None, + local_ssd_put: None, source_eviction_selection: None, reclaim: None, external_get: None, @@ -4707,6 +5819,7 @@ mod owner_reclaim_slot_tests { external_pending_puts: 1, external_put: None, remote_put: None, + local_ssd_put: None, source_eviction_selection: None, reclaim: None, external_get: None, @@ -4760,6 +5873,7 @@ mod owner_reclaim_slot_tests { target_offset: 0, len: 1, make_replica_task: false, + remote_replica_admitted: false, preferred_sub_cluster: None, local_reserve_slot: None, local_reserve_slot_size: None, @@ -5125,6 +6239,8 @@ mod owner_reclaim_slot_tests { key: key.to_string(), put_id: (identity.put_time_ms, identity.put_version), backing: OwnerReclaimBacking::Allocation, + ssd_backing_len: None, + ssd_policy: OwnerSourceSsdPolicy::Drop, }, 101, ) @@ -5370,6 +6486,7 @@ mod owner_reclaim_slot_tests { external_pending_puts: 0, external_put: None, remote_put: None, + local_ssd_put: None, source_eviction_selection: None, reclaim: Some(OwnerReclaimRecord::Committed(OwnerReclaimItem { key: "fenced".to_string(), @@ -5687,6 +6804,7 @@ impl ClientKvApiInner { } pub fn runtime_observe_snapshot(&self) -> OwnerRuntimeObserveSnapshot { + let ssd = self.kv_ssd_storage_usage_snapshot().unwrap_or_default(); let mut external_get_holding_bytes = 0u64; for entry in self.external_get_holding.inner().iter() { external_get_holding_bytes = @@ -5766,6 +6884,123 @@ impl ClientKvApiInner { (free, prepared, pending_visible, committed) }; OwnerRuntimeObserveSnapshot { + ssd_capacity_bytes: ssd.capacity_bytes, + ssd_used_bytes: ssd.used_bytes, + ssd_persist_requests: ssd.persist_requests, + ssd_persist_successes: ssd.persist_successes, + ssd_persist_failures: ssd.persist_failures, + ssd_persist_bytes: ssd.persist_bytes, + ssd_persist_duration_us: ssd.persist_duration_us, + ssd_persist_batch_requests: ssd.persist_batch_requests, + ssd_persist_batch_items: ssd.persist_batch_items, + ssd_persist_flush_batches: ssd.persist_flush_batches, + ssd_persist_busy_batches: ssd.persist_busy_batches, + ssd_persist_admission_skips: ssd.persist_admission_skips, + ssd_persist_batch_duration_us: ssd.persist_batch_duration_us, + ssd_write_candidate_items: ssd.write_candidate_items, + ssd_write_candidate_bytes: ssd.write_candidate_bytes, + ssd_write_admitted_items: ssd.write_admitted_items, + ssd_write_admitted_bytes: ssd.write_admitted_bytes, + ssd_write_dropped_items: ssd.write_dropped_items, + ssd_write_dropped_bytes: ssd.write_dropped_bytes, + ssd_write_refunded_items: ssd.write_refunded_items, + ssd_write_refunded_bytes: ssd.write_refunded_bytes, + ssd_load_requests: ssd.load_requests, + ssd_load_successes: ssd.load_successes, + ssd_load_misses: ssd.load_misses, + ssd_load_failures: ssd.load_failures, + ssd_load_bytes: ssd.load_bytes, + ssd_load_duration_us: ssd.load_duration_us, + ssd_memory_hits: ssd.memory_hits, + ssd_disk_hits: ssd.disk_hits, + ssd_outer_hits: ssd.outer_hits, + ssd_removals: ssd.removals, + ssd_stage_flights: self.ssd_stage_flights.len() as u64, + ssd_stage_terminals: self.completed_ssd_stages.entry_count(), + ssd_stage_ready_requests: self + .ssd_stage_counters + .ready_requests + .load(Ordering::Relaxed), + ssd_stage_ready_successes: self + .ssd_stage_counters + .ready_successes + .load(Ordering::Relaxed), + ssd_stage_ready_failures: self + .ssd_stage_counters + .ready_failures + .load(Ordering::Relaxed), + ssd_stage_ready_duration_us: self + .ssd_stage_counters + .ready_duration_us + .load(Ordering::Relaxed), + ssd_stage_execute_completions: self + .ssd_stage_counters + .execute_completions + .load(Ordering::Relaxed), + ssd_stage_terminal_published: self + .ssd_stage_counters + .terminal_published + .load(Ordering::Relaxed), + ssd_stage_terminal_cache_inserts: self + .ssd_stage_counters + .terminal_cache_inserts + .load(Ordering::Relaxed), + ssd_stage_terminal_cache_duration_us: self + .ssd_stage_counters + .terminal_cache_duration_us + .load(Ordering::Relaxed), + ssd_stage_response_send_attempts: self + .ssd_stage_counters + .response_send_attempts + .load(Ordering::Relaxed), + ssd_stage_response_send_successes: self + .ssd_stage_counters + .response_send_successes + .load(Ordering::Relaxed), + ssd_stage_response_send_failures: self + .ssd_stage_counters + .response_send_failures + .load(Ordering::Relaxed), + ssd_stage_response_send_duration_us: self + .ssd_stage_counters + .response_send_duration_us + .load(Ordering::Relaxed), + ssd_source_ready_wait_requests: self + .ssd_stage_counters + .source_ready_wait_requests + .load(Ordering::Relaxed), + ssd_source_ready_wait_successes: self + .ssd_stage_counters + .source_ready_wait_successes + .load(Ordering::Relaxed), + ssd_source_ready_wait_failures: self + .ssd_stage_counters + .source_ready_wait_failures + .load(Ordering::Relaxed), + ssd_source_ready_wait_duration_us: self + .ssd_stage_counters + .source_ready_wait_duration_us + .load(Ordering::Relaxed), + ssd_target_pull_requests: self + .ssd_stage_counters + .target_pull_requests + .load(Ordering::Relaxed), + ssd_target_pull_successes: self + .ssd_stage_counters + .target_pull_successes + .load(Ordering::Relaxed), + ssd_target_pull_failures: self + .ssd_stage_counters + .target_pull_failures + .load(Ordering::Relaxed), + ssd_target_pull_duration_us: self + .ssd_stage_counters + .target_pull_duration_us + .load(Ordering::Relaxed), + ssd_stage_done_detached: self + .ssd_stage_counters + .done_detached + .load(Ordering::Relaxed), external_get_holding_entries: self.external_get_holding.total() as u64, external_get_holding_bytes, external_get_start_handles: self.external_get_start_registry.len() as u64, @@ -5853,6 +7088,42 @@ impl ClientKvApiInner { .owner_remote_put_counters .failed .load(Ordering::Relaxed), + local_ssd_put_flights_active: self + .owner_local_ssd_put_counters + .active + .load(Ordering::Relaxed), + local_ssd_put_flight_leaders: self + .owner_local_ssd_put_counters + .leaders + .load(Ordering::Relaxed), + local_ssd_put_flight_followers: self + .owner_local_ssd_put_counters + .followers + .load(Ordering::Relaxed), + local_ssd_put_source_unavailable: self + .owner_local_ssd_put_counters + .source_unavailable + .load(Ordering::Relaxed), + local_ssd_put_published: self + .owner_local_ssd_put_counters + .published + .load(Ordering::Relaxed), + local_ssd_put_already_present: self + .owner_local_ssd_put_counters + .already_present + .load(Ordering::Relaxed), + local_ssd_put_dropped: self + .owner_local_ssd_put_counters + .dropped + .load(Ordering::Relaxed), + local_ssd_put_obsolete: self + .owner_local_ssd_put_counters + .obsolete + .load(Ordering::Relaxed), + local_ssd_put_failed: self + .owner_local_ssd_put_counters + .failed + .load(Ordering::Relaxed), local_reserve_slots_free, local_reserve_slots_prepared, local_reserve_slots_pending_visible, @@ -6436,6 +7707,44 @@ impl ClientKvApi { _ = shutdown_waiter.wait() => break, _ = interval.tick() => { let snapshot = view_task.client_kv_api().inner().runtime_observe_snapshot(); + if snapshot.ssd_capacity_bytes > 0 { + tracing::info!( + capacity_bytes = snapshot.ssd_capacity_bytes, + used_bytes = snapshot.ssd_used_bytes, + persist_requests = snapshot.ssd_persist_requests, + persist_successes = snapshot.ssd_persist_successes, + persist_failures = snapshot.ssd_persist_failures, + persist_bytes = snapshot.ssd_persist_bytes, + persist_duration_us = snapshot.ssd_persist_duration_us, + persist_batch_requests = snapshot.ssd_persist_batch_requests, + persist_batch_items = snapshot.ssd_persist_batch_items, + persist_flush_batches = snapshot.ssd_persist_flush_batches, + persist_busy_batches = snapshot.ssd_persist_busy_batches, + persist_admission_skips = snapshot.ssd_persist_admission_skips, + persist_batch_duration_us = snapshot.ssd_persist_batch_duration_us, + write_candidate_items = snapshot.ssd_write_candidate_items, + write_candidate_bytes = snapshot.ssd_write_candidate_bytes, + write_admitted_items = snapshot.ssd_write_admitted_items, + write_admitted_bytes = snapshot.ssd_write_admitted_bytes, + write_dropped_items = snapshot.ssd_write_dropped_items, + write_dropped_bytes = snapshot.ssd_write_dropped_bytes, + write_refunded_items = snapshot.ssd_write_refunded_items, + write_refunded_bytes = snapshot.ssd_write_refunded_bytes, + load_requests = snapshot.ssd_load_requests, + load_successes = snapshot.ssd_load_successes, + load_misses = snapshot.ssd_load_misses, + load_failures = snapshot.ssd_load_failures, + load_bytes = snapshot.ssd_load_bytes, + load_duration_us = snapshot.ssd_load_duration_us, + memory_hits = snapshot.ssd_memory_hits, + disk_hits = snapshot.ssd_disk_hits, + outer_hits = snapshot.ssd_outer_hits, + removals = snapshot.ssd_removals, + active_stage_flights = snapshot.ssd_stage_flights, + retained_stage_terminals = snapshot.ssd_stage_terminals, + "owner KV SSD storage snapshot" + ); + } let metrics = view_task.metric_reporter().metrics(); metrics.set_kv_holding_entries( "owner_external_get_holding", @@ -6464,6 +7773,27 @@ impl ClientKvApi { planned_cpu_local_items = snapshot.planned_cpu_get_local_items, planned_cpu_leader_items = snapshot.planned_cpu_get_leader_items, planned_cpu_follower_items = snapshot.planned_cpu_get_follower_items, + ssd_stage_ready_requests = snapshot.ssd_stage_ready_requests, + ssd_stage_ready_successes = snapshot.ssd_stage_ready_successes, + ssd_stage_ready_failures = snapshot.ssd_stage_ready_failures, + ssd_stage_ready_duration_us = snapshot.ssd_stage_ready_duration_us, + ssd_stage_execute_completions = snapshot.ssd_stage_execute_completions, + ssd_stage_terminal_published = snapshot.ssd_stage_terminal_published, + ssd_stage_terminal_cache_inserts = snapshot.ssd_stage_terminal_cache_inserts, + ssd_stage_terminal_cache_duration_us = snapshot.ssd_stage_terminal_cache_duration_us, + ssd_stage_response_send_attempts = snapshot.ssd_stage_response_send_attempts, + ssd_stage_response_send_successes = snapshot.ssd_stage_response_send_successes, + ssd_stage_response_send_failures = snapshot.ssd_stage_response_send_failures, + ssd_stage_response_send_duration_us = snapshot.ssd_stage_response_send_duration_us, + ssd_source_ready_wait_requests = snapshot.ssd_source_ready_wait_requests, + ssd_source_ready_wait_successes = snapshot.ssd_source_ready_wait_successes, + ssd_source_ready_wait_failures = snapshot.ssd_source_ready_wait_failures, + ssd_source_ready_wait_duration_us = snapshot.ssd_source_ready_wait_duration_us, + ssd_target_pull_requests = snapshot.ssd_target_pull_requests, + ssd_target_pull_successes = snapshot.ssd_target_pull_successes, + ssd_target_pull_failures = snapshot.ssd_target_pull_failures, + ssd_target_pull_duration_us = snapshot.ssd_target_pull_duration_us, + ssd_stage_done_detached = snapshot.ssd_stage_done_detached, reserve_free = snapshot.local_reserve_slots_free, reserve_prepared = snapshot.local_reserve_slots_prepared, reserve_pending_visible = snapshot.local_reserve_slots_pending_visible, @@ -6485,6 +7815,18 @@ impl ClientKvApi { failed = snapshot.remote_put_failed, "owner unified remote Put flight snapshot" ); + tracing::info!( + active = snapshot.local_ssd_put_flights_active, + leaders = snapshot.local_ssd_put_flight_leaders, + followers = snapshot.local_ssd_put_flight_followers, + source_unavailable = snapshot.local_ssd_put_source_unavailable, + published = snapshot.local_ssd_put_published, + already_present = snapshot.local_ssd_put_already_present, + dropped = snapshot.local_ssd_put_dropped, + obsolete = snapshot.local_ssd_put_obsolete, + failed = snapshot.local_ssd_put_failed, + "owner local SSD Put flight snapshot" + ); if snapshot.hot_cache_capacity_bytes > 0 { tracing::info!( capacity_bytes = snapshot.hot_cache_capacity_bytes, @@ -6529,7 +7871,12 @@ impl ClientKvApi { let ClientKvApiNewArg { test_spec_config, owner_hot_cache_capacity_bytes, + ssd_storage, } = arg; + let ssd_storage = match ssd_storage { + Some(init) => Some(Arc::new(KvSsdStorage::new(init).await?)), + None => None, + }; let (owner_local_publish_tx, owner_local_publish_rx) = tokio::sync::ampsc::channel(OWNER_LOCAL_PUBLISH_QUEUE_CAPACITY); // The Moka eviction listener is synchronous and must never block while @@ -6544,6 +7891,7 @@ impl ClientKvApi { let owner_source_eviction_selected = Arc::new(DashMap::new()); let owner_hot_counters = Arc::new(OwnerHotCacheCounters::default()); let owner_remote_put_counters = Arc::new(OwnerRemotePutCounters::default()); + let owner_local_ssd_put_counters = Arc::new(OwnerLocalSsdPutCounters::default()); let owner_hot_retry_queue = Arc::new(OwnerHotRetryQueue::new(owner_hot_counters.clone())); let owner_hot_cache = owner_hot_cache_capacity_bytes.map(|capacity_bytes| { build_owner_hot_cache( @@ -6557,6 +7905,7 @@ impl ClientKvApi { let inner = ClientKvApiInner { view: ClientKvApiViewHolder::new(), test_spec_config, + ssd_storage, metrics: OnceLock::new(), all_memholder_refcount: OnceLock::new(), get_remote_kv_lock: AMapLock::new(Duration::from_secs(60)), @@ -6576,7 +7925,9 @@ impl ClientKvApi { owner_source_eviction_selected, owner_hot_counters, owner_remote_put_counters, + owner_local_ssd_put_counters, planned_get_counters: OwnerPlannedGetCounters::default(), + ssd_stage_counters: OwnerSsdStageCounters::default(), owner_hot_retry_queue, owner_hot_eviction_tx, owner_hot_eviction_rx: Mutex::new(Some(owner_hot_eviction_rx)), @@ -6598,6 +7949,10 @@ impl ClientKvApi { completed_planned_external_get_executes: moka::future::Cache::builder() .time_to_live(Duration::from_secs(120)) .build(), + ssd_stage_flights: DashMap::new(), + completed_ssd_stages: moka::future::Cache::builder() + .time_to_live(SSD_STAGE_TERMINAL_TTL) + .build(), next_external_get_start_handle: AtomicU64::new(1), next_external_holding_id: AtomicU64::new(1), external_pending_puts: moka::sync::Cache::builder() @@ -6628,6 +7983,7 @@ impl ClientKvApi { rpc_caller_put_append_done: RPCCaller::new(), rpc_caller_batch_put_append_done: RPCCaller::new(), rpc_caller_batch_evict_owner_source: RPCCaller::new(), + rpc_caller_batch_publish_owner_ssd: RPCCaller::new(), rpc_caller_reserve_local_grant: RPCCaller::new(), rpc_caller_release_local_grant: RPCCaller::new(), rpc_caller_delete: RPCCaller::new(), @@ -6636,6 +7992,9 @@ impl ClientKvApi { rpc_caller_get_meta: RPCCaller::new(), rpc_caller_allocate_client_lease: RPCCaller::new(), rpc_caller_client_lease_keepalive: RPCCaller::new(), + rpc_caller_ssd_stage_read: RPCCaller::new(), + rpc_caller_ssd_stage_begin: RPCCaller::new(), + rpc_caller_ssd_stage_done: RPCCaller::new(), rpc_caller_external_put_commit: RPCCaller::new(), rpc_caller_external_put_revoke: RPCCaller::new(), rpc_caller_resolve_side_transfer_lane: RPCCaller::new(), @@ -6708,6 +8067,9 @@ impl ClientKvApi { inner .rpc_caller_batch_evict_owner_source .regist(inner.view.p2p_module()); + inner + .rpc_caller_batch_publish_owner_ssd + .regist(inner.view.p2p_module()); inner .rpc_caller_reserve_local_grant .regist(inner.view.p2p_module()); @@ -6722,6 +8084,15 @@ impl ClientKvApi { .rpc_caller_batch_is_exist .regist(inner.view.p2p_module()); inner.rpc_caller_get_meta.regist(inner.view.p2p_module()); + inner + .rpc_caller_ssd_stage_read + .regist(inner.view.p2p_module()); + inner + .rpc_caller_ssd_stage_begin + .regist(inner.view.p2p_module()); + inner + .rpc_caller_ssd_stage_done + .regist(inner.view.p2p_module()); inner .rpc_caller_external_put_commit .regist(inner.view.p2p_module()); @@ -6743,6 +8114,53 @@ impl ClientKvApi { external_api::spawn_external_get_start_handle_sweeper(inner.view.clone_view()); self.spawn_runtime_observe_reporter(); + let view_ssd = inner.view.clone_view(); + RPCHandler::::new().regist(inner.view.p2p_module(), move |resp, msg| { + let view = view_ssd.clone(); + let task_view = view.clone(); + view.spawn("rpc_ssd_stage_read", async move { + let get_id = msg.serialize_part.get_id; + let peer = resp.node_id(); + let task_id = resp.task_id(); + let result = handle_ssd_stage_read(&task_view, &msg).await; + let inner = task_view.client_kv_api().inner(); + inner + .ssd_stage_counters + .response_send_attempts + .fetch_add(1, Ordering::Relaxed); + let send_started_at = Instant::now(); + let send_result = resp + .send_resp_with_transport_policy(result, RpcTransportPolicy::ForceTransport) + .await; + inner + .ssd_stage_counters + .response_send_duration_us + .fetch_add( + u64::try_from(send_started_at.elapsed().as_micros()).unwrap_or(u64::MAX), + Ordering::Relaxed, + ); + if let Err(err) = send_result { + inner + .ssd_stage_counters + .response_send_failures + .fetch_add(1, Ordering::Relaxed); + tracing::warn!( + get_id, + peer = %peer, + task_id, + error = ?err, + "SSD stage-ready response send failed" + ); + } else { + inner + .ssd_stage_counters + .response_send_successes + .fetch_add(1, Ordering::Relaxed); + } + }); + Ok(()) + }); + // External RPC handlers let view_ext = inner.view.clone_view(); RPCHandler::::new().regist(inner.view.p2p_module(), move |resp, msg| { @@ -7357,6 +8775,9 @@ impl LogicalModule for ClientKvApi { } async fn shutdown(&self) -> Result<(), Self::Error> { tracing::info!("ClientKvApi shutting down..."); + if let Some(store) = self.0.ssd_storage.as_ref() { + store.close().await?; + } tracing::info!( "ClientKvApi final: holding_len={} , cache_len={}", self.0.get_holding_len(), diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs index 372a9a2..4c87394 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/msg_pack.rs @@ -59,6 +59,38 @@ impl TestPutPhaseTrace { merge_i64_field!(owner_master_put_end_server_us); } } + +#[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)] +pub struct SsdStageReadReq { + pub key: String, + pub put_id: PutIDForAKey, + pub get_id: u64, + pub stage_addr: u64, + pub stage_capacity: u64, + pub len: u64, +} + +impl MsgPackSerializePart for SsdStageReadReq { + fn msg_id(&self) -> u32 { + 4044 + } +} + +impl RPCReq for SsdStageReadReq { + type Resp = SsdStageReadResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct SsdStageReadResp { + pub error_code: ErrorCode, + pub error_json: String, +} + +impl MsgPackSerializePart for SsdStageReadResp { + fn msg_id(&self) -> u32 { + 4045 + } +} // --- RPC for Physical Node Shared Memory --- #[derive(Default, Debug, Clone, Encode, Decode)] diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs index d8bcc0a..11a5f5a 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/put.rs @@ -2,6 +2,7 @@ use super::{ ClientKvApiInner, OwnerHotEvictionEvent, OwnerHotEvictionPreparation, OwnerHotSelectionFenceOutcome, OwnerLocalReserveClassState, OwnerLocalReserveGrantState, OwnerLocalReservePoolState, OwnerLocalReserveSlotLease, OwnerLocalReserveSlotRef, + OwnerLocalSsdPutOutcome, OwnerLocalSsdPutReservation, OwnerLocalSsdPutSharedOp, OwnerRemotePutOutcome, OwnerRemotePutReservation, OwnerRemotePutSharedOp, local_reserve_rebalance::{owner_local_reserve_timeout_config, wait_owner_local_reserve_ready}, }; @@ -19,19 +20,20 @@ use crate::{ master_kv_router::msg_pack::{ BatchEnqueueReplicaTaskReq, BatchEnqueueReplicaTaskResp, BatchEvictOwnerSourceReq, BatchEvictOwnerSourceResp, BatchPreparePutKeyItemReq, BatchPreparePutKeysReq, - BatchPreparePutKeysResp, BatchPutAppendDoneItemReq, BatchPutAppendDoneReq, - BatchPutAppendDoneResp, BatchPutAppendStartItemReq, BatchPutAppendStartReq, - BatchPutAppendStartResp, BatchPutDoneItemReq, BatchPutDoneItemResp, BatchPutDoneReq, - BatchPutDoneResp, BatchPutRevokeItemReq, BatchPutRevokeReq, BatchPutRevokeResp, - BatchPutStartItemReq, BatchPutStartReq, BatchPutStartResp, - BatchReleasePutKeyReservationsReq, BatchReleasePutKeyReservationsResp, - EnqueueReplicaTaskItemResp, GroupedBatchPutDoneItemReq, GroupedBatchPutDoneReq, - GroupedBatchPutDoneResp, OwnerReclaimBacking, OwnerSourceEvictionOutcome, - OwnerSourceEvictionVictim, PutAppendDoneReq, PutAppendDoneResp, PutAppendRevokeReq, - PutAppendStartOutcome, PutAppendStartReq, PutAppendStartResp, PutAtomicGroup, - PutDoneCommittedSlot, PutDoneReq, PutRevokeReq, PutStartReq, PutStartResp, - ReleaseLocalGrantReq, ReserveLocalGrantOutcome, ReserveLocalGrantReq, - owner_source_eviction_epoch, + BatchPreparePutKeysResp, BatchPublishOwnerSsdReq, BatchPublishOwnerSsdResp, + BatchPutAppendDoneItemReq, BatchPutAppendDoneReq, BatchPutAppendDoneResp, + BatchPutAppendStartItemReq, BatchPutAppendStartReq, BatchPutAppendStartResp, + BatchPutDoneItemReq, BatchPutDoneItemResp, BatchPutDoneReq, BatchPutDoneResp, + BatchPutRevokeItemReq, BatchPutRevokeReq, BatchPutRevokeResp, BatchPutStartItemReq, + BatchPutStartReq, BatchPutStartResp, BatchReleasePutKeyReservationsReq, + BatchReleasePutKeyReservationsResp, EnqueueReplicaTaskItemResp, GroupedBatchPutDoneItemReq, + GroupedBatchPutDoneReq, GroupedBatchPutDoneResp, OwnerReclaimBacking, + OwnerSourceEvictionOutcome, OwnerSourceEvictionVictim, OwnerSourceEvictionVictimResp, + OwnerSourceSsdPolicy, OwnerSsdPublishItem, OwnerSsdPublishOutcome, PutAppendDoneReq, + PutAppendDoneResp, PutAppendRevokeReq, PutAppendStartOutcome, PutAppendStartReq, + PutAppendStartResp, PutAtomicGroup, PutDoneCommittedSlot, PutDoneReq, PutRevokeReq, + PutStartReq, PutStartResp, ReleaseLocalGrantReq, ReserveLocalGrantOutcome, + ReserveLocalGrantReq, owner_source_eviction_epoch, }, memholder::{UserMemHolder, UserMemHolderExposeKind}, p2p::msg_pack::MsgPack, @@ -41,6 +43,7 @@ use crate::{ use chrono::Utc; use fluxon_commu::TransferBreakdown; use limit_thirdparty::tokio; +use std::future::Future; use std::sync::{Arc, atomic::Ordering}; use std::time::{Duration, Instant}; use tracing::info; @@ -363,6 +366,7 @@ mod local_reserve_claim_tests { ClientKvApi::construct(ClientKvApiNewArg { test_spec_config: TestSpecConfig::default(), owner_hot_cache_capacity_bytes: None, + ssd_storage: None, }) .await .expect("construct test ClientKvApi"), @@ -457,6 +461,7 @@ mod local_reserve_claim_tests { ClientKvApi::construct(ClientKvApiNewArg { test_spec_config: TestSpecConfig::default(), owner_hot_cache_capacity_bytes: None, + ssd_storage: None, }) .await .expect("construct test ClientKvApi"), @@ -511,6 +516,7 @@ mod local_reserve_claim_tests { ClientKvApi::construct(ClientKvApiNewArg { test_spec_config: TestSpecConfig::default(), owner_hot_cache_capacity_bytes: None, + ssd_storage: None, }) .await .expect("construct test ClientKvApi"), @@ -558,6 +564,7 @@ mod local_reserve_claim_tests { ClientKvApi::construct(ClientKvApiNewArg { test_spec_config: TestSpecConfig::default(), owner_hot_cache_capacity_bytes: None, + ssd_storage: None, }) .await .expect("construct test ClientKvApi"), @@ -630,7 +637,10 @@ pub struct OwnerReservedPutItem { pub lease_id: Option, pub peer_node_id: Option, pub remember_local_snapshot: bool, + /// Original caller/content selection, independent of remote capacity. pub make_replica_task: bool, + /// The master pre-reserved a remote memory target for this Put. + pub remote_replica_admitted: bool, pub preferred_sub_cluster: Option, } @@ -641,7 +651,12 @@ pub struct OwnerLocalPublishItem { pub value_len: u64, pub lease_id: Option, pub committed_slot: PutDoneCommittedSlot, + /// Original caller/content selection, independent of remote capacity. pub make_replica_task: bool, + /// This Put path admitted a remote trigger. Pre-reserved paths set this + /// only when a target exists; owner-local fast Put admits selected items + /// here and performs allocation inside the later append Start. + pub remote_replica_admitted: bool, pub preferred_sub_cluster: Option, pub atomic_group: Option, } @@ -656,6 +671,40 @@ pub struct OwnerLocalPublishJob { pub external_pending_contexts: Vec, } +fn owner_local_publish_starts_remote(item: &OwnerLocalPublishItem) -> bool { + item.make_replica_task && item.remote_replica_admitted +} + +#[derive(Clone)] +struct OwnerLocalSsdPutCandidate { + key: String, + put_id: PutIDForAKey, + /// Exact logical value bytes known by the publishing Put path. Early SSD + /// writes use this to reject over-budget candidates before installing a + /// generation flight or acquiring a source holder. A zero value is kept + /// only for legacy allocation-backed last-backing candidates whose + /// resource admission already happened upstream. + value_len: u64, + selected_victim: Option>, +} + +struct OwnerLocalSsdPutLeader { + op: Arc, + memory_info: Arc, + /// Bytes actually charged by the caller's admission pass. This can be + /// zero for a legacy allocation-backed last-backing candidate, so gate + /// failure must refund this value rather than minting credit from the + /// subsequently discovered source length. + admission_len: u64, +} + +fn owner_reclaim_backing_len(backing: &OwnerReclaimBacking) -> u64 { + match backing { + OwnerReclaimBacking::CommittedSlot { slot_size, .. } => *slot_size, + OwnerReclaimBacking::Allocation | OwnerReclaimBacking::UnindexedAllocation { .. } => 0, + } +} + #[derive(Debug, Clone, Copy, Default)] pub struct PutEndStats { pub master_put_end_rpc_us: i64, @@ -1093,7 +1142,8 @@ impl ClientKvApiInner { lease_id, peer_node_id: peer_node_id.clone(), remember_local_snapshot: true, - make_replica_task: start_req.make_replica_task && replica_admitted, + make_replica_task: start_req.make_replica_task, + remote_replica_admitted: replica_admitted, preferred_sub_cluster: start_req.preferred_sub_cluster, }); } @@ -1176,6 +1226,8 @@ impl ClientKvApiInner { })); } + let mut early_ssd_candidates = Vec::new(); + let mut remote_replica_pending = Vec::new(); for (pending, done_item) in done_pending.into_iter().zip(done_resp.items.into_iter()) { if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( done_item.error_code, @@ -1188,27 +1240,38 @@ impl ClientKvApiInner { self.remember_local_snapshot(&pending.item.key, pending.item.put_id); } if pending.item.make_replica_task { - if let Err(err) = self - .ensure_remote_put( - &pending.item.key, - pending.item.put_id, - pending.item.preferred_sub_cluster.clone(), - true, - ) - .await - { - tracing::warn!( - "owner_batch_put_commit_reserved make replica task failed after local commit: key={} put_id=({},{}) err={}", - pending.item.key, - pending.item.put_id.0, - pending.item.put_id.1, - err - ); - } + early_ssd_candidates.push(( + pending.item.key.clone(), + pending.item.put_id, + pending.item.value_len, + )); + } + if pending.item.make_replica_task && pending.item.remote_replica_admitted { + remote_replica_pending.push(( + pending.item.key.clone(), + pending.item.put_id, + pending.item.preferred_sub_cluster.clone(), + )); } results[pending.idx] = Some(Ok(())); } + self.start_early_owner_local_ssd_puts(early_ssd_candidates); + for (key, put_id, preferred_sub_cluster) in remote_replica_pending { + if let Err(err) = self + .ensure_remote_put(&key, put_id, preferred_sub_cluster, true) + .await + { + tracing::warn!( + "owner_batch_put_commit_reserved make replica task failed after local commit: key={} put_id=({},{}) err={}", + key, + put_id.0, + put_id.1, + err + ); + } + } + Ok(results .into_iter() .map(|item| { @@ -1302,9 +1365,11 @@ impl ClientKvApiInner { idx: usize, key: String, put_id: PutIDForAKey, + value_len: u64, lease_id: Option, remember_local_snapshot: bool, make_replica_task: bool, + remote_replica_admitted: bool, preferred_sub_cluster: Option, } @@ -1313,7 +1378,7 @@ impl ClientKvApiInner { let short_circuit_payload = self.short_circuit_put_payload_path_enabled(); let skip_put_end_commit = self.skip_put_end_commit_enabled(); - for (idx, (((key, ptrs), _payload_len), start_item)) in keys + for (idx, (((key, ptrs), payload_len), start_item)) in keys .into_iter() .zip(ptrs_groups.into_iter()) .zip(payload_lens.into_iter()) @@ -1342,9 +1407,11 @@ impl ClientKvApiInner { idx, key, put_id, + value_len: payload_len, lease_id, remember_local_snapshot, - make_replica_task: make_replica_task && replica_admitted, + make_replica_task, + remote_replica_admitted: replica_admitted, preferred_sub_cluster: preferred_sub_cluster.clone(), }); } @@ -1386,6 +1453,8 @@ impl ClientKvApiInner { ), })); } + let mut early_ssd_candidates = Vec::new(); + let mut remote_replica_pending = Vec::new(); for (pending, done_item) in done_pending.into_iter().zip(done_resp.items.into_iter()) { if let Err(err) = crate::rpcresp_kvresult_convert::try_from_code( done_item.error_code, @@ -1398,27 +1467,34 @@ impl ClientKvApiInner { self.remember_local_snapshot(&pending.key, pending.put_id); } if pending.make_replica_task { - if let Err(err) = self - .ensure_remote_put( - &pending.key, - pending.put_id, - pending.preferred_sub_cluster.clone(), - true, - ) - .await - { - tracing::warn!( - "batch make replica task failed after local commit: key={} put_id=({},{}) err={}", - pending.key, - pending.put_id.0, - pending.put_id.1, - err - ); - } + early_ssd_candidates.push((pending.key.clone(), pending.put_id, pending.value_len)); + } + if pending.make_replica_task && pending.remote_replica_admitted { + remote_replica_pending.push(( + pending.key.clone(), + pending.put_id, + pending.preferred_sub_cluster.clone(), + )); } results[pending.idx] = Some(Ok(())); } + self.start_early_owner_local_ssd_puts(early_ssd_candidates); + for (key, put_id, preferred_sub_cluster) in remote_replica_pending { + if let Err(err) = self + .ensure_remote_put(&key, put_id, preferred_sub_cluster, true) + .await + { + tracing::warn!( + "batch make replica task failed after local commit: key={} put_id=({},{}) err={}", + key, + put_id.0, + put_id.1, + err + ); + } + } + Ok(results .into_iter() .map(|item| { @@ -1431,6 +1507,148 @@ impl ClientKvApiInner { .collect()) } + fn start_owner_local_ssd_puts( + &self, + candidates: Vec, + resources_pre_admitted: bool, + ) -> Vec>> { + // Early backing is optional work. Apply its independent byte budget + // before touching the per-key generation table or pinning a source. + // Last-backing callers have already performed the same admission while + // deciding which capacity victims may enter durability, so they pass + // resources_pre_admitted=true and must not be charged twice. + let admission = if resources_pre_admitted { + vec![true; candidates.len()] + } else { + let lengths = candidates + .iter() + .map(|candidate| candidate.value_len) + .collect::>(); + self.ssd_storage + .as_ref() + .map(|store| store.admit_owner_write_candidates(&lengths)) + .unwrap_or_else(|| vec![false; candidates.len()]) + }; + let mut operations = std::iter::repeat_with(|| None) + .take(candidates.len()) + .collect::>(); + let mut leaders = Vec::new(); + let mut unused_pre_admission_lengths = Vec::new(); + for (index, (candidate, admitted_by_resource)) in + candidates.into_iter().zip(admission).enumerate() + { + if !admitted_by_resource { + continue; + } + let pre_admitted_len = candidate.value_len; + match self.begin_owner_local_ssd_put( + &candidate.key, + candidate.put_id, + candidate.selected_victim.as_deref(), + ) { + OwnerLocalSsdPutReservation::Leader { op, memory_info } => { + operations[index] = Some(op.clone()); + if pre_admitted_len != 0 && u64::from(memory_info.len) != pre_admitted_len { + tracing::warn!( + key = %candidate.key, + put_id_time = candidate.put_id.0, + put_id_version = candidate.put_id.1, + admitted_len = pre_admitted_len, + source_len = memory_info.len, + "owner local SSD pre-admission length no longer matches exact source" + ); + unused_pre_admission_lengths.push(pre_admitted_len); + self.finish_owner_local_ssd_put(&op, OwnerLocalSsdPutOutcome::Failed); + continue; + } + leaders.push(OwnerLocalSsdPutLeader { + op, + memory_info, + admission_len: pre_admitted_len, + }); + } + OwnerLocalSsdPutReservation::Follower(op) => { + operations[index] = Some(op); + unused_pre_admission_lengths.push(pre_admitted_len); + } + OwnerLocalSsdPutReservation::SourceUnavailable => { + unused_pre_admission_lengths.push(pre_admitted_len); + } + } + } + if let Some(store) = self.ssd_storage.as_ref() { + store.refund_owner_write_admission(&unused_pre_admission_lengths); + } + if leaders.is_empty() { + return operations; + } + + let admitted_lengths = leaders + .iter() + .map(|leader| leader.admission_len) + .collect::>(); + let permit = match self.try_acquire_local_ssd_persist_batch(leaders.len()) { + Ok(Some(permit)) => permit, + Ok(None) => { + if let Some(store) = self.ssd_storage.as_ref() { + store.refund_owner_write_admission(&admitted_lengths); + } + for leader in leaders { + self.finish_owner_local_ssd_put(&leader.op, OwnerLocalSsdPutOutcome::Dropped); + } + return operations; + } + Err(err) => { + if let Some(store) = self.ssd_storage.as_ref() { + store.refund_owner_write_admission(&admitted_lengths); + } + tracing::warn!( + items = leaders.len(), + error = %err, + "owner local SSD durability batch admission failed" + ); + for leader in leaders { + self.finish_owner_local_ssd_put(&leader.op, OwnerLocalSsdPutOutcome::Failed); + } + return operations; + } + }; + + let spawn_view = self.view.clone_view(); + let task_view = spawn_view.clone(); + let _ = spawn_view.spawn("owner_local_ssd_put_batch", async move { + run_owner_local_ssd_put_batch(task_view, leaders, permit).await; + }); + operations + } + + pub(crate) fn start_early_owner_local_ssd_puts( + &self, + candidates: Vec<(String, PutIDForAKey, u64)>, + ) { + let _ = self.start_owner_local_ssd_puts( + candidates + .into_iter() + .map(|(key, put_id, value_len)| OwnerLocalSsdPutCandidate { + key, + put_id, + value_len, + selected_victim: None, + }) + .collect(), + false, + ); + } + + pub(crate) fn start_early_owner_local_ssd_put( + &self, + key: &str, + put_id: PutIDForAKey, + value_len: u64, + ) { + self.start_early_owner_local_ssd_puts(vec![(key.to_string(), put_id, value_len)]); + } + /// Ensure one remote backing exists for an exact owner-local generation. /// /// Normal Put, pre-reserved replica, proactive write-back, and tier1 all @@ -1605,6 +1823,9 @@ impl ClientKvApiInner { ); self.put_end(key, put_id, lease_id).await?; self.remember_local_snapshot(key, put_id); + if make_replica_task { + self.start_early_owner_local_ssd_put(key, put_id, payload_len); + } if make_replica_task && replica_admitted { if let Err(err) = self .ensure_remote_put(key, put_id, preferred_sub_cluster.map(str::to_string), true) @@ -1676,6 +1897,9 @@ impl ClientKvApiInner { self.put_end(key, put_id, lease_id).await?; self.remember_local_snapshot(key, put_id); + if make_replica_task { + self.start_early_owner_local_ssd_put(key, put_id, payload_len); + } if make_replica_task && replica_admitted { if let Err(err) = self .ensure_remote_put(key, put_id, preferred_sub_cluster.map(str::to_string), true) @@ -2215,6 +2439,54 @@ impl ClientKvApiInner { Ok(resp.serialize_part) } + async fn batch_publish_owner_ssd( + &self, + items: Vec, + ) -> KvResult { + if items.is_empty() { + return Ok(BatchPublishOwnerSsdResp { + items: Vec::new(), + error_code: crate::rpcresp_kvresult_convert::msg_and_error::OK, + error_json: String::new(), + }); + } + if !self.view.register_shutdown_poller().is_running() { + return Err(KvError::Api(ApiError::SystemShutdown { + detail: "ClientKvApi is shutting down; rejecting owner SSD publication".to_string(), + })); + } + let self_info = self.view.cluster_manager().get_self_info(); + let req = MsgPack { + serialize_part: BatchPublishOwnerSsdReq { + owner_node_start_time: self_info.node_start_time, + items, + }, + raw_bytes: Vec::new(), + }; + let master_node_id = self + .view + .cluster_manager() + .find_or_wait_master_node() + .await?; + let resp = self + .rpc_caller_batch_publish_owner_ssd + .call_with_transport_policy( + self.view.p2p_module(), + master_node_id.into(), + req, + Some(Duration::from_secs(60)), + RpcTransportPolicy::ForceTransport, + 2, + ) + .await + .map_err(KvError::from)?; + crate::rpcresp_kvresult_convert::try_from_code( + resp.serialize_part.error_code, + resp.serialize_part.error_json.clone(), + )?; + Ok(resp.serialize_part) + } + pub async fn put_append_revoke( &self, key: &str, @@ -2786,7 +3058,7 @@ const OWNER_LOCAL_PUBLISH_RETRY_MAX: Duration = Duration::from_secs(1); mod owner_hot_replica_policy_tests { use super::{ OwnerLocalPublishItem, complete_owner_local_publish_group_lens, - owner_local_publish_atomic_batch_complete, + owner_local_publish_atomic_batch_complete, owner_local_publish_starts_remote, }; use crate::master_kv_router::msg_pack::{ PutAtomicGroup, PutAtomicGroupMember, PutDoneCommittedSlot, @@ -2804,6 +3076,7 @@ mod owner_hot_replica_policy_tests { lease_id: None, committed_slot: PutDoneCommittedSlot::default(), make_replica_task: false, + remote_replica_admitted: false, preferred_sub_cluster: None, atomic_group, } @@ -2845,6 +3118,19 @@ mod owner_hot_replica_policy_tests { assert_eq!(complete_owner_local_publish_group_lens(&partial), None); } + #[test] + fn local_ssd_content_selection_does_not_bypass_remote_resource_admission() { + let mut item = publish_item("key", (1, 0), None); + item.make_replica_task = true; + assert!(!owner_local_publish_starts_remote(&item)); + + item.remote_replica_admitted = true; + assert!(owner_local_publish_starts_remote(&item)); + + item.make_replica_task = false; + assert!(!owner_local_publish_starts_remote(&item)); + } + #[test] fn hot_admission_waits_for_every_atomic_group_member_to_publish() { let group = PutAtomicGroup { @@ -2919,6 +3205,7 @@ fn owner_source_eviction_identity( fn owner_source_eviction_victim( identity: &super::OwnerHotReplicaIdentity, memory_info: &crate::memholder::MemoryInfo, + ssd_enabled: bool, ) -> Option { let (slot_size, grant_id, slot_index) = memory_info.local_reserve_resident_slot_ref()?; Some(OwnerSourceEvictionVictim { @@ -2929,6 +3216,12 @@ fn owner_source_eviction_victim( slot_index, slot_size, }, + ssd_backing_len: None, + ssd_policy: if ssd_enabled { + OwnerSourceSsdPolicy::SelectLastLive + } else { + OwnerSourceSsdPolicy::Drop + }, }) } @@ -3049,7 +3342,9 @@ fn prepare_owner_source_eviction_event( }; debug_assert_eq!(resolved_trigger, trigger); - let Some(victim) = owner_source_eviction_victim(&trigger, source.as_ref()) else { + let Some(victim) = + owner_source_eviction_victim(&trigger, source.as_ref(), inner.ssd_storage.is_some()) + else { event.selection_debt.release(); inner .owner_hot_counters @@ -3112,6 +3407,194 @@ fn prepare_owner_source_eviction_event( Some((event, victim)) } +async fn finish_owner_source_eviction_result( + inner: &ClientKvApiInner, + operation_id: u64, + index: usize, + event: OwnerHotEvictionEvent, + victim: Arc, + result: OwnerSourceEvictionVictimResp, +) { + if victim.ssd_policy == OwnerSourceSsdPolicy::Persisted + && !result.ssd_backing_committed + && matches!( + result.outcome, + OwnerSourceEvictionOutcome::Completed + | OwnerSourceEvictionOutcome::Stale + | OwnerSourceEvictionOutcome::RejectedNotEvictable + ) + { + inner + .discard_local_ssd_replica(&victim.key, victim.put_id) + .await; + } + match result.outcome { + OwnerSourceEvictionOutcome::Accepted | OwnerSourceEvictionOutcome::AlreadyInProgress => { + inner + .owner_hot_counters + .source_evict_handoff_members + .fetch_add(1, Ordering::Relaxed); + } + OwnerSourceEvictionOutcome::Completed => { + let epoch = owner_source_eviction_epoch(operation_id, index); + match super::reclaim::complete_owner_source_eviction(inner, &victim, epoch) { + Ok(()) => { + inner + .owner_hot_counters + .source_evict_handoff_members + .fetch_add(1, Ordering::Relaxed); + } + Err(detail) => { + tracing::warn!( + key = victim.key, + put_time_ms = victim.put_id.0, + put_version = victim.put_id.1, + detail, + "master deleted source route but owner slot release must retry" + ); + schedule_owner_source_eviction_retry( + inner, + event, + victim, + "owner slot release after master direct-delete is temporarily busy", + ); + } + } + } + OwnerSourceEvictionOutcome::SsdCandidate => { + tracing::error!( + key = victim.key, + policy = ?victim.ssd_policy, + "master returned an SSD candidate outside the selection phase" + ); + schedule_owner_source_eviction_retry( + inner, + event, + victim, + "unexpected repeated SSD candidate response", + ); + } + OwnerSourceEvictionOutcome::RetryableBusy | OwnerSourceEvictionOutcome::Unspecified => { + schedule_owner_source_eviction_retry( + inner, + event, + victim, + "master source reclaim is temporarily busy", + ); + } + OwnerSourceEvictionOutcome::Stale => { + finish_owner_source_selection( + inner, + &victim, + true, + "master rejected stale source identity", + ); + } + OwnerSourceEvictionOutcome::RejectedNotEvictable => { + tracing::error!( + key = victim.key, + detail = result.detail, + "owner selected a source victim that master declared non-evictable" + ); + finish_owner_source_selection( + inner, + &victim, + true, + "master rejected non-evictable source victim", + ); + } + } +} + +async fn submit_owner_source_eviction_decisions( + inner: &ClientKvApiInner, + prepared: Vec<(OwnerHotEvictionEvent, Arc)>, + rpc_failure_reason: &'static str, + response_length_reason: &'static str, + response_identity_reason: &'static str, +) { + if prepared.is_empty() { + return; + } + let response = inner + .batch_evict_owner_source( + prepared + .iter() + .map(|(_, victim)| victim.as_ref().clone()) + .collect(), + ) + .await; + let Ok(response) = response else { + for (event, victim) in prepared { + schedule_owner_source_eviction_retry(inner, event, victim, rpc_failure_reason); + } + return; + }; + if response.victims.len() != prepared.len() { + for (event, victim) in prepared { + schedule_owner_source_eviction_retry(inner, event, victim, response_length_reason); + } + return; + } + let operation_id = response.operation_id; + for (index, ((event, victim), result)) in prepared.into_iter().zip(response.victims).enumerate() + { + if result.victim_index != u32::try_from(index).unwrap_or(u32::MAX) { + schedule_owner_source_eviction_retry(inner, event, victim, response_identity_reason); + continue; + } + finish_owner_source_eviction_result(inner, operation_id, index, event, victim, result) + .await; + } +} + +async fn reclaim_admission_drops_before_ssd_persist( + drop_reclaim: DropFuture, + persist: PersistFn, +) -> T +where + DropFuture: Future, + PersistFn: FnOnce() -> PersistFuture, + PersistFuture: Future, +{ + drop_reclaim.await; + persist().await +} + +#[cfg(test)] +mod owner_ssd_fast_drop_tests { + use super::reclaim_admission_drops_before_ssd_persist; + use std::sync::{Arc, Mutex}; + + #[limit_thirdparty::tokio::test] + async fn admission_drops_finish_before_ssd_persist_starts() { + let order = Arc::new(Mutex::new(Vec::new())); + let drop_order = order.clone(); + let persist_order = order.clone(); + + let result = reclaim_admission_drops_before_ssd_persist( + async move { + drop_order.lock().unwrap().push("drop-start"); + limit_thirdparty::tokio::task::yield_now().await; + drop_order.lock().unwrap().push("drop-finished"); + }, + move || async move { + let mut order = persist_order.lock().unwrap(); + assert_eq!(order.last(), Some(&"drop-finished")); + order.push("persist-start"); + 17 + }, + ) + .await; + + assert_eq!(result, 17); + assert_eq!( + order.lock().unwrap().as_slice(), + ["drop-start", "drop-finished", "persist-start"] + ); + } +} + async fn process_owner_source_eviction_events( view: &ClientKvApiView, events: Vec, @@ -3124,11 +3607,16 @@ async fn process_owner_source_eviction_events( if prepared.is_empty() { return; } - let victims = prepared - .iter() - .map(|(_, victim)| victim.as_ref().clone()) - .collect::>(); - let response = inner.batch_evict_owner_source(victims).await; + // The first pass never touches SSD. Master deletes sources that already + // have another live backing and returns only exact last-copy candidates. + let response = inner + .batch_evict_owner_source( + prepared + .iter() + .map(|(_, victim)| victim.as_ref().clone()) + .collect(), + ) + .await; let Ok(response) = response else { for (event, victim) in prepared { schedule_owner_source_eviction_retry( @@ -3184,6 +3672,8 @@ async fn process_owner_source_eviction_events( ); } + let first_operation_id = response.operation_id; + let mut candidates = Vec::new(); for (index, ((event, victim), result)) in prepared .into_iter() .zip(response.victims.into_iter()) @@ -3198,73 +3688,120 @@ async fn process_owner_source_eviction_events( ); continue; } - match result.outcome { - OwnerSourceEvictionOutcome::Accepted - | OwnerSourceEvictionOutcome::AlreadyInProgress => { - inner - .owner_hot_counters - .source_evict_handoff_members - .fetch_add(1, Ordering::Relaxed); - // Selected debt stays live until owner reclaim Commit calls - // owner_hot_invalidate_version for the exact victim. - } - OwnerSourceEvictionOutcome::Completed => { - let epoch = owner_source_eviction_epoch(response.operation_id, index); - match super::reclaim::complete_owner_source_eviction(inner, &victim, epoch) { - Ok(()) => { - inner - .owner_hot_counters - .source_evict_handoff_members - .fetch_add(1, Ordering::Relaxed); - } - Err(detail) => { - tracing::warn!( - key = victim.key, - put_time_ms = victim.put_id.0, - put_version = victim.put_id.1, - detail, - "master deleted source route but owner slot release must retry" - ); - schedule_owner_source_eviction_retry( - inner, - event, - victim, - "owner slot release after master direct-delete is temporarily busy", - ); - } - } - } - OwnerSourceEvictionOutcome::RetryableBusy | OwnerSourceEvictionOutcome::Unspecified => { - schedule_owner_source_eviction_retry( - inner, - event, - victim, - "master source reclaim is temporarily busy", - ); - } - OwnerSourceEvictionOutcome::Stale => { - finish_owner_source_selection( - inner, - &victim, - true, - "master rejected stale source identity", - ); - } - OwnerSourceEvictionOutcome::RejectedNotEvictable => { - tracing::error!( - key = victim.key, - detail = result.detail, - "owner selected a source victim that master declared non-evictable" - ); - finish_owner_source_selection( - inner, - &victim, - true, - "master rejected non-evictable source victim", - ); - } + if result.outcome == OwnerSourceEvictionOutcome::SsdCandidate + && victim.ssd_policy == OwnerSourceSsdPolicy::SelectLastLive + { + candidates.push((event, victim)); + continue; + } + finish_owner_source_eviction_result( + inner, + first_operation_id, + index, + event, + victim, + result, + ) + .await; + } + + if candidates.is_empty() { + return; + } + let candidate_lengths = candidates + .iter() + .map(|(_, victim)| owner_reclaim_backing_len(&victim.backing)) + .collect::>(); + let admission = inner + .ssd_storage + .as_ref() + .map(|store| store.admit_owner_write_candidates(&candidate_lengths)) + .unwrap_or_else(|| vec![false; candidates.len()]); + let candidate_items = candidates.len(); + let mut dropped = Vec::new(); + let mut admitted_candidates = Vec::new(); + for ((mut event, victim), is_admitted) in candidates.into_iter().zip(admission) { + let mut request = victim.as_ref().clone(); + request.ssd_backing_len = None; + request.ssd_policy = OwnerSourceSsdPolicy::Drop; + let request = Arc::new(request); + event.source_eviction_victim = Some(request.clone()); + if is_admitted { + admitted_candidates.push((event, request)); + } else { + dropped.push((event, request)); } } + + // Candidates rejected by the byte budget must release their DRAM slots + // before the admitted durability batch starts. Otherwise one slow SSD + // flush makes every intentional Drop in the same pressure batch wait, + // recreating a reclaim backlog even though no SSD queue exists. + let dropped_items = dropped.len(); + let admitted_items = admitted_candidates.len(); + // Both early Put and last-backing fallback enter the same per-generation + // local_ssd_put flight. The fallback starts only after explicit admission + // Drops have released their DRAM slots. + let operations = reclaim_admission_drops_before_ssd_persist( + submit_owner_source_eviction_decisions( + inner, + dropped, + "owner SSD admission-drop direct-delete RPC failed", + "owner SSD admission-drop response length mismatch", + "owner SSD admission-drop response identity mismatch", + ), + || async { + inner.start_owner_local_ssd_puts( + admitted_candidates + .iter() + .map(|(_, victim)| OwnerLocalSsdPutCandidate { + key: victim.key.clone(), + put_id: victim.put_id, + value_len: owner_reclaim_backing_len(&victim.backing), + selected_victim: Some(victim.clone()), + }) + .collect(), + true, + ) + }, + ) + .await; + let mut admitted_decisions = Vec::with_capacity(admitted_candidates.len()); + let mut persisted_items = 0usize; + for ((mut event, victim), operation) in admitted_candidates.into_iter().zip(operations) { + let outcome = match operation { + Some(operation) => operation.wait().await, + None => OwnerLocalSsdPutOutcome::Failed, + }; + if matches!( + outcome, + OwnerLocalSsdPutOutcome::Published | OwnerLocalSsdPutOutcome::AlreadyPresent + ) { + persisted_items += 1; + } + // Publication, when successful, already attached SSD to the exact + // route. Direct-delete now removes only memory. Failed/Drop outcomes + // retain the cache's existing fail-open eviction behavior. + event.source_eviction_victim = Some(victim.clone()); + admitted_decisions.push((event, victim)); + } + tracing::info!( + candidates = candidate_items, + admitted = admitted_items, + persisted = persisted_items, + admission_dropped = dropped_items, + persist_dropped = admitted_items.saturating_sub(persisted_items), + "owner last-backing SSD admission completed without queueing excess victims" + ); + + submit_owner_source_eviction_decisions( + inner, + admitted_decisions, + "owner SSD persisted decision direct-delete RPC failed", + "owner SSD persisted decision response length mismatch", + "owner SSD persisted decision response identity mismatch", + ) + .await; } pub fn spawn_owner_source_eviction_dispatcher( @@ -3406,6 +3943,167 @@ pub fn spawn_owner_hot_retry_actor(view: ClientKvApiView) { }); } +async fn run_owner_local_ssd_put_batch( + view: ClientKvApiView, + leaders: Vec, + permit: crate::kv_ssd_storage::KvSsdPersistBatchPermit, +) { + let inner = view.client_kv_api().inner(); + let mut holders = Vec::with_capacity(leaders.len()); + let mut sources = Vec::with_capacity(leaders.len()); + for leader in &leaders { + let holder = Arc::new(UserMemHolder::new( + leader.memory_info.clone(), + inner.get_or_init_all_memholder_refcount(), + UserMemHolderExposeKind::SegPtr, + )); + sources.push(crate::kv_ssd_storage::KvSsdPersistSource { + key: leader.op.key.clone(), + put_id: leader.op.put_id, + addr: holder.memory_info.addr, + len: u64::from(holder.memory_info.len), + }); + holders.push(holder); + } + + let copies = match inner.copy_local_kvs_for_ssd(&sources).await { + Ok(copies) => copies, + Err(err) => { + drop(holders); + tracing::warn!( + items = leaders.len(), + error = %err, + "owner local SSD source copy validation failed" + ); + for leader in leaders { + inner.finish_owner_local_ssd_put(&leader.op, OwnerLocalSsdPutOutcome::Failed); + } + return; + } + }; + // Durability now reads only owner-owned copies. The source Moka pins may + // be released while this flight remains installed through route publish. + drop(holders); + + let persisted = match inner.persist_copied_local_kvs_to_ssd(permit, copies).await { + Ok(persisted) => persisted, + Err(err) => { + tracing::warn!( + items = leaders.len(), + error = %err, + "owner local SSD durability setup failed" + ); + for leader in leaders { + inner.finish_owner_local_ssd_put(&leader.op, OwnerLocalSsdPutOutcome::Failed); + } + return; + } + }; + + let mut publish = Vec::new(); + for ((leader, source), outcome) in leaders + .into_iter() + .zip(sources.into_iter()) + .zip(persisted.into_iter()) + { + match outcome { + Ok(Some(guard)) => { + publish.push((leader, source, guard)); + } + Ok(None) => { + inner.finish_owner_local_ssd_put(&leader.op, OwnerLocalSsdPutOutcome::Dropped); + } + Err(err) => { + tracing::warn!( + key = leader.op.key, + put_time_ms = leader.op.put_id.0, + put_version = leader.op.put_id.1, + error = %err, + "owner local SSD persist failed" + ); + inner.finish_owner_local_ssd_put(&leader.op, OwnerLocalSsdPutOutcome::Failed); + } + } + } + if publish.is_empty() { + return; + } + + let response = match inner + .batch_publish_owner_ssd( + publish + .iter() + .map(|(leader, source, _)| OwnerSsdPublishItem { + key: leader.op.key.clone(), + put_id: leader.op.put_id, + len: source.len, + }) + .collect(), + ) + .await + { + Ok(response) => response, + Err(err) => { + tracing::warn!( + items = publish.len(), + error = %err, + "owner local SSD publication was uncertain; retaining durable bytes for replay" + ); + for (leader, _, _guard) in publish { + inner.finish_owner_local_ssd_put(&leader.op, OwnerLocalSsdPutOutcome::Failed); + } + return; + } + }; + if response.items.len() != publish.len() { + tracing::warn!( + requested = publish.len(), + received = response.items.len(), + "owner local SSD publication response length mismatch; retaining bytes for replay" + ); + for (leader, _, _guard) in publish { + inner.finish_owner_local_ssd_put(&leader.op, OwnerLocalSsdPutOutcome::Failed); + } + return; + } + + for ((leader, _, _guard), result) in publish.into_iter().zip(response.items) { + if result.key != leader.op.key || result.put_id != leader.op.put_id { + tracing::warn!( + expected_key = leader.op.key, + expected_put_time_ms = leader.op.put_id.0, + expected_put_version = leader.op.put_id.1, + response_key = result.key, + response_put_time_ms = result.put_id.0, + response_put_version = result.put_id.1, + "owner local SSD publication identity mismatch; retaining bytes for replay" + ); + inner.finish_owner_local_ssd_put(&leader.op, OwnerLocalSsdPutOutcome::Failed); + continue; + } + let outcome = match result.outcome { + OwnerSsdPublishOutcome::Published => OwnerLocalSsdPutOutcome::Published, + OwnerSsdPublishOutcome::AlreadyPresent => OwnerLocalSsdPutOutcome::AlreadyPresent, + OwnerSsdPublishOutcome::Obsolete => { + inner + .discard_local_ssd_replica(&leader.op.key, leader.op.put_id) + .await; + OwnerLocalSsdPutOutcome::Obsolete + } + OwnerSsdPublishOutcome::Rejected => { + inner + .discard_local_ssd_replica(&leader.op.key, leader.op.put_id) + .await; + OwnerLocalSsdPutOutcome::Failed + } + OwnerSsdPublishOutcome::RetryableBusy | OwnerSsdPublishOutcome::Unspecified => { + OwnerLocalSsdPutOutcome::Failed + } + }; + inner.finish_owner_local_ssd_put(&leader.op, outcome); + } +} + async fn fail_owner_remote_put( view: &ClientKvApiView, op: Arc, @@ -3897,8 +4595,22 @@ pub(crate) async fn publish_owner_local_job(view: ClientKvApiView, job: OwnerLoc let _ = inner.owner_hot_admit_published_committed(&item.key, item.put_id); } + let _ = inner.start_owner_local_ssd_puts( + promoted_items + .iter() + .filter(|item| item.make_replica_task) + .map(|item| OwnerLocalSsdPutCandidate { + key: item.key.clone(), + put_id: item.put_id, + value_len: item.value_len, + selected_victim: None, + }) + .collect(), + false, + ); + for item in promoted_items { - if item.make_replica_task { + if owner_local_publish_starts_remote(item) { if let Err(err) = inner .ensure_remote_put( &item.key, diff --git a/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs b/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs index 1eb0a5a..43a3b47 100644 --- a/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs +++ b/fluxon_rs/fluxon_kv/src/client_kv_api/reclaim.rs @@ -1,4 +1,7 @@ -use super::{ClientKvApiInner, ClientKvApiView, OwnerPreparedReclaim, OwnerReclaimRecord}; +use super::{ + ClientKvApiInner, ClientKvApiView, OwnerPreparedReclaim, OwnerPreparedReclaimSource, + OwnerPreparedSsdBacking, OwnerReclaimRecord, +}; use crate::cluster_manager::{NodeID, NodeRole}; use crate::master_kv_router::msg_pack::{ BatchOwnerReclaimReq, BatchOwnerReclaimResp, OwnerReclaimBacking, OwnerReclaimItem, @@ -7,6 +10,7 @@ use crate::master_kv_router::msg_pack::{ }; use crate::p2p::msg_pack::MsgPack; use crate::rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, OK}; +use limit_thirdparty::tokio; use std::{collections::HashMap, sync::Arc}; fn item_resp( @@ -18,6 +22,7 @@ fn item_resp( key: item.key.clone(), epoch: item.epoch, state, + ssd_backing_len: None, detail: detail.into(), } } @@ -36,7 +41,7 @@ fn memory_matches_reclaim_backing( ) -> bool { match backing { OwnerReclaimBacking::Allocation => memory_info.local_reserve_resident_slot_ref().is_none(), - OwnerReclaimBacking::UnindexedAllocation => false, + OwnerReclaimBacking::UnindexedAllocation { .. } => false, OwnerReclaimBacking::CommittedSlot { grant_id, slot_index, @@ -58,6 +63,8 @@ fn reclaim_key_control_busy_detail(state: &super::OwnerKeyControlState) -> Optio Some("owner external put context is still pending") } else if state.remote_put.is_some() { Some("owner remote put transfer is inflight") + } else if state.local_ssd_put.is_some() { + Some("owner local SSD put is inflight") } else if state.source_eviction_selection.is_some() { Some("owner source eviction selection fence is active") } else if state.external_get.is_some() { @@ -93,7 +100,11 @@ fn prepare_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclai "another owner source selection owns the key fence", ); } - if state.local_puts != 0 || state.external_pending_puts != 0 || state.remote_put.is_some() { + if state.local_puts != 0 + || state.external_pending_puts != 0 + || state.remote_put.is_some() + || state.local_ssd_put.is_some() + { return item_resp( item, OwnerReclaimItemState::Busy, @@ -134,8 +145,13 @@ fn prepare_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclai ); state.reclaim = Some(OwnerReclaimRecord::Prepared(OwnerPreparedReclaim { item: item.clone(), - cached_info: selection.cached_info, - local_snapshot, + source: OwnerPreparedReclaimSource::Indexed { + cached_info: selection.cached_info, + local_snapshot, + }, + ssd_prepare_lock: Arc::new(tokio::sync::AMutex::new(())), + ssd_prepare_complete: false, + ssd_backing: None, })); return item_resp( item, @@ -180,6 +196,58 @@ fn prepare_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclai "owner local Get commit is pending", ); } + if let OwnerReclaimBacking::UnindexedAllocation { + addr, + base_addr, + len, + capacity_bytes, + } = &item.backing + { + if item.reason != OwnerReclaimReason::MasterAllocationCapacity + || *len == 0 + || *capacity_bytes < *len + || *addr < *base_addr + || addr.checked_add(*len).is_none() + { + return item_resp( + item, + OwnerReclaimItemState::Stale, + "invalid unindexed Allocation source identity", + ); + } + if inner.get_cached_info.contains_key(&item.key) + || inner.local_snapshot_info.contains_key(&item.key) + { + return item_resp( + item, + OwnerReclaimItemState::Stale, + "unindexed Allocation unexpectedly has an owner-local index", + ); + } + let state = controls.entry(item.key.clone()).or_default(); + assert!( + state.reclaim.is_none() + && state.local_puts == 0 + && state.external_pending_puts == 0 + && state.external_get.is_none() + ); + state.begin_local_access_fence(); + state.reclaim = Some(OwnerReclaimRecord::Prepared(OwnerPreparedReclaim { + item: item.clone(), + source: OwnerPreparedReclaimSource::UnindexedAllocation { + addr: *addr, + len: *len, + }, + ssd_prepare_lock: Arc::new(tokio::sync::AMutex::new(())), + ssd_prepare_complete: false, + ssd_backing: None, + })); + return item_resp( + item, + OwnerReclaimItemState::Prepared, + "master-owned Allocation source fenced", + ); + } let Some((_key, cached_info)) = inner.get_cached_info.remove_if(&item.key, |_, cached| { cached.put_time_ms == item.put_id.0 && cached.put_version == item.put_id.1 @@ -223,8 +291,13 @@ fn prepare_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclai state.begin_local_access_fence(); state.reclaim = Some(OwnerReclaimRecord::Prepared(OwnerPreparedReclaim { item: item.clone(), - cached_info, - local_snapshot, + source: OwnerPreparedReclaimSource::Indexed { + cached_info, + local_snapshot, + }, + ssd_prepare_lock: Arc::new(tokio::sync::AMutex::new(())), + ssd_prepare_complete: false, + ssd_backing: None, })); item_resp( item, @@ -233,45 +306,227 @@ fn prepare_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclai ) } -fn release_prepared_backing_now(inner: &ClientKvApiInner, prepared: OwnerPreparedReclaim) { - let mut memory_info = Arc::try_unwrap(prepared.cached_info.mem_holder).unwrap_or_else(|_| { - panic!( - "owner reclaim prepared memory unexpectedly gained a holder: key={} epoch={}", - prepared.item.key, prepared.item.epoch - ) - }); - match &prepared.item.backing { - OwnerReclaimBacking::Allocation => { - assert!( - memory_info.local_reserve_resident_slot_ref().is_none(), - "allocation reclaim must not carry a local-reserve slot" - ); +/// Persist one bounded master-capacity batch while every exact source remains +/// fenced. Per-key async locks make an overlapping RPC replay join the first +/// attempt. The storage layer then admits the whole batch without queueing, +/// inserts every independent generation, and executes one durability barrier. +async fn persist_prepared_reclaim_batch_to_ssd( + inner: &ClientKvApiInner, + items: &[OwnerReclaimItem], +) -> Vec> { + let mut backing_lens = vec![None; items.len()]; + if items.is_empty() || inner.ssd_storage.is_none() { + return backing_lens; + } + + let mut prepare_locks = Vec::new(); + for (index, item) in items.iter().enumerate() { + if item.reason != OwnerReclaimReason::MasterAllocationCapacity { + continue; } - OwnerReclaimBacking::UnindexedAllocation => { - unreachable!("unindexed allocations must be reclaimed entirely on the master") + let controls = inner.owner_key_control.lock_key(&item.key); + let Some(OwnerReclaimRecord::Prepared(prepared)) = controls + .get(&item.key) + .and_then(|state| state.reclaim.as_ref()) + else { + continue; + }; + if prepared.item != *item { + continue; } - OwnerReclaimBacking::CommittedSlot { - grant_id, - slot_index, - slot_size, - } => { - let (actual_slot_size, actual_grant_id, actual_slot_index) = memory_info - .take_local_reserve_resident_slot_ref() - .expect("committed-slot reclaim must carry a local-reserve slot"); - assert_eq!(actual_slot_size, *slot_size); - assert_eq!(actual_grant_id, *grant_id); - assert_eq!(actual_slot_index, *slot_index); + if prepared.ssd_prepare_complete { + backing_lens[index] = prepared.ssd_backing.as_ref().map(|backing| backing.len); + continue; + } + prepare_locks.push((item.key.clone(), index, prepared.ssd_prepare_lock.clone())); + } + prepare_locks.sort_by(|left, right| left.0.cmp(&right.0)); + debug_assert!( + prepare_locks + .windows(2) + .all(|window| window[0].0 != window[1].0) + ); + let mut prepare_guards = Vec::with_capacity(prepare_locks.len()); + for (_, _, lock) in &prepare_locks { + prepare_guards.push(lock.clone().lock_owned().await); + } + + let mut sources = Vec::new(); + let mut source_indices = Vec::new(); + let mut source_holders = Vec::new(); + for (_, index, _) in &prepare_locks { + let item = &items[*index]; + let controls = inner.owner_key_control.lock_key(&item.key); + let Some(OwnerReclaimRecord::Prepared(prepared)) = controls + .get(&item.key) + .and_then(|state| state.reclaim.as_ref()) + else { + continue; + }; + if prepared.item != *item { + continue; + } + if prepared.ssd_prepare_complete { + backing_lens[*index] = prepared.ssd_backing.as_ref().map(|backing| backing.len); + continue; + } + let (addr, len, holder) = match &prepared.source { + OwnerPreparedReclaimSource::Indexed { cached_info, .. } => { + let holder = cached_info.mem_holder.clone(); + (holder.addr, u64::from(holder.len), Some(holder)) + } + OwnerPreparedReclaimSource::UnindexedAllocation { addr, len } => (*addr, *len, None), + }; + sources.push(crate::kv_ssd_storage::KvSsdPersistSource { + key: item.key.clone(), + put_id: item.put_id, + addr, + len, + }); + source_indices.push(*index); + source_holders.push(holder); + } + + let persisted = if sources.is_empty() { + Vec::new() + } else { + match inner.persist_local_kvs_to_ssd(&sources).await { + Ok(results) => results, + Err(err) => { + tracing::warn!( + items = sources.len(), + error = %err, + "master-capacity SSD batch validation failed; continuing DRAM reclaim" + ); + sources + .iter() + .map(|_| None) + .collect::>() + .into_iter() + .map(Ok) + .collect() + } + } + }; + drop(source_holders); + + let mut discard = Vec::new(); + for ((index, source), outcome) in source_indices + .into_iter() + .zip(sources.into_iter()) + .zip(persisted.into_iter()) + { + let item = &items[index]; + let mut persist_guard = match outcome { + Ok(Some(guard)) => Some(guard), + Ok(None) => None, + Err(err) => { + tracing::warn!( + key = item.key, + put_time_ms = item.put_id.0, + put_version = item.put_id.1, + epoch = item.epoch, + len = source.len, + error = %err, + "master-capacity victim SSD write-back failed; continuing DRAM reclaim" + ); + None + } + }; + let attached = { + let mut controls = inner.owner_key_control.lock_key(&item.key); + match controls + .get_mut(&item.key) + .and_then(|state| state.reclaim.as_mut()) + { + Some(OwnerReclaimRecord::Prepared(prepared)) if prepared.item == *item => { + if prepared.ssd_prepare_complete { + Some(prepared.ssd_backing.as_ref().map(|backing| backing.len)) + } else { + prepared.ssd_prepare_complete = true; + if let Some(guard) = persist_guard.take() { + prepared.ssd_backing = Some(OwnerPreparedSsdBacking { + len: source.len, + _persist_guard: guard, + }); + Some(Some(source.len)) + } else { + Some(None) + } + } + } + _ => None, + } + }; + match attached { + Some(len) => backing_lens[index] = len, + None => { + let should_discard = persist_guard.is_some(); + drop(persist_guard); + if should_discard { + discard.push((item.key.clone(), item.put_id)); + } + } + } + } + drop(prepare_guards); + for (key, put_id) in discard { + inner.discard_local_ssd_replica(&key, put_id).await; + } + backing_lens +} - inner - .owner_release_local_reserve_committed_resident_slot( - actual_slot_size, - actual_grant_id, - actual_slot_index, +fn release_prepared_backing_now(inner: &ClientKvApiInner, prepared: OwnerPreparedReclaim) { + match prepared.source { + OwnerPreparedReclaimSource::Indexed { cached_info, .. } => { + let mut memory_info = Arc::try_unwrap(cached_info.mem_holder).unwrap_or_else(|_| { + panic!( + "owner reclaim prepared memory unexpectedly gained a holder: key={} epoch={}", + prepared.item.key, prepared.item.epoch ) - .expect("owner reclaim committed resident slot release must succeed"); + }); + match &prepared.item.backing { + OwnerReclaimBacking::Allocation => { + assert!( + memory_info.local_reserve_resident_slot_ref().is_none(), + "allocation reclaim must not carry a local-reserve slot" + ); + } + OwnerReclaimBacking::UnindexedAllocation { .. } => { + unreachable!("indexed reclaim source cannot name an unindexed Allocation") + } + OwnerReclaimBacking::CommittedSlot { + grant_id, + slot_index, + slot_size, + } => { + let (actual_slot_size, actual_grant_id, actual_slot_index) = memory_info + .take_local_reserve_resident_slot_ref() + .expect("committed-slot reclaim must carry a local-reserve slot"); + assert_eq!(actual_slot_size, *slot_size); + assert_eq!(actual_grant_id, *grant_id); + assert_eq!(actual_slot_index, *slot_index); + + inner + .owner_release_local_reserve_committed_resident_slot( + actual_slot_size, + actual_grant_id, + actual_slot_index, + ) + .expect("owner reclaim committed resident slot release must succeed"); + } + } + drop(memory_info); + } + OwnerPreparedReclaimSource::UnindexedAllocation { .. } => { + assert!(matches!( + prepared.item.backing, + OwnerReclaimBacking::UnindexedAllocation { .. } + )); + // The master route still owns the Allocation. It is removed only after this Commit + // response, which releases the physical bytes on the master side. } } - drop(memory_info); } fn reclaim_release_fence_is_intact( @@ -287,6 +542,7 @@ fn reclaim_release_fence_is_intact( ) && state.local_puts == 0 && state.external_pending_puts == 0 && state.remote_put.is_none() + && state.local_ssd_put.is_none() && state.source_eviction_selection.is_none() && state.local_access_fence.is_some() } @@ -419,75 +675,118 @@ mod tests { } } -fn abort_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclaimItemResp { +struct AbortOneResult { + response: OwnerReclaimItemResp, + discard_ssd: bool, +} + +fn abort_one_fenced(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> AbortOneResult { let mut controls = inner.owner_key_control.lock_key(&item.key); let Some(state) = controls.get_mut(&item.key) else { - return item_resp( - item, - OwnerReclaimItemState::Aborted, - "owner reclaim was already absent", - ); + return AbortOneResult { + response: item_resp( + item, + OwnerReclaimItemState::Aborted, + "owner reclaim was already absent", + ), + discard_ssd: false, + }; }; let Some(record) = state.reclaim.take() else { - return item_resp( - item, - OwnerReclaimItemState::Aborted, - "owner reclaim was already absent", - ); + return AbortOneResult { + response: item_resp( + item, + OwnerReclaimItemState::Aborted, + "owner reclaim was already absent", + ), + discard_ssd: false, + }; }; match record { OwnerReclaimRecord::Prepared(prepared) if prepared.item == *item => { - let replaced = inner - .get_cached_info - .insert(item.key.clone(), prepared.cached_info); - assert!( - replaced.is_none(), - "owner reclaim abort must restore an empty local index slot" - ); - if let Some(snapshot) = prepared.local_snapshot { - let replaced = inner.local_snapshot_info.insert(item.key.clone(), snapshot); - assert!( - replaced.is_none(), - "owner reclaim abort must restore an empty local snapshot slot" - ); - } + let OwnerPreparedReclaim { + source, + ssd_backing, + .. + } = prepared; + let detail = match source { + OwnerPreparedReclaimSource::Indexed { + cached_info, + local_snapshot, + } => { + let replaced = inner.get_cached_info.insert(item.key.clone(), cached_info); + assert!( + replaced.is_none(), + "owner reclaim abort must restore an empty local index slot" + ); + if let Some(snapshot) = local_snapshot { + let replaced = inner.local_snapshot_info.insert(item.key.clone(), snapshot); + assert!( + replaced.is_none(), + "owner reclaim abort must restore an empty local snapshot slot" + ); + } + "owner local index fence rolled back" + } + OwnerPreparedReclaimSource::UnindexedAllocation { .. } => { + "master-owned Allocation source fence rolled back" + } + }; state.finish_local_access_fence(); if state.is_idle() { controls.remove(&item.key); } - item_resp( - item, - OwnerReclaimItemState::Aborted, - "owner local index fence rolled back", - ) + AbortOneResult { + response: item_resp(item, OwnerReclaimItemState::Aborted, detail), + discard_ssd: ssd_backing.is_some(), + } } OwnerReclaimRecord::Releasing(releasing) if releasing == *item => { state.reclaim = Some(OwnerReclaimRecord::Releasing(releasing)); - item_resp( - item, - OwnerReclaimItemState::Busy, - "owner slot release is already in progress and cannot be aborted", - ) + AbortOneResult { + response: item_resp( + item, + OwnerReclaimItemState::Busy, + "owner slot release is already in progress and cannot be aborted", + ), + discard_ssd: false, + } } OwnerReclaimRecord::Committed(committed) if committed == *item => { state.reclaim = Some(OwnerReclaimRecord::Committed(committed)); - item_resp( - item, - OwnerReclaimItemState::Committed, - "owner slot was already committed and cannot be restored", - ) + AbortOneResult { + response: item_resp( + item, + OwnerReclaimItemState::Committed, + "owner slot was already committed and cannot be restored", + ), + discard_ssd: false, + } } other => { state.reclaim = Some(other); - item_resp( - item, - OwnerReclaimItemState::Stale, - "owner reclaim epoch or slot identity changed", - ) + AbortOneResult { + response: item_resp( + item, + OwnerReclaimItemState::Stale, + "owner reclaim epoch or slot identity changed", + ), + discard_ssd: false, + } } } } +async fn abort_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclaimItemResp { + let outcome = abort_one_fenced(inner, item); + if outcome.discard_ssd { + inner + .discard_local_ssd_replica(&item.key, item.put_id) + .await; + } + outcome.response +} + fn finalize_one(inner: &ClientKvApiInner, item: &OwnerReclaimItem) -> OwnerReclaimItemResp { let mut controls = inner.owner_key_control.lock_key(&item.key); let Some(state) = controls.get_mut(&item.key) else { @@ -595,17 +894,55 @@ pub async fn handle_batch_owner_reclaim( } let inner = view.client_kv_api().inner(); let phase = req.serialize_part.phase; - let items = req - .serialize_part - .items - .iter() - .map(|item| match phase { - OwnerReclaimPhase::Prepare => prepare_one(inner, item), - OwnerReclaimPhase::Commit => commit_one(inner, item), - OwnerReclaimPhase::Abort => abort_one(inner, item), - OwnerReclaimPhase::Finalize => finalize_one(inner, item), - }) - .collect::>(); + let items = match phase { + OwnerReclaimPhase::Prepare => { + let mut responses = req + .serialize_part + .items + .iter() + .map(|item| prepare_one(inner, item)) + .collect::>(); + let prepared_indices = responses + .iter() + .enumerate() + .filter_map(|(index, response)| { + (response.state == OwnerReclaimItemState::Prepared).then_some(index) + }) + .collect::>(); + for indices in prepared_indices.chunks(crate::kv_ssd_storage::MAX_PERSIST_BATCH_ITEMS) { + let batch = indices + .iter() + .map(|index| req.serialize_part.items[*index].clone()) + .collect::>(); + let persisted = persist_prepared_reclaim_batch_to_ssd(inner, &batch).await; + for (index, ssd_backing_len) in indices.iter().copied().zip(persisted) { + responses[index].ssd_backing_len = ssd_backing_len; + } + } + responses + } + OwnerReclaimPhase::Commit => req + .serialize_part + .items + .iter() + .map(|item| commit_one(inner, item)) + .collect(), + OwnerReclaimPhase::Abort => { + futures::future::join_all( + req.serialize_part + .items + .iter() + .map(|item| abort_one(inner, item)), + ) + .await + } + OwnerReclaimPhase::Finalize => req + .serialize_part + .items + .iter() + .map(|item| finalize_one(inner, item)) + .collect(), + }; let prepared = items .iter() .filter(|item| item.state == OwnerReclaimItemState::Prepared) @@ -618,6 +955,14 @@ pub async fn handle_batch_owner_reclaim( .iter() .filter(|item| item.state == OwnerReclaimItemState::Finalized) .count(); + let ssd_prepared = items + .iter() + .filter(|item| item.ssd_backing_len.is_some()) + .count(); + let ssd_prepared_bytes = items + .iter() + .filter_map(|item| item.ssd_backing_len) + .fold(0_u64, u64::saturating_add); let busy_or_stale = items .iter() .filter(|item| { @@ -641,12 +986,14 @@ pub async fn handle_batch_owner_reclaim( let mut rejection_reason_counts = rejection_reason_counts.into_iter().collect::>(); rejection_reason_counts.sort_by(|a, b| a.0.cmp(&b.0)); tracing::info!( - "owner reclaim phase completed: phase={:?} items={} prepared={} committed={} finalized={} busy_or_stale={} rejection_reasons={:?}", + "owner reclaim phase completed: phase={:?} items={} prepared={} committed={} finalized={} ssd_prepared={} ssd_prepared_bytes={} busy_or_stale={} rejection_reasons={:?}", phase, items.len(), prepared, committed, finalized, + ssd_prepared, + ssd_prepared_bytes, busy_or_stale, rejection_reason_counts ); diff --git a/fluxon_rs/fluxon_kv/src/cluster_manager/mod.rs b/fluxon_rs/fluxon_kv/src/cluster_manager/mod.rs index 97a5758..b563d5a 100644 --- a/fluxon_rs/fluxon_kv/src/cluster_manager/mod.rs +++ b/fluxon_rs/fluxon_kv/src/cluster_manager/mod.rs @@ -5,6 +5,8 @@ pub use fluxon_commu::{ META_KEY_SHARED_STORAGE_NODE_ID, META_KEY_SHARED_STORAGE_NODE_START_TIME, }; +pub(crate) const META_KEY_KV_SSD_STORAGE: &str = "kv_ssd_storage"; + pub mod app_logic_ext; #[cfg(test)] diff --git a/fluxon_rs/fluxon_kv/src/config.rs b/fluxon_rs/fluxon_kv/src/config.rs index 0e12327..3634c63 100644 --- a/fluxon_rs/fluxon_kv/src/config.rs +++ b/fluxon_rs/fluxon_kv/src/config.rs @@ -97,6 +97,23 @@ pub enum SideTransferRole { Worker, } +/// Experimental source ordering for an external planned Get when SSD routes +/// are present. The default preserves the sealed r89 behavior so a new +/// release does not silently change an existing baseline. +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)] +#[serde(rename_all = "snake_case")] +pub enum SsdReadSourcePolicy { + /// Any memory source wins over any SSD source; within a tier a remote + /// source wins over the requester-local owner. This is the r89 order. + #[default] + LegacyRemoteFirst, + /// Treat SSD as a requester-local tier, never as a cross-node source. + /// The eligible order is local memory, local SSD, then remote memory. + /// A remote owner's SSD route is deliberately excluded rather than used + /// as a fallback. + LocalSsdOnlyFirst, +} + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(deny_unknown_fields)] pub struct OwnerLocalReserveExpectedCapacity { @@ -142,6 +159,8 @@ pub struct TestSpecConfig { pub short_circuit_put_payload_path: bool, #[serde(default)] pub skip_put_end_commit: bool, + #[serde(default)] + pub ssd_read_source_policy: SsdReadSourcePolicy, #[serde(default, skip_serializing_if = "Option::is_none")] pub owner_local_reserve_soft_wait_timeout_ms: Option, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -192,6 +211,7 @@ impl Default for TestSpecConfig { prefer_local_placement: false, short_circuit_put_payload_path: false, skip_put_end_commit: false, + ssd_read_source_policy: SsdReadSourcePolicy::default(), owner_local_reserve_soft_wait_timeout_ms: None, owner_local_reserve_hard_timeout_ms: None, owner_local_reserve_expected_capacity: None, @@ -891,6 +911,19 @@ pub struct FluxonKvSpecYaml { pub share_mem_path: String, #[serde(skip_serializing_if = "Option::is_none")] pub large_file_paths: Option, + /// Optional per-owner SSD capacity. When present, it must contain one + /// value matching the single local `large_file_paths` root. + #[serde(skip_serializing_if = "Option::is_none")] + pub large_limit_size: Option>>, + /// Optional sustained SSD write admission rate. This is a load-shedding + /// limit, not a queue: owner-local victims beyond the available budget are + /// reclaimed without an SSD copy. + #[serde(skip_serializing_if = "Option::is_none")] + pub ssd_write_rate_limit_bytes_per_sec: Option, + /// Maximum immediately admissible SSD bytes. It must be paired with + /// `ssd_write_rate_limit_bytes_per_sec`. + #[serde(skip_serializing_if = "Option::is_none")] + pub ssd_write_burst_bytes: Option, #[serde(skip_serializing_if = "Option::is_none")] pub p2p_listen_port: Option, #[serde(skip_serializing_if = "Option::is_none")] @@ -903,6 +936,13 @@ pub struct FluxonKvSpecYaml { #[serde(transparent)] pub struct LargeFilePathsYaml(pub Vec); +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct KvSsdStorageConfig { + pub limit_bytes: u64, + pub write_rate_limit_bytes_per_sec: Option, + pub write_burst_bytes: Option, +} + #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct RedisCompatConfigYaml { @@ -1029,6 +1069,14 @@ impl LargeFilePaths { "fluxon fs disk cache", ) } + + pub fn kv_ssd_storage_root(&self, cluster_name: &str, instance_key: &str) -> KvResult { + let relative_dir = PathBuf::from(format!( + "{cluster_name}_cluster_kv_ssd_storage/{}", + crate::kv_ssd_storage::safe_path_component(instance_key) + )); + self.resolve_preferred_root_subdir(&relative_dir, "kv ssd storage") + } } /// KV client backend types supported by the system @@ -1051,6 +1099,7 @@ pub struct ClientConfig { pub fluxonkv_spec: FluxonKvSpec, pub share_mem_path: String, // Mandatory shared bundle path pub large_file_paths: LargeFilePaths, // Mandatory large-file roots for logs and caches + pub ssd_storage: Option, pub test_spec_config: TestSpecConfig, } @@ -1398,6 +1447,13 @@ impl ClientConfigYaml { } .into_kverror()); } + if self.fluxonkv_spec.large_limit_size.is_some() { + return Err(ConfigError::InvalidClientConfig { + detail: "fluxonkv_spec.large_limit_size is forbidden in zero-contribution mode" + .to_string(), + } + .into_kverror()); + } } // Preserve historical behavior for configs that omit `protocol`, but allow @@ -1576,6 +1632,81 @@ impl ClientConfigYaml { } }; + let ssd_write_rate_limit_bytes_per_sec = + self.fluxonkv_spec.ssd_write_rate_limit_bytes_per_sec; + let ssd_write_burst_bytes = self.fluxonkv_spec.ssd_write_burst_bytes; + let write_limit = match (ssd_write_rate_limit_bytes_per_sec, ssd_write_burst_bytes) { + (None, None) => None, + (Some(rate), Some(burst)) if rate > 0 && burst > 0 => Some((rate, burst)), + (Some(_), Some(_)) => { + return Err(ConfigError::InvalidClientConfig { + detail: "fluxonkv_spec SSD write rate and burst must both be positive" + .to_string(), + } + .into_kverror()); + } + _ => { + return Err(ConfigError::InvalidClientConfig { + detail: "fluxonkv_spec.ssd_write_rate_limit_bytes_per_sec and ssd_write_burst_bytes must be configured together" + .to_string(), + } + .into_kverror()); + } + }; + + let ssd_storage = if is_external { + if write_limit.is_some() { + return Err(ConfigError::InvalidClientConfig { + detail: "SSD write admission is only valid on owner configs".to_string(), + } + .into_kverror()); + } + None + } else { + match std::mem::take(&mut self.fluxonkv_spec.large_limit_size) { + None | Some(YamlNullable::Null) => { + if write_limit.is_some() { + return Err(ConfigError::InvalidClientConfig { + detail: "SSD write admission requires fluxonkv_spec.large_limit_size" + .to_string(), + } + .into_kverror()); + } + None + } + Some(YamlNullable::Value(limits)) => { + if large_file_paths.paths.len() != 1 || limits.len() != 1 { + return Err(ConfigError::InvalidClientConfig { + detail: format!( + "SSD-enabled owners require exactly one local large_file_paths root and one large_limit_size value: roots={} limits={}", + large_file_paths.paths.len(), + limits.len() + ), + } + .into_kverror()); + } + let limit_bytes = limits[0]; + if limit_bytes < crate::kv_ssd_storage::MIN_CAPACITY_BYTES { + return Err(ConfigError::InvalidClientConfig { + detail: format!( + "fluxonkv_spec.large_limit_size[0] must be at least {} bytes", + crate::kv_ssd_storage::MIN_CAPACITY_BYTES + ), + } + .into_kverror()); + } + let (write_rate_limit_bytes_per_sec, write_burst_bytes) = write_limit + .map(|(rate, burst)| (Some(rate), Some(burst))) + .unwrap_or((None, None)); + Some(KvSsdStorageConfig { + limit_bytes, + write_rate_limit_bytes_per_sec, + write_burst_bytes, + }) + } + } + }; + Ok(ClientConfig { cluster_name: fluxonkv_spec.cluster_name.clone(), etcd_addresses_raw, @@ -1588,6 +1719,7 @@ impl ClientConfigYaml { fluxonkv_spec, share_mem_path, large_file_paths, + ssd_storage, test_spec_config, }) } @@ -2264,6 +2396,114 @@ fluxonkv_spec: ); } + #[test] + fn owner_ssd_config_requires_one_local_root_and_one_capacity() { + let valid = ClientConfigYaml::from_str( + r#" +instance_key: test_ssd_owner +contribute_to_cluster_pool_size: + dram: 16777216 + vram: {} +fluxonkv_spec: + etcd_addresses: ["127.0.0.1:2379"] + cluster_name: test_cluster + share_mem_path: /mnt/nvme0/mjq_build/fluxon_config_ssd_share + large_file_paths: [/mnt/nvme0/mjq_build/fluxon_config_ssd_local] + large_limit_size: [67108864] + ssd_write_rate_limit_bytes_per_sec: 268435456 + ssd_write_burst_bytes: 67108864 + sub_cluster: rack-a +"#, + ) + .unwrap() + .verify() + .unwrap(); + assert_eq!( + valid.ssd_storage.as_ref().map(|ssd| ssd.limit_bytes), + Some(crate::kv_ssd_storage::MIN_CAPACITY_BYTES) + ); + assert_eq!( + valid + .ssd_storage + .as_ref() + .and_then(|ssd| ssd.write_rate_limit_bytes_per_sec), + Some(268435456) + ); + assert_eq!( + valid + .ssd_storage + .as_ref() + .and_then(|ssd| ssd.write_burst_bytes), + Some(67108864) + ); + + let multiple_roots = ClientConfigYaml::from_str( + r#" +instance_key: test_ssd_owner +contribute_to_cluster_pool_size: + dram: 16777216 + vram: {} +fluxonkv_spec: + etcd_addresses: ["127.0.0.1:2379"] + cluster_name: test_cluster + share_mem_path: /mnt/nvme0/mjq_build/fluxon_config_ssd_share + large_file_paths: + - /mnt/nvme0/mjq_build/fluxon_config_ssd_local_a + - /mnt/nvme0/mjq_build/fluxon_config_ssd_local_b + large_limit_size: [67108864] + sub_cluster: rack-a +"#, + ) + .unwrap() + .verify() + .unwrap_err(); + assert!( + multiple_roots + .to_string() + .contains("SSD-enabled owners require exactly one local large_file_paths root") + ); + + let too_small = ClientConfigYaml::from_str( + r#" +instance_key: test_ssd_owner +contribute_to_cluster_pool_size: + dram: 16777216 + vram: {} +fluxonkv_spec: + etcd_addresses: ["127.0.0.1:2379"] + cluster_name: test_cluster + share_mem_path: /mnt/nvme0/mjq_build/fluxon_config_ssd_share + large_file_paths: [/mnt/nvme0/mjq_build/fluxon_config_ssd_local] + large_limit_size: [67108863] + sub_cluster: rack-a +"#, + ) + .unwrap() + .verify() + .unwrap_err(); + assert!(too_small.to_string().contains("must be at least 67108864")); + } + + #[test] + fn zero_contribution_rejects_owner_ssd_capacity() { + let cfg = ClientConfigYaml::from_str( + r#" +instance_key: test_external +fluxonkv_spec: + cluster_name: test_cluster + share_mem_path: /mnt/nvme0/mjq_build/fluxon_config_ssd_external + large_limit_size: [67108864] +"#, + ) + .unwrap(); + assert!( + cfg.verify() + .unwrap_err() + .to_string() + .contains("large_limit_size is forbidden in zero-contribution mode") + ); + } + #[test] fn large_file_paths_prefers_first_usable_root() { let tempdir = new_test_dir("fluxon_large_paths_prefers_first_usable_root"); diff --git a/fluxon_rs/fluxon_kv/src/external_client_api/external_client_test.rs b/fluxon_rs/fluxon_kv/src/external_client_api/external_client_test.rs index ed9863e..e1d4162 100644 --- a/fluxon_rs/fluxon_kv/src/external_client_api/external_client_test.rs +++ b/fluxon_rs/fluxon_kv/src/external_client_api/external_client_test.rs @@ -94,6 +94,7 @@ fn new_client_config( large_file_paths: LargeFilePaths { paths: vec![format!("{}_large", shm_path)], }, + ssd_storage: None, test_spec_config: TestSpecConfig::default(), } } @@ -136,6 +137,7 @@ fn new_zero_contribution_client_config( }, share_mem_path: shm_path.to_string(), large_file_paths: LargeFilePaths { paths: Vec::new() }, + ssd_storage: None, test_spec_config: TestSpecConfig::default(), } } diff --git a/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs b/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs index 5af3351..d984e05 100644 --- a/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs +++ b/fluxon_rs/fluxon_kv/src/external_client_api/mod.rs @@ -130,9 +130,13 @@ pub struct ExternalGpuGetStartResp { pub struct ExternalGetPlanResp { pub handle: u64, pub raw_prefix_hit_len: usize, + /// Prefix that can be executed by the mixed GPU path. CPU-backed sources + /// inside this prefix remain holder/H2D sources; only indices listed in + /// `gpu_remote_indices` consume GPU destinations. pub gpu_raw_prefix_hit_len: usize, - /// Original key positions that need remote GPU destinations. Owner-local - /// positions remain CPU-backed and are absent from this vector. + /// Original key positions that can bind remote GPU destinations. Local + /// DRAM, requester-local SSD, and other CPU-only positions remain + /// holder/H2D sources and are absent from this vector. pub gpu_remote_indices: Vec, } @@ -177,27 +181,30 @@ fn external_get_plan_raw_prefixes_from_statuses( statuses: impl IntoIterator, ) -> (usize, usize) { let mut cpu_prefix = 0usize; - let mut gpu_prefix = 0usize; - let mut gpu_prefix_open = true; - for (hit, gpu_eligible) in statuses { + for (hit, _gpu_eligible) in statuses { if !hit { break; } cpu_prefix += 1; - if gpu_prefix_open && gpu_eligible { - gpu_prefix += 1; - } else { - gpu_prefix_open = false; - } } - (cpu_prefix, gpu_prefix) + // The GPU execution path is mixed: CPU-only sources are materialized as + // holders while later eligible remote-memory sources still bind GPU + // destinations. Therefore one CPU-only hit no longer truncates the plan. + (cpu_prefix, cpu_prefix) } #[derive(Clone, Debug)] enum ExternalGpuGetTerminal { - Completed, - Revoked { transfer_error: Option }, - Failed { detail: String }, + Completed { + planned_cpu_items: Vec, + planned_cpu_owner_start_time: Option, + }, + Revoked { + transfer_error: Option, + }, + Failed { + detail: String, + }, } #[derive(Clone, Debug)] @@ -238,6 +245,7 @@ struct PendingExternalGpuGet { atomic_group_lens: Vec, value_ptrs: Vec, local_holders: Vec<(usize, Arc)>, + planned_cpu_sources: Vec<(usize, String)>, cancel_requested: Arc, transfer_started_at: Instant, terminal_rx: watch::Receiver>, @@ -503,7 +511,7 @@ mod inline_external_get_start_tests { external_get_plan_raw_prefixes_from_statuses, external_gpu_transfer_plan_geometry_is_valid, inline_external_get_tail_holder_ids, observe_external_gpu_get_consume_timing, validate_external_local_holder_geometry, validate_inline_external_get_owner_generation, - validate_inline_external_get_start_plan, + validate_inline_external_get_start_plan, validate_mixed_planned_cpu_terminal, }; use crate::client_kv_api::msg_pack::ExternalBatchGetItemResp; use crate::master_kv_router::msg_pack::{BatchGetPlanItemResp, BatchGetStartItemResp}; @@ -596,6 +604,29 @@ mod inline_external_get_start_tests { ); } + #[test] + fn mixed_planned_cpu_terminal_requires_exact_owner_mapping() { + let items = vec![inline_hit(1), inline_hit(2)]; + assert!( + validate_mixed_planned_cpu_terminal(&items, 2, Some(17), 17, 0x10_000, 0x10_000,) + .is_ok() + ); + assert!( + validate_mixed_planned_cpu_terminal(&items, 1, Some(17), 17, 0x10_000, 0x10_000) + .is_err() + ); + assert!( + validate_mixed_planned_cpu_terminal(&items, 2, None, 17, 0x10_000, 0x10_000).is_err() + ); + assert!( + validate_mixed_planned_cpu_terminal(&items, 2, Some(16), 17, 0x10_000, 0x10_000,) + .is_err() + ); + assert!( + validate_mixed_planned_cpu_terminal(&items, 2, Some(17), 17, 0x10_000, 4096).is_err() + ); + } + #[test] fn inline_partial_consume_returns_only_tail_holder_ids() { let items = vec![inline_hit(11), inline_hit(12), inline_hit(13)]; @@ -635,7 +666,7 @@ mod inline_external_get_start_tests { } #[test] - fn gpu_prefix_stops_without_shortening_the_cpu_plan() { + fn mixed_gpu_prefix_keeps_cpu_only_sources_and_later_gpu_sources() { let items = vec![ BatchGetPlanItemResp { error_code: OK, @@ -653,7 +684,7 @@ mod inline_external_get_start_tests { ..Default::default() }, ]; - assert_eq!(external_get_plan_raw_prefixes(&items), (3, 1)); + assert_eq!(external_get_plan_raw_prefixes(&items), (3, 3)); } #[test] @@ -668,15 +699,15 @@ mod inline_external_get_start_tests { ]), (3, 3) ); - // A remote source that cannot bind a GPU sink stops only the mixed - // GPU prefix; the CPU plan can still consume later local pages. + // A CPU-only source is materialized through the existing planned CPU + // holder path and does not hide a later GPU-eligible source. assert_eq!( external_get_plan_raw_prefixes_from_statuses([ (true, true), (true, false), (true, true), ]), - (3, 1) + (3, 3) ); assert_eq!( external_get_plan_raw_prefixes_from_statuses([ @@ -1220,9 +1251,17 @@ fn release_planned_cpu_response_holders( inner: &ExternalInner, response: &ExternalExecutePlannedGetResp, owner_start_time: i64, +) { + release_planned_cpu_item_holders(inner, &response.items, owner_start_time); +} + +fn release_planned_cpu_item_holders( + inner: &ExternalInner, + items: &[ExternalBatchGetItemResp], + owner_start_time: i64, ) { let external_client_id = inner.view.cluster_manager().get_self_info().id; - for holder_id in response.items.iter().filter_map(|item| { + for holder_id in items.iter().filter_map(|item| { item.external_memholder_info .as_ref() .map(|info| info.holder_id) @@ -1241,6 +1280,84 @@ fn release_planned_cpu_response_holders( } } +fn release_optional_planned_cpu_item_holders( + inner: &ExternalInner, + items: &[ExternalBatchGetItemResp], + owner_start_time: Option, +) { + if items.is_empty() { + return; + } + let Some(owner_start_time) = owner_start_time else { + tracing::error!( + items = items.len(), + "mixed Get terminal lost the owner generation needed to release CPU holders" + ); + return; + }; + release_planned_cpu_item_holders(inner, items, owner_start_time); +} + +fn validate_mixed_planned_cpu_terminal( + items: &[ExternalBatchGetItemResp], + expected_items: usize, + owner_start_time: Option, + current_owner_start_time: i64, + base_ptr: u64, + mapped_len: u64, +) -> KvResult { + if items.len() != expected_items { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "mixed Get planned CPU terminal length mismatch: expected={} got={}", + expected_items, + items.len() + ), + })); + } + let owner_start_time = owner_start_time.ok_or_else(|| { + KvError::Api(ApiError::Unknown { + detail: "mixed Get planned CPU terminal omitted its owner generation".to_string(), + }) + })?; + validate_inline_external_get_owner_generation(owner_start_time, current_owner_start_time)?; + for (index, item) in items.iter().enumerate() { + if item.error_code != OK { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "mixed Get planned CPU item failed: index={} error_code={} error_json={}", + index, item.error_code, item.error_json + ), + })); + } + let Some(info) = item.external_memholder_info.as_ref() else { + return Err(KvError::Api(ApiError::Unknown { + detail: format!("mixed Get planned CPU item has no holder: index={index}"), + })); + }; + let end = info + .offset + .checked_add(u64::from(info.len)) + .ok_or_else(|| { + KvError::Api(ApiError::Unknown { + detail: format!( + "mixed Get planned CPU holder range overflow: index={} offset={} len={}", + index, info.offset, info.len + ), + }) + })?; + if end > mapped_len || base_ptr.checked_add(info.offset).is_none() { + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "mixed Get planned CPU holder is outside owner mapping: index={} end={} mapped_len={} base={:#x} offset={}", + index, end, mapped_len, base_ptr, info.offset + ), + })); + } + } + Ok(owner_start_time) +} + fn spawn_uncertain_planned_cpu_get_cleanup( view: ExternalClientApiView, owner: String, @@ -1528,7 +1645,10 @@ async fn run_external_gpu_get_transfer( .master_batch_gpu_get_done(transfer_get_ids) .await { - Ok(()) => ExternalGpuGetTerminal::Completed, + Ok(()) => ExternalGpuGetTerminal::Completed { + planned_cpu_items: Vec::new(), + planned_cpu_owner_start_time: None, + }, Err(err) => ExternalGpuGetTerminal::Failed { detail: format!("GPU Get BatchDone failed: {err}"), }, @@ -1556,6 +1676,104 @@ async fn run_external_gpu_get_transfer_timed( } } +async fn run_external_mixed_gpu_get_transfer_timed( + view: ExternalClientApiView, + plan_handle: u64, + gpu_transfer_items: Vec<(BatchGetStartItemResp, GpuMemoryGuard)>, + planned_cpu_items: Vec<(String, u64)>, + skipped_get_ids: Vec, + transfer_concurrency: usize, + cancel_requested: Arc, +) -> ExternalGpuGetTerminalEvent { + if planned_cpu_items.is_empty() { + return run_external_gpu_get_transfer_timed( + view, + gpu_transfer_items, + skipped_get_ids, + transfer_concurrency, + cancel_requested, + ) + .await; + } + + // The GPU branch owns tail Revoke. The planned CPU branch receives an + // empty tail so every master operation identity is finalized exactly + // once while both source classes still execute concurrently. + let gpu_future = run_external_gpu_get_transfer( + view.clone(), + gpu_transfer_items, + skipped_get_ids, + transfer_concurrency, + cancel_requested.clone(), + ); + let cpu_future = run_external_planned_cpu_get( + view.clone(), + plan_handle, + planned_cpu_items, + Vec::new(), + transfer_concurrency, + cancel_requested, + ); + let (gpu_terminal, cpu_terminal) = futures::future::join(gpu_future, cpu_future).await; + + let outcome = match (gpu_terminal, cpu_terminal) { + ( + ExternalGpuGetTerminal::Completed { .. }, + ExternalPlannedCpuGetTerminal::Completed { + items, + owner_start_time, + }, + ) => ExternalGpuGetTerminal::Completed { + planned_cpu_items: items, + planned_cpu_owner_start_time: Some(owner_start_time), + }, + (gpu_terminal, cpu_terminal) => { + if let ExternalPlannedCpuGetTerminal::Completed { + items, + owner_start_time, + } = &cpu_terminal + { + release_planned_cpu_item_holders( + view.external_client_api().inner(), + items, + *owner_start_time, + ); + } + match (&gpu_terminal, &cpu_terminal) { + ( + ExternalGpuGetTerminal::Failed { detail: gpu_detail }, + ExternalPlannedCpuGetTerminal::Failed { detail: cpu_detail }, + ) => ExternalGpuGetTerminal::Failed { + detail: format!( + "mixed Get GPU and CPU branches failed: gpu={gpu_detail}; cpu={cpu_detail}" + ), + }, + (ExternalGpuGetTerminal::Failed { detail }, _) => ExternalGpuGetTerminal::Failed { + detail: format!("mixed Get GPU branch failed: {detail}"), + }, + (_, ExternalPlannedCpuGetTerminal::Failed { detail }) => { + ExternalGpuGetTerminal::Failed { + detail: format!("mixed Get CPU branch failed: {detail}"), + } + } + (ExternalGpuGetTerminal::Revoked { transfer_error }, _) => { + ExternalGpuGetTerminal::Revoked { + transfer_error: transfer_error.clone(), + } + } + (_, ExternalPlannedCpuGetTerminal::Revoked) => ExternalGpuGetTerminal::Revoked { + transfer_error: Some("mixed Get CPU branch was revoked".to_string()), + }, + _ => unreachable!("mixed Get non-completed branches must fail or revoke"), + } + } + }; + ExternalGpuGetTerminalEvent { + outcome, + terminal_at: Instant::now(), + } +} + impl ExternalClientApi { /// Access inner external-only API. Safe to unwrap in external role. pub fn inner(&self) -> &ExternalInner { @@ -3660,8 +3878,11 @@ impl ExternalInner { .iter() .take(gpu_transferable_len) .enumerate() - .filter_map(|(index, item)| { - matches!(item, PendingExternalGetPlanItem::Remote { .. }).then_some(index) + .filter_map(|(index, item)| match item { + PendingExternalGetPlanItem::Remote { plan, .. } if plan.gpu_direct_eligible => { + Some(index) + } + _ => None, }) .collect::>(); self.pending_external_get_plan.insert( @@ -3800,6 +4021,8 @@ impl ExternalInner { }) .collect::>(); let mut remote_plans = Vec::with_capacity(destinations.len()); + let mut planned_cpu_items = Vec::new(); + let mut planned_cpu_sources = Vec::new(); let mut local_holders = Vec::new(); let mut value_ptrs = Vec::with_capacity(consume_prefix_len); let mut destination_index = 0usize; @@ -3813,11 +4036,19 @@ impl ExternalInner { value_ptrs.push(holder.addr); local_holders.push((source_index, holder)); } - PendingExternalGetPlanItem::Remote { plan, .. } => { - let destination = &destinations[destination_index]; - value_ptrs.push(destination.addr); - remote_plans.push(plan); - destination_index += 1; + PendingExternalGetPlanItem::Remote { key, plan } => { + if plan.gpu_direct_eligible { + let destination = &destinations[destination_index]; + value_ptrs.push(destination.addr); + remote_plans.push(plan); + destination_index += 1; + } else { + // Filled with the owner-mapped holder pointer after the + // planned CPU branch reaches its terminal. + value_ptrs.push(0); + planned_cpu_sources.push((source_index, key.clone())); + planned_cpu_items.push((key, plan.get_id)); + } } } } @@ -3895,6 +4126,7 @@ impl ExternalInner { atomic_group_lens, value_ptrs, local_holders, + planned_cpu_sources, cancel_requested: cancel_requested.clone(), transfer_started_at, terminal_rx, @@ -3903,9 +4135,11 @@ impl ExternalInner { let view = self.view.clone_view(); let task_view = view.clone(); view.spawn(format!("external_gpu_get_execute_{handle}"), async move { - let terminal = run_external_gpu_get_transfer_timed( + let terminal = run_external_mixed_gpu_get_transfer_timed( task_view, + handle, transfer_items, + planned_cpu_items, skipped_get_ids, transfer_concurrency, cancel_requested, @@ -4213,6 +4447,7 @@ impl ExternalInner { .map(|destination| destination.addr) .collect(), local_holders: Vec::new(), + planned_cpu_sources: Vec::new(), cancel_requested: cancel_requested.clone(), transfer_started_at, terminal_rx, @@ -4269,7 +4504,7 @@ impl ExternalInner { } }; let finish_wait = finish_wait_started_at.elapsed(); - let pending = pending_guard.take(); + let mut pending = pending_guard.take(); let timing = observe_external_gpu_get_consume_timing( pending.transfer_started_at, terminal_event.terminal_at, @@ -4277,15 +4512,24 @@ impl ExternalInner { finish_wait, ); let outcome = match &terminal_event.outcome { - ExternalGpuGetTerminal::Completed => "completed", + ExternalGpuGetTerminal::Completed { .. } => "completed", ExternalGpuGetTerminal::Revoked { .. } => "revoked", ExternalGpuGetTerminal::Failed { .. } => "failed", }; + let local_source_count = pending.local_holders.len(); + let planned_cpu_source_count = pending.planned_cpu_sources.len(); + let gpu_direct_source_count = pending + .transferable_len + .saturating_sub(local_source_count) + .saturating_sub(planned_cpu_source_count); tracing::info!( - "external GPU Get consume lifecycle: handle={} transferred={} consumed={} outcome={} transfer_wall_us={} terminal_before_consume={} terminal_to_consume_us={} finish_wait_us={}", + "external GPU Get consume lifecycle: handle={} transferred={} consumed={} local_sources={} planned_cpu_sources={} gpu_direct_sources={} outcome={} transfer_wall_us={} terminal_before_consume={} terminal_to_consume_us={} finish_wait_us={}", handle, pending.transferable_len, consumed_prefix_len, + local_source_count, + planned_cpu_source_count, + gpu_direct_source_count, outcome, timing.transfer_wall_us, timing.terminal_before_consume, @@ -4293,17 +4537,159 @@ impl ExternalInner { timing.finish_wait_us, ); match terminal_event.outcome { - ExternalGpuGetTerminal::Completed => { + ExternalGpuGetTerminal::Completed { + planned_cpu_items, + planned_cpu_owner_start_time, + } => { assert_eq!(pending.value_ptrs.len(), pending.transferable_len); - if !pending.local_holders.is_empty() { - let (_, current_owner_start_time, _, base_ptr, mapped_len) = - self.wait_current_owner_mapped_range().await?; - validate_external_local_holders_mapping( + let planned_cpu_sources = std::mem::take(&mut pending.planned_cpu_sources); + let cpu_terminal_shape_is_valid = planned_cpu_sources.len() + == planned_cpu_items.len() + && planned_cpu_sources.iter().enumerate().all( + |(source_order, (source_index, _))| { + *source_index < pending.value_ptrs.len() + && pending.value_ptrs[*source_index] == 0 + && source_order.checked_sub(1).is_none_or(|previous_order| { + planned_cpu_sources[previous_order].0 < *source_index + }) + }, + ); + if !cpu_terminal_shape_is_valid { + release_optional_planned_cpu_item_holders( + self, + &planned_cpu_items, + planned_cpu_owner_start_time, + ); + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "mixed Get CPU source/terminal shape mismatch: sources={} items={} values={}", + planned_cpu_sources.len(), + planned_cpu_items.len(), + pending.value_ptrs.len() + ), + })); + } + + let needs_owner_mapping = + !pending.local_holders.is_empty() || !planned_cpu_sources.is_empty(); + let owner_mapping = if needs_owner_mapping { + match self.wait_current_owner_mapped_range().await { + Ok(mapping) => Some(mapping), + Err(err) => { + release_optional_planned_cpu_item_holders( + self, + &planned_cpu_items, + planned_cpu_owner_start_time, + ); + return Err(err); + } + } + } else { + None + }; + if let Some((_, current_owner_start_time, _, base_ptr, mapped_len)) = owner_mapping + { + if let Err(err) = validate_external_local_holders_mapping( &pending.local_holders, current_owner_start_time, base_ptr, mapped_len, - )?; + ) { + release_optional_planned_cpu_item_holders( + self, + &planned_cpu_items, + planned_cpu_owner_start_time, + ); + return Err(err); + } + if !planned_cpu_sources.is_empty() { + let owner_start_time = match validate_mixed_planned_cpu_terminal( + &planned_cpu_items, + planned_cpu_sources.len(), + planned_cpu_owner_start_time, + current_owner_start_time, + base_ptr, + mapped_len, + ) { + Ok(owner_start_time) => owner_start_time, + Err(err) => { + release_optional_planned_cpu_item_holders( + self, + &planned_cpu_items, + planned_cpu_owner_start_time, + ); + return Err(err); + } + }; + for ((source_index, _), item) in + planned_cpu_sources.iter().zip(&planned_cpu_items) + { + if *source_index >= consumed_prefix_len { + let info = item + .external_memholder_info + .as_ref() + .expect("validated mixed CPU item must have a holder"); + if let Err(detail) = self.enqueue_external_delete_ack( + self.view.cluster_manager().get_self_info().id.clone(), + info.holder_id, + owner_start_time, + ) { + release_optional_planned_cpu_item_holders( + self, + &planned_cpu_items, + planned_cpu_owner_start_time, + ); + return Err(KvError::Api(ApiError::Unknown { detail })); + } + } + } + let external_client_id = + self.view.cluster_manager().get_self_info().id.clone(); + for ((source_index, key), item) in planned_cpu_sources + .into_iter() + .zip(planned_cpu_items.iter()) + .take_while(|((source_index, _), _)| { + *source_index < consumed_prefix_len + }) + { + let info = item + .external_memholder_info + .as_ref() + .expect("validated mixed CPU item must have a holder"); + let holder_ptr = base_ptr + .checked_add(info.offset) + .expect("validated mixed CPU holder pointer must not overflow"); + let holder = Arc::new(ExternalMemHolder::new( + info.offset, + holder_ptr, + info.len, + info.holder_id, + key.clone(), + external_client_id.clone(), + self.view.clone(), + owner_start_time, + )); + pending.value_ptrs[source_index] = holder_ptr; + self.key_weak_memholder_index + .insert(key, Arc::downgrade(&holder)); + pending.local_holders.push((source_index, holder)); + } + } + } + if let Some(index) = pending.value_ptrs[..consumed_prefix_len] + .iter() + .position(|pointer| *pointer == 0) + { + release_optional_planned_cpu_item_holders( + self, + &planned_cpu_items, + planned_cpu_owner_start_time, + ); + return Err(KvError::Api(ApiError::Unknown { + detail: format!( + "mixed Get left a consumed source pointer unresolved: index={index}" + ), + })); } let bandwidth_handle = self .view @@ -4354,7 +4740,18 @@ impl ExternalInner { .await? .outcome { - ExternalGpuGetTerminal::Completed | ExternalGpuGetTerminal::Revoked { .. } => Ok(()), + ExternalGpuGetTerminal::Completed { + planned_cpu_items, + planned_cpu_owner_start_time, + } => { + release_optional_planned_cpu_item_holders( + self, + &planned_cpu_items, + planned_cpu_owner_start_time, + ); + Ok(()) + } + ExternalGpuGetTerminal::Revoked { .. } => Ok(()), ExternalGpuGetTerminal::Failed { detail } => { Err(KvError::Api(ApiError::Unknown { detail })) } diff --git a/fluxon_rs/fluxon_kv/src/kv_ssd_storage.rs b/fluxon_rs/fluxon_kv/src/kv_ssd_storage.rs new file mode 100644 index 0000000..d5875a2 --- /dev/null +++ b/fluxon_rs/fluxon_kv/src/kv_ssd_storage.rs @@ -0,0 +1,1360 @@ +use crate::master_kv_router::put::PutIDForAKey; +use crate::rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, KvResult}; +use ::tokio::sync::{Mutex as AsyncMutex, OwnedMutexGuard}; +use foyer::{ + BlockEngineConfig, DeviceBuilder, FsDeviceBuilder, HybridCache, HybridCacheBuilder, + HybridCacheEntry, HybridCachePolicy, PsyncIoEngineConfig, Source, +}; +use parking_lot::Mutex; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; +use std::collections::HashMap; +use std::fs; +use std::path::{Path, PathBuf}; +use std::sync::{ + Arc, + atomic::{AtomicU64, Ordering}, +}; +use std::time::Instant; + +const MEMORY_CAPACITY_BYTES: usize = 1; +const MEMORY_SHARDS: usize = 1; +const BLOCK_SIZE_BYTES: usize = 64 * 1024 * 1024; +const FLUSH_BUFFER_BYTES: usize = BLOCK_SIZE_BYTES; +const SUBMIT_QUEUE_BYTES: usize = 2 * FLUSH_BUFFER_BYTES; +// Thirteen workload-sized values (13 * 4.5 MiB) fit below one 64 MiB block. +// This is an I/O aggregation bound only; every entry keeps an independent +// single-KV generation and result. +pub(crate) const MAX_PERSIST_BATCH_ITEMS: usize = 13; +pub const MIN_CAPACITY_BYTES: u64 = BLOCK_SIZE_BYTES as u64; + +pub fn safe_path_component(raw: &str) -> String { + format!("v1-{}", hex::encode(Sha256::digest(raw.as_bytes()))) +} + +#[derive(Clone, Debug)] +pub struct KvSsdStorageRootLimit { + pub root_dir: PathBuf, + pub limit_bytes: u64, +} + +#[derive(Clone, Debug)] +pub struct KvSsdStorageInit { + pub roots: Vec, + pub write_rate_limit_bytes_per_sec: Option, + pub write_burst_bytes: Option, +} + +#[derive(Clone, Debug, Default)] +pub struct KvSsdStorageDeviceUsage { + pub device: String, + pub capacity_bytes: u64, + pub used_bytes: u64, + pub persist_requests: u64, + pub persist_successes: u64, + pub persist_failures: u64, + pub persist_bytes: u64, + pub persist_duration_us: u64, + pub persist_batch_requests: u64, + pub persist_batch_items: u64, + pub persist_flush_batches: u64, + pub persist_busy_batches: u64, + pub persist_admission_skips: u64, + pub persist_batch_duration_us: u64, + pub write_candidate_items: u64, + pub write_candidate_bytes: u64, + pub write_admitted_items: u64, + pub write_admitted_bytes: u64, + pub write_dropped_items: u64, + pub write_dropped_bytes: u64, + pub write_refunded_items: u64, + pub write_refunded_bytes: u64, + pub load_requests: u64, + pub load_successes: u64, + pub load_misses: u64, + pub load_failures: u64, + pub load_bytes: u64, + pub load_duration_us: u64, + pub memory_hits: u64, + pub disk_hits: u64, + pub outer_hits: u64, + pub removals: u64, +} + +#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +struct KvSsdKey { + key: String, + put_id: PutIDForAKey, +} + +#[derive(Debug)] +struct WriteRateLimiter { + rate_bytes_per_sec: u64, + burst_bytes: u64, + available_bytes: u64, + refill_remainder: u128, + last_refill: Instant, +} + +impl WriteRateLimiter { + fn new(rate_bytes_per_sec: u64, burst_bytes: u64) -> Self { + Self { + rate_bytes_per_sec, + burst_bytes, + available_bytes: burst_bytes, + refill_remainder: 0, + last_refill: Instant::now(), + } + } + + fn refill(&mut self, now: Instant) { + let elapsed_ns = now.duration_since(self.last_refill).as_nanos(); + self.last_refill = now; + if self.available_bytes == self.burst_bytes { + self.refill_remainder = 0; + return; + } + let scaled = elapsed_ns + .saturating_mul(u128::from(self.rate_bytes_per_sec)) + .saturating_add(self.refill_remainder); + let refill = scaled / 1_000_000_000u128; + self.refill_remainder = scaled % 1_000_000_000u128; + let refill = u64::try_from(refill).unwrap_or(u64::MAX); + self.available_bytes = self + .available_bytes + .saturating_add(refill) + .min(self.burst_bytes); + if self.available_bytes == self.burst_bytes { + self.refill_remainder = 0; + } + } + + fn try_consume(&mut self, bytes: u64, now: Instant) -> bool { + self.refill(now); + if bytes > self.available_bytes { + return false; + } + self.available_bytes -= bytes; + true + } +} + +type SsdEntry = HybridCacheEntry>; + +/// Pins a just-persisted entry until the master has published its SSD backing. +pub(crate) struct KvSsdPersistGuard { + _entry: Option, +} + +#[derive(Clone, Debug)] +pub(crate) struct KvSsdPersistSource { + pub key: String, + pub put_id: PutIDForAKey, + pub addr: u64, + pub len: u64, +} + +pub(crate) struct KvSsdPersistCopy { + key: String, + put_id: PutIDForAKey, + data: Vec, +} + +impl KvSsdPersistCopy { + fn len(&self) -> u64 { + u64::try_from(self.data.len()).unwrap_or(u64::MAX) + } +} + +pub(crate) struct KvSsdPersistBatchPermit { + _guard: OwnedMutexGuard<()>, +} + +/// The only owner-local SSD store used by Fluxon KV. +/// +/// DRAM ownership, distributed routing, and Put/Get terminal state remain in +/// their existing modules. This type only persists and materializes bytes for +/// one `(key, put_id)` generation. +#[derive(Debug)] +pub struct KvSsdStorage { + cache: HybridCache>, + root_dir: PathBuf, + capacity_bytes: u64, + write_rate_limiter: Option>, + // Exactly one admitted write batch may own Foyer's global durability + // barrier. New unrelated pressure batches use try_lock and fail open to + // ordinary DRAM reclaim instead of becoming SSD backlog. + persist_batch_gate: Arc>, + entry_lengths: Mutex>, + logical_used_bytes: AtomicU64, + persist_requests: AtomicU64, + persist_successes: AtomicU64, + persist_failures: AtomicU64, + persist_bytes: AtomicU64, + persist_duration_us: AtomicU64, + persist_batch_requests: AtomicU64, + persist_batch_items: AtomicU64, + persist_flush_batches: AtomicU64, + persist_busy_batches: AtomicU64, + persist_admission_skips: AtomicU64, + persist_batch_duration_us: AtomicU64, + write_candidate_items: AtomicU64, + write_candidate_bytes: AtomicU64, + write_admitted_items: AtomicU64, + write_admitted_bytes: AtomicU64, + write_dropped_items: AtomicU64, + write_dropped_bytes: AtomicU64, + write_refunded_items: AtomicU64, + write_refunded_bytes: AtomicU64, + load_requests: AtomicU64, + load_successes: AtomicU64, + load_misses: AtomicU64, + load_failures: AtomicU64, + load_bytes: AtomicU64, + load_duration_us: AtomicU64, + memory_hits: AtomicU64, + disk_hits: AtomicU64, + outer_hits: AtomicU64, + removals: AtomicU64, +} + +impl KvSsdStorage { + pub async fn new(init: KvSsdStorageInit) -> KvResult { + let write_rate_limiter = match (init.write_rate_limit_bytes_per_sec, init.write_burst_bytes) + { + (None, None) => None, + (Some(rate), Some(burst)) if rate > 0 && burst > 0 => { + Some(Mutex::new(WriteRateLimiter::new(rate, burst))) + } + _ => { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: "SSD write rate and burst must be configured together and be positive" + .to_string(), + })); + } + }; + let [root] = init.roots.as_slice() else { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "kv ssd storage currently requires exactly one local root, got {}", + init.roots.len() + ), + })); + }; + if root.limit_bytes < MIN_CAPACITY_BYTES { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "kv ssd capacity must be at least {} bytes, got {}", + BLOCK_SIZE_BYTES, root.limit_bytes + ), + })); + } + let capacity_bytes = usize::try_from(root.limit_bytes).map_err(|_| { + KvError::Api(ApiError::InvalidArgument { + detail: format!("kv ssd capacity does not fit usize: {}", root.limit_bytes), + }) + })?; + + fs::create_dir_all(&root.root_dir) + .map_err(|err| file_error(&root.root_dir, "create root", err))?; + let storage_root = root.root_dir.join("foyer"); + match fs::remove_dir_all(&storage_root) { + Ok(()) => {} + Err(err) if err.kind() == std::io::ErrorKind::NotFound => {} + Err(err) => return Err(file_error(&storage_root, "clear old store", err)), + } + fs::create_dir_all(&storage_root) + .map_err(|err| file_error(&storage_root, "create store", err))?; + + let device = FsDeviceBuilder::new(&storage_root) + .with_capacity(capacity_bytes) + .with_direct(true) + .build() + .map_err(|err| storage_error("build filesystem device", err))?; + let engine = BlockEngineConfig::new(device) + .with_block_size(BLOCK_SIZE_BYTES) + .with_buffer_pool_size(FLUSH_BUFFER_BYTES) + .with_submit_queue_size_threshold(SUBMIT_QUEUE_BYTES); + let cache = HybridCacheBuilder::new() + .with_name("fluxon_kv_ssd") + .with_policy(HybridCachePolicy::WriteOnInsertion) + .with_flush_on_close(false) + .memory(MEMORY_CAPACITY_BYTES) + .with_shards(MEMORY_SHARDS) + .with_weighter(|_key: &KvSsdKey, value: &Vec| value.len()) + .with_filter(|_key: &KvSsdKey, _value: &Vec| false) + .storage() + .with_io_engine_config(PsyncIoEngineConfig::new()) + .with_engine_config(engine) + .build() + .await + .map_err(|err| storage_error("build cache", err))?; + + tracing::info!( + root = %root.root_dir.display(), + capacity_bytes = root.limit_bytes, + write_rate_limit_bytes_per_sec = init.write_rate_limit_bytes_per_sec, + write_burst_bytes = init.write_burst_bytes, + direct_io = true, + "Initialized owner-local KV SSD backing" + ); + + Ok(Self { + cache, + root_dir: root.root_dir.clone(), + capacity_bytes: root.limit_bytes, + write_rate_limiter, + persist_batch_gate: Arc::new(AsyncMutex::new(())), + entry_lengths: Mutex::new(HashMap::new()), + logical_used_bytes: AtomicU64::new(0), + persist_requests: AtomicU64::new(0), + persist_successes: AtomicU64::new(0), + persist_failures: AtomicU64::new(0), + persist_bytes: AtomicU64::new(0), + persist_duration_us: AtomicU64::new(0), + persist_batch_requests: AtomicU64::new(0), + persist_batch_items: AtomicU64::new(0), + persist_flush_batches: AtomicU64::new(0), + persist_busy_batches: AtomicU64::new(0), + persist_admission_skips: AtomicU64::new(0), + persist_batch_duration_us: AtomicU64::new(0), + write_candidate_items: AtomicU64::new(0), + write_candidate_bytes: AtomicU64::new(0), + write_admitted_items: AtomicU64::new(0), + write_admitted_bytes: AtomicU64::new(0), + write_dropped_items: AtomicU64::new(0), + write_dropped_bytes: AtomicU64::new(0), + write_refunded_items: AtomicU64::new(0), + write_refunded_bytes: AtomicU64::new(0), + load_requests: AtomicU64::new(0), + load_successes: AtomicU64::new(0), + load_misses: AtomicU64::new(0), + load_failures: AtomicU64::new(0), + load_bytes: AtomicU64::new(0), + load_duration_us: AtomicU64::new(0), + memory_hits: AtomicU64::new(0), + disk_hits: AtomicU64::new(0), + outer_hits: AtomicU64::new(0), + removals: AtomicU64::new(0), + }) + } + + pub fn root_dir(&self) -> &Path { + &self.root_dir + } + + pub fn usage_snapshot(&self) -> KvSsdStorageDeviceUsage { + KvSsdStorageDeviceUsage { + device: self.root_dir.display().to_string(), + capacity_bytes: self.capacity_bytes, + used_bytes: self + .logical_used_bytes + .load(Ordering::Relaxed) + .min(self.capacity_bytes), + persist_requests: self.persist_requests.load(Ordering::Relaxed), + persist_successes: self.persist_successes.load(Ordering::Relaxed), + persist_failures: self.persist_failures.load(Ordering::Relaxed), + persist_bytes: self.persist_bytes.load(Ordering::Relaxed), + persist_duration_us: self.persist_duration_us.load(Ordering::Relaxed), + persist_batch_requests: self.persist_batch_requests.load(Ordering::Relaxed), + persist_batch_items: self.persist_batch_items.load(Ordering::Relaxed), + persist_flush_batches: self.persist_flush_batches.load(Ordering::Relaxed), + persist_busy_batches: self.persist_busy_batches.load(Ordering::Relaxed), + persist_admission_skips: self.persist_admission_skips.load(Ordering::Relaxed), + persist_batch_duration_us: self.persist_batch_duration_us.load(Ordering::Relaxed), + write_candidate_items: self.write_candidate_items.load(Ordering::Relaxed), + write_candidate_bytes: self.write_candidate_bytes.load(Ordering::Relaxed), + write_admitted_items: self.write_admitted_items.load(Ordering::Relaxed), + write_admitted_bytes: self.write_admitted_bytes.load(Ordering::Relaxed), + write_dropped_items: self.write_dropped_items.load(Ordering::Relaxed), + write_dropped_bytes: self.write_dropped_bytes.load(Ordering::Relaxed), + write_refunded_items: self.write_refunded_items.load(Ordering::Relaxed), + write_refunded_bytes: self.write_refunded_bytes.load(Ordering::Relaxed), + load_requests: self.load_requests.load(Ordering::Relaxed), + load_successes: self.load_successes.load(Ordering::Relaxed), + load_misses: self.load_misses.load(Ordering::Relaxed), + load_failures: self.load_failures.load(Ordering::Relaxed), + load_bytes: self.load_bytes.load(Ordering::Relaxed), + load_duration_us: self.load_duration_us.load(Ordering::Relaxed), + memory_hits: self.memory_hits.load(Ordering::Relaxed), + disk_hits: self.disk_hits.load(Ordering::Relaxed), + outer_hits: self.outer_hits.load(Ordering::Relaxed), + removals: self.removals.load(Ordering::Relaxed), + } + } + + pub async fn close(&self) -> KvResult<()> { + self.cache + .close() + .await + .map_err(|err| storage_error("close", err)) + } + + /// Select at most one bounded durability batch from master-confirmed + /// last-backing candidates. Smaller values win ties because they preserve + /// more independently reusable keys per admitted byte. The decision is + /// immediate: candidates outside the burst/rate budget are returned as + /// false and must be reclaimed without waiting for SSD bandwidth. + pub(crate) fn admit_owner_write_candidates(&self, lengths: &[u64]) -> Vec { + let mut order = (0..lengths.len()).collect::>(); + order.sort_by_key(|index| (lengths[*index], *index)); + let mut admitted = vec![false; lengths.len()]; + let mut admitted_items = 0usize; + let mut admitted_bytes = 0u64; + let now = Instant::now(); + let mut limiter = self + .write_rate_limiter + .as_ref() + .map(|limiter| limiter.lock()); + for index in order { + if admitted_items == MAX_PERSIST_BATCH_ITEMS { + break; + } + let len = lengths[index]; + let allowed = limiter + .as_mut() + .is_none_or(|limiter| limiter.try_consume(len, now)); + if allowed { + admitted[index] = true; + admitted_items += 1; + admitted_bytes = admitted_bytes.saturating_add(len); + } + } + let candidate_bytes = lengths.iter().copied().fold(0u64, u64::saturating_add); + let candidate_items = u64::try_from(lengths.len()).unwrap_or(u64::MAX); + let admitted_items = u64::try_from(admitted_items).unwrap_or(u64::MAX); + let dropped_items = candidate_items.saturating_sub(admitted_items); + let dropped_bytes = candidate_bytes.saturating_sub(admitted_bytes); + self.write_candidate_items + .fetch_add(candidate_items, Ordering::Relaxed); + self.write_candidate_bytes + .fetch_add(candidate_bytes, Ordering::Relaxed); + self.write_admitted_items + .fetch_add(admitted_items, Ordering::Relaxed); + self.write_admitted_bytes + .fetch_add(admitted_bytes, Ordering::Relaxed); + self.write_dropped_items + .fetch_add(dropped_items, Ordering::Relaxed); + self.write_dropped_bytes + .fetch_add(dropped_bytes, Ordering::Relaxed); + admitted + } + + /// Return rate-budget bytes when a provisionally admitted no-queue batch + /// loses the persist gate before any copy or I/O starts. This keeps gate + /// contention from silently burning future bandwidth while preserving the + /// immediate-Drop contract. + pub(crate) fn refund_owner_write_admission(&self, lengths: &[u64]) { + if lengths.is_empty() { + return; + } + let Some(limiter) = self.write_rate_limiter.as_ref() else { + return; + }; + let refunded_bytes = lengths.iter().copied().fold(0u64, u64::saturating_add); + let mut limiter = limiter.lock(); + limiter.refill(Instant::now()); + limiter.available_bytes = limiter + .available_bytes + .saturating_add(refunded_bytes) + .min(limiter.burst_bytes); + drop(limiter); + self.write_refunded_items.fetch_add( + u64::try_from(lengths.len()).unwrap_or(u64::MAX), + Ordering::Relaxed, + ); + self.write_refunded_bytes + .fetch_add(refunded_bytes, Ordering::Relaxed); + } + + /// Copy exact source bytes into owner-owned buffers. Callers may release + /// source holders after this returns; durability uses only these copies. + pub(crate) fn copy_batch_from_addrs( + sources: &[KvSsdPersistSource], + ) -> Vec> { + sources + .iter() + .map(|source| { + let len = checked_len(source.len, "persist copy")?; + let data = + unsafe { std::slice::from_raw_parts(source.addr as *const u8, len).to_vec() }; + Ok(KvSsdPersistCopy { + key: source.key.clone(), + put_id: source.put_id, + data, + }) + }) + .collect() + } + + pub(crate) async fn persist_batch_from_addrs( + &self, + sources: &[KvSsdPersistSource], + ) -> Vec>> { + if sources.is_empty() { + return Vec::new(); + } + match self.try_acquire_persist_batch(sources.len()) { + Ok(Some(permit)) => { + self.persist_batch_from_copies_with_permit( + permit, + Self::copy_batch_from_addrs(sources), + ) + .await + } + Ok(None) => sources.iter().map(|_| Ok(None)).collect(), + Err(_) => sources + .iter() + .map(|_| Err(persist_batch_size_error(sources.len()))) + .collect(), + } + } + + pub(crate) fn try_acquire_persist_batch( + &self, + item_count: usize, + ) -> KvResult> { + self.persist_requests + .fetch_add(item_count as u64, Ordering::Relaxed); + self.persist_batch_requests.fetch_add(1, Ordering::Relaxed); + self.persist_batch_items + .fetch_add(item_count as u64, Ordering::Relaxed); + if item_count == 0 || item_count > MAX_PERSIST_BATCH_ITEMS { + self.persist_failures + .fetch_add(item_count as u64, Ordering::Relaxed); + return Err(persist_batch_size_error(item_count)); + } + let Ok(guard) = self.persist_batch_gate.clone().try_lock_owned() else { + self.persist_busy_batches.fetch_add(1, Ordering::Relaxed); + self.persist_admission_skips + .fetch_add(item_count as u64, Ordering::Relaxed); + return Ok(None); + }; + Ok(Some(KvSsdPersistBatchPermit { _guard: guard })) + } + + /// Persist owner-owned copies through the canonical durability path. + #[cfg(test)] + pub(crate) async fn persist_batch_from_copies( + &self, + copies: Vec>, + ) -> Vec>> { + if copies.is_empty() { + return Vec::new(); + } + let item_count = copies.len(); + match self.try_acquire_persist_batch(item_count) { + Ok(Some(permit)) => { + self.persist_batch_from_copies_with_permit(permit, copies) + .await + } + Ok(None) => copies.into_iter().map(|copy| copy.map(|_| None)).collect(), + Err(_) => copies + .into_iter() + .map(|copy| copy.and_then(|_| Err(persist_batch_size_error(item_count)))) + .collect(), + } + } + + pub(crate) async fn persist_batch_from_copies_with_permit( + &self, + _permit: KvSsdPersistBatchPermit, + copies: Vec>, + ) -> Vec>> { + let item_count = copies.len(); + let lengths = copies + .iter() + .map(|copy| copy.as_ref().map_or(0, KvSsdPersistCopy::len)) + .collect::>(); + let started_at = Instant::now(); + let mut results = std::iter::repeat_with(|| None) + .take(item_count) + .collect::>>>>(); + let mut batch_keys = std::collections::HashSet::with_capacity(item_count); + let mut pending = Vec::<(usize, KvSsdKey, u64, SsdEntry)>::new(); + + for (index, copy) in copies.into_iter().enumerate() { + let copy = match copy { + Ok(copy) => copy, + Err(err) => { + results[index] = Some(Err(err)); + continue; + } + }; + let len = lengths[index]; + let cache_key = KvSsdKey { + key: copy.key.clone(), + put_id: copy.put_id, + }; + if !batch_keys.insert(cache_key.clone()) { + results[index] = Some(Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "kv ssd persist batch contains duplicate generation: key={} put_id=({},{})", + copy.key, copy.put_id.0, copy.put_id.1 + ), + }))); + continue; + } + let existing_len = self.entry_lengths.lock().get(&cache_key).copied(); + if let Some(existing_len) = existing_len { + if existing_len != len { + results[index] = Some(Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "kv ssd duplicate persist length mismatch: key={} put_id=({},{}) existing={} requested={}", + copy.key, copy.put_id.0, copy.put_id.1, existing_len, len + ), + }))); + continue; + } + // Lengths are published only after the batch durability + // barrier, so a tracked generation can be replayed directly. + if self.cache.storage().may_contains(&cache_key) { + results[index] = Some(Ok(Some(KvSsdPersistGuard { _entry: None }))); + continue; + } + self.forget_entry(&cache_key); + } + + match self + .cache + .storage_writer(cache_key.clone()) + .force() + .insert(copy.data) + { + Some(entry) => pending.push((index, cache_key, len, entry)), + None => { + results[index] = Some(Err(KvError::Api(ApiError::FileWriteError { + path: self.root_dir.display().to_string(), + offset: 0, + detail: format!( + "SSD admission rejected: key={} put_id=({},{})", + copy.key, copy.put_id.0, copy.put_id.1 + ), + }))); + } + } + } + + if !pending.is_empty() { + self.persist_flush_batches.fetch_add(1, Ordering::Relaxed); + // One global barrier covers every independently keyed insertion in + // this admitted batch. No per-item Wait is interleaved into the + // Foyer submit queue. + self.cache.storage().wait().await; + } + for (index, cache_key, len, entry) in pending { + if !self.cache.storage().may_contains(&cache_key) { + results[index] = Some(Err(KvError::Api(ApiError::FileWriteError { + path: self.root_dir.display().to_string(), + offset: 0, + detail: format!( + "SSD commit missing: key={} put_id=({},{})", + cache_key.key, cache_key.put_id.0, cache_key.put_id.1 + ), + }))); + continue; + } + let mut lengths = self.entry_lengths.lock(); + if lengths.insert(cache_key, len).is_none() { + self.logical_used_bytes.fetch_add(len, Ordering::Relaxed); + } + drop(lengths); + results[index] = Some(Ok(Some(KvSsdPersistGuard { + _entry: Some(entry), + }))); + } + + let elapsed = elapsed_us(started_at); + self.persist_batch_duration_us + .fetch_add(elapsed, Ordering::Relaxed); + self.persist_duration_us + .fetch_add(elapsed.saturating_mul(item_count as u64), Ordering::Relaxed); + let mut successes = 0u64; + let mut failures = 0u64; + let mut bytes = 0u64; + let results = results + .into_iter() + .enumerate() + .map(|(index, result)| { + let result = result.unwrap_or_else(|| { + Err(KvError::Api(ApiError::Unknown { + detail: "kv ssd batch result was not populated".to_string(), + })) + }); + match &result { + Ok(Some(_)) => { + successes = successes.saturating_add(1); + bytes = bytes.saturating_add(lengths[index]); + } + Ok(None) => {} + Err(_) => failures = failures.saturating_add(1), + } + result + }) + .collect::>(); + self.persist_successes + .fetch_add(successes, Ordering::Relaxed); + self.persist_failures.fetch_add(failures, Ordering::Relaxed); + self.persist_bytes.fetch_add(bytes, Ordering::Relaxed); + results + } + + #[cfg(test)] + async fn persist( + &self, + key: &str, + put_id: PutIDForAKey, + data: &[u8], + ) -> KvResult { + let source = KvSsdPersistSource { + key: key.to_string(), + put_id, + addr: data.as_ptr() as u64, + len: data.len() as u64, + }; + match self + .persist_batch_from_addrs(std::slice::from_ref(&source)) + .await + .pop() + .expect("one persist source must produce one result")? + { + Some(guard) => Ok(guard), + None => Err(KvError::Api(ApiError::Unknown { + detail: "test persist was skipped by an unexpected busy batch".to_string(), + })), + } + } + + pub(crate) async fn load_into_addr( + &self, + key: &str, + put_id: PutIDForAKey, + target_addr: u64, + len: u64, + target_capacity: u64, + ) -> KvResult<()> { + self.load_requests.fetch_add(1, Ordering::Relaxed); + let started_at = Instant::now(); + let result = self + .load_into_addr_inner(key, put_id, target_addr, len, target_capacity) + .await; + self.load_duration_us + .fetch_add(elapsed_us(started_at), Ordering::Relaxed); + match &result { + Ok(()) => { + self.load_successes.fetch_add(1, Ordering::Relaxed); + self.load_bytes.fetch_add(len, Ordering::Relaxed); + } + Err(KvError::Api(ApiError::KeyNotFound { .. })) => { + self.load_misses.fetch_add(1, Ordering::Relaxed); + } + Err(_) => { + self.load_failures.fetch_add(1, Ordering::Relaxed); + } + } + result + } + + async fn load_into_addr_inner( + &self, + key: &str, + put_id: PutIDForAKey, + target_addr: u64, + len: u64, + target_capacity: u64, + ) -> KvResult<()> { + if target_capacity < len { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "kv ssd target too small: key={} put_id=({},{}) len={} capacity={}", + key, put_id.0, put_id.1, len, target_capacity + ), + })); + } + let len_usize = checked_len(len, "load")?; + let cache_key = KvSsdKey { + key: key.to_string(), + put_id, + }; + let entry = self + .cache + .get(&cache_key) + .await + .map_err(|err| storage_error("load", err))? + .ok_or_else(|| { + self.forget_entry(&cache_key); + KvError::Api(ApiError::KeyNotFound { + key: key.to_string(), + }) + })?; + match entry.source() { + Source::Memory => self.memory_hits.fetch_add(1, Ordering::Relaxed), + Source::Disk => self.disk_hits.fetch_add(1, Ordering::Relaxed), + Source::Outer => self.outer_hits.fetch_add(1, Ordering::Relaxed), + }; + if entry.value().len() != len_usize { + tracing::warn!( + key, + put_time_ms = put_id.0, + put_version = put_id.1, + expected_len = len, + actual_len = entry.value().len(), + "Dropping corrupt/stale KV SSD entry with a length mismatch" + ); + self.forget_entry(&cache_key); + self.cache.remove(&cache_key); + return Err(KvError::Api(ApiError::KeyNotFound { + key: key.to_string(), + })); + } + unsafe { + std::ptr::copy_nonoverlapping( + entry.value().as_ptr(), + target_addr as *mut u8, + len_usize, + ); + } + Ok(()) + } + + pub(crate) async fn remove_exact(&self, key: &str, put_id: PutIDForAKey) -> bool { + let _batch_guard = self.persist_batch_gate.lock().await; + let cache_key = KvSsdKey { + key: key.to_string(), + put_id, + }; + let removed = self.entry_lengths.lock().remove(&cache_key); + self.cache.remove(&cache_key); + if let Some(len) = removed { + self.logical_used_bytes.fetch_sub(len, Ordering::Relaxed); + self.removals.fetch_add(1, Ordering::Relaxed); + true + } else { + false + } + } + + fn forget_entry(&self, key: &KvSsdKey) { + if let Some(len) = self.entry_lengths.lock().remove(key) { + self.logical_used_bytes.fetch_sub(len, Ordering::Relaxed); + } + } +} + +fn elapsed_us(started_at: Instant) -> u64 { + u64::try_from(started_at.elapsed().as_micros()).unwrap_or(u64::MAX) +} + +fn checked_len(len: u64, operation: &str) -> KvResult { + let len = usize::try_from(len).map_err(|_| { + KvError::Api(ApiError::InvalidArgument { + detail: format!("kv ssd {operation} len does not fit usize: {len}"), + }) + })?; + if len == 0 { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!("kv ssd {operation} len must be positive"), + })); + } + Ok(len) +} + +fn persist_batch_size_error(item_count: usize) -> KvError { + KvError::Api(ApiError::InvalidArgument { + detail: format!( + "kv ssd persist batch item count is outside 1..={}: items={}", + MAX_PERSIST_BATCH_ITEMS, item_count + ), + }) +} + +fn storage_error(operation: &str, err: impl std::fmt::Display) -> KvError { + KvError::Api(ApiError::Unknown { + detail: format!("kv ssd {operation} failed: {err}"), + }) +} + +fn file_error(path: &Path, operation: &str, err: std::io::Error) -> KvError { + KvError::Api(ApiError::FileWriteError { + path: path.display().to_string(), + offset: 0, + detail: format!("{operation}: {err}"), + }) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::cluster_manager::NodeID; + use crate::master_kv_router::{ + CommittedSlotReplica, KvMemoryReplica, KvNodeReplicas, KvReplicaBacking, OneKvNodesRoutes, + SsdReplicaCommitStatus, + }; + use crate::master_seg_manager::NodeTombTag; + use parking_lot::RwLock; + use std::collections::HashMap; + use std::sync::Arc; + use std::sync::atomic::AtomicU32; + use std::time::Duration; + + fn test_root(name: &str) -> PathBuf { + let target = std::env::var_os("CARGO_TARGET_DIR") + .map(PathBuf::from) + .unwrap_or_else(|| PathBuf::from("/mnt/nvme0/mjq_build/push_sglang_fluxon_target")); + target.join("kv_ssd_tests").join(format!( + "{}-{}-{}", + name, + std::process::id(), + uuid::Uuid::new_v4() + )) + } + + #[test] + fn write_rate_limiter_refills_without_queueing() { + let start = Instant::now(); + let mut limiter = WriteRateLimiter { + rate_bytes_per_sec: 100, + burst_bytes: 100, + available_bytes: 100, + refill_remainder: 0, + last_refill: start, + }; + assert!(limiter.try_consume(60, start)); + assert!(!limiter.try_consume(50, start)); + assert!(limiter.try_consume(50, start + Duration::from_millis(500))); + assert_eq!(limiter.available_bytes, 40); + } + + #[tokio::test] + async fn owner_candidate_admission_prefers_small_values_and_one_batch() { + let root = test_root("candidate-admission"); + let store = KvSsdStorage::new(KvSsdStorageInit { + roots: vec![KvSsdStorageRootLimit { + root_dir: root.clone(), + limit_bytes: MIN_CAPACITY_BYTES, + }], + write_rate_limit_bytes_per_sec: Some(1), + write_burst_bytes: Some(10), + }) + .await + .unwrap(); + let admitted = store.admit_owner_write_candidates(&[8, 3, 3]); + assert_eq!(admitted, vec![false, true, true]); + let usage = store.usage_snapshot(); + assert_eq!(usage.write_candidate_items, 3); + assert_eq!(usage.write_candidate_bytes, 14); + assert_eq!(usage.write_admitted_items, 2); + assert_eq!(usage.write_admitted_bytes, 6); + assert_eq!(usage.write_dropped_items, 1); + assert_eq!(usage.write_dropped_bytes, 8); + + store.close().await.unwrap(); + fs::remove_dir_all(root).unwrap(); + } + + #[tokio::test] + async fn busy_gate_refund_restores_owner_write_budget() { + let root = test_root("candidate-refund"); + let store = KvSsdStorage::new(KvSsdStorageInit { + roots: vec![KvSsdStorageRootLimit { + root_dir: root.clone(), + limit_bytes: MIN_CAPACITY_BYTES, + }], + write_rate_limit_bytes_per_sec: Some(1), + write_burst_bytes: Some(10), + }) + .await + .unwrap(); + + assert_eq!(store.admit_owner_write_candidates(&[8]), vec![true]); + store.refund_owner_write_admission(&[8]); + assert_eq!(store.admit_owner_write_candidates(&[8]), vec![true]); + let usage = store.usage_snapshot(); + assert_eq!(usage.write_refunded_items, 1); + assert_eq!(usage.write_refunded_bytes, 8); + + store.close().await.unwrap(); + fs::remove_dir_all(root).unwrap(); + } + + #[tokio::test] + async fn persist_and_load_one_generation() { + let root = test_root("roundtrip"); + let store = KvSsdStorage::new(KvSsdStorageInit { + roots: vec![KvSsdStorageRootLimit { + root_dir: root.clone(), + limit_bytes: BLOCK_SIZE_BYTES as u64, + }], + write_rate_limit_bytes_per_sec: None, + write_burst_bytes: None, + }) + .await + .unwrap(); + let input = vec![0x5au8; 4096]; + let guard = store.persist("key", (7, 3), &input).await.unwrap(); + let mut output = vec![0u8; input.len()]; + store + .load_into_addr( + "key", + (7, 3), + output.as_mut_ptr() as u64, + input.len() as u64, + output.len() as u64, + ) + .await + .unwrap(); + assert_eq!(output, input); + let usage = store.usage_snapshot(); + assert_eq!(usage.used_bytes, input.len() as u64); + assert_eq!(usage.persist_requests, 1); + assert_eq!(usage.persist_successes, 1); + assert_eq!(usage.persist_failures, 0); + assert_eq!(usage.persist_bytes, input.len() as u64); + assert_eq!(usage.load_requests, 1); + assert_eq!(usage.load_successes, 1); + assert_eq!(usage.load_misses, 0); + assert_eq!(usage.load_bytes, input.len() as u64); + assert_eq!(usage.memory_hits + usage.disk_hits + usage.outer_hits, 1); + + assert!(store.remove_exact("key", (7, 3)).await); + assert!(!store.remove_exact("key", (7, 3)).await); + assert_eq!(store.usage_snapshot().used_bytes, 0); + assert!( + store + .load_into_addr( + "key", + (7, 3), + output.as_mut_ptr() as u64, + input.len() as u64, + output.len() as u64, + ) + .await + .is_err() + ); + let usage = store.usage_snapshot(); + assert_eq!(usage.load_requests, 2); + assert_eq!(usage.load_misses, 1); + assert_eq!(usage.removals, 1); + drop(guard); + store.close().await.unwrap(); + fs::remove_dir_all(root).unwrap(); + } + + #[tokio::test] + async fn copied_persist_no_longer_reads_the_source_buffer() { + let root = test_root("copied-persist"); + let store = KvSsdStorage::new(KvSsdStorageInit { + roots: vec![KvSsdStorageRootLimit { + root_dir: root.clone(), + limit_bytes: BLOCK_SIZE_BYTES as u64, + }], + write_rate_limit_bytes_per_sec: None, + write_burst_bytes: None, + }) + .await + .unwrap(); + let mut input = vec![0x3cu8; 4096]; + let source = KvSsdPersistSource { + key: "copied-key".to_string(), + put_id: (8, 4), + addr: input.as_ptr() as u64, + len: input.len() as u64, + }; + let copies = KvSsdStorage::copy_batch_from_addrs(std::slice::from_ref(&source)); + input.fill(0xe7); + let guard = store + .persist_batch_from_copies(copies) + .await + .pop() + .unwrap() + .unwrap() + .expect("copied persist must acquire the durability gate"); + let mut output = vec![0u8; input.len()]; + store + .load_into_addr( + "copied-key", + (8, 4), + output.as_mut_ptr() as u64, + output.len() as u64, + output.len() as u64, + ) + .await + .unwrap(); + assert!(output.iter().all(|byte| *byte == 0x3c)); + + drop(guard); + store.close().await.unwrap(); + fs::remove_dir_all(root).unwrap(); + } + + #[tokio::test] + async fn one_batch_uses_one_flush_barrier_and_keeps_per_key_results() { + let root = test_root("one-batch-one-barrier"); + let store = KvSsdStorage::new(KvSsdStorageInit { + roots: vec![KvSsdStorageRootLimit { + root_dir: root.clone(), + limit_bytes: MIN_CAPACITY_BYTES, + }], + write_rate_limit_bytes_per_sec: None, + write_burst_bytes: None, + }) + .await + .unwrap(); + let payloads = (0..MAX_PERSIST_BATCH_ITEMS) + .map(|index| vec![u8::try_from(index + 1).unwrap(); 1024 * 1024]) + .collect::>(); + let sources = payloads + .iter() + .enumerate() + .map(|(index, payload)| KvSsdPersistSource { + key: format!("batch-victim-{index}"), + put_id: (31, u32::try_from(index).unwrap()), + addr: payload.as_ptr() as u64, + len: payload.len() as u64, + }) + .collect::>(); + let guards = store + .persist_batch_from_addrs(&sources) + .await + .into_iter() + .map(|result| result.unwrap().expect("the only batch must be admitted")) + .collect::>(); + assert_eq!(guards.len(), MAX_PERSIST_BATCH_ITEMS); + + for (index, payload) in payloads.iter().enumerate() { + let mut output = vec![0; payload.len()]; + store + .load_into_addr( + &format!("batch-victim-{index}"), + (31, u32::try_from(index).unwrap()), + output.as_mut_ptr() as u64, + output.len() as u64, + output.len() as u64, + ) + .await + .unwrap(); + assert_eq!(&output, payload); + } + let usage = store.usage_snapshot(); + assert_eq!(usage.persist_successes, MAX_PERSIST_BATCH_ITEMS as u64); + assert_eq!(usage.persist_failures, 0); + assert_eq!(usage.persist_batch_requests, 1); + assert_eq!(usage.persist_flush_batches, 1); + assert_eq!(usage.persist_busy_batches, 0); + assert_eq!(usage.persist_admission_skips, 0); + assert_eq!(usage.load_successes, MAX_PERSIST_BATCH_ITEMS as u64); + + drop(guards); + store.close().await.unwrap(); + fs::remove_dir_all(root).unwrap(); + } + + #[tokio::test] + async fn retrying_a_multi_key_batch_reuses_durable_generations() { + let root = test_root("multi-key-batch-retry"); + let store = KvSsdStorage::new(KvSsdStorageInit { + roots: vec![KvSsdStorageRootLimit { + root_dir: root.clone(), + limit_bytes: MIN_CAPACITY_BYTES, + }], + write_rate_limit_bytes_per_sec: None, + write_burst_bytes: None, + }) + .await + .unwrap(); + let original = (0..3) + .map(|index| vec![u8::try_from(0x41 + index).unwrap(); 4096]) + .collect::>(); + let original_sources = original + .iter() + .enumerate() + .map(|(index, payload)| KvSsdPersistSource { + key: format!("retry-victim-{index}"), + put_id: (35, u32::try_from(index).unwrap()), + addr: payload.as_ptr() as u64, + len: payload.len() as u64, + }) + .collect::>(); + let first_guards = store + .persist_batch_from_addrs(&original_sources) + .await + .into_iter() + .map(|result| result.unwrap().expect("the first batch must be admitted")) + .collect::>(); + + // A retry may arrive after the caller has reused its source buffer. The + // generation identity, not the retried bytes, owns the durable result. + let retry_payloads = original + .iter() + .map(|payload| vec![0xee; payload.len()]) + .collect::>(); + let retry_sources = retry_payloads + .iter() + .enumerate() + .map(|(index, payload)| KvSsdPersistSource { + key: format!("retry-victim-{index}"), + put_id: (35, u32::try_from(index).unwrap()), + addr: payload.as_ptr() as u64, + len: payload.len() as u64, + }) + .collect::>(); + let retry_guards = store + .persist_batch_from_addrs(&retry_sources) + .await + .into_iter() + .map(|result| result.unwrap().expect("a durable retry must be replayable")) + .collect::>(); + + for (index, expected) in original.iter().enumerate() { + let mut output = vec![0; expected.len()]; + store + .load_into_addr( + &format!("retry-victim-{index}"), + (35, u32::try_from(index).unwrap()), + output.as_mut_ptr() as u64, + output.len() as u64, + output.len() as u64, + ) + .await + .unwrap(); + assert_eq!(&output, expected); + } + let expected_bytes = original.iter().map(Vec::len).sum::() as u64; + let usage = store.usage_snapshot(); + assert_eq!(usage.used_bytes, expected_bytes); + assert_eq!(usage.persist_requests, 6); + assert_eq!(usage.persist_successes, 6); + assert_eq!(usage.persist_failures, 0); + assert_eq!(usage.persist_batch_requests, 2); + assert_eq!(usage.persist_flush_batches, 1); + assert_eq!(usage.persist_busy_batches, 0); + + drop(retry_guards); + drop(first_guards); + store.close().await.unwrap(); + fs::remove_dir_all(root).unwrap(); + } + + #[tokio::test] + async fn busy_write_batch_skips_without_copying_or_queueing() { + let root = test_root("busy-batch-skip"); + let store = KvSsdStorage::new(KvSsdStorageInit { + roots: vec![KvSsdStorageRootLimit { + root_dir: root.clone(), + limit_bytes: MIN_CAPACITY_BYTES, + }], + write_rate_limit_bytes_per_sec: None, + write_burst_bytes: None, + }) + .await + .unwrap(); + let input = vec![0xabu8; 4096]; + let source = KvSsdPersistSource { + key: "busy-skip".to_string(), + put_id: (37, 1), + addr: input.as_ptr() as u64, + len: input.len() as u64, + }; + let held = store.persist_batch_gate.lock().await; + let result = store + .persist_batch_from_addrs(std::slice::from_ref(&source)) + .await + .pop() + .unwrap() + .unwrap(); + assert!(result.is_none()); + drop(held); + + let usage = store.usage_snapshot(); + assert_eq!(usage.persist_requests, 1); + assert_eq!(usage.persist_successes, 0); + assert_eq!(usage.persist_failures, 0); + assert_eq!(usage.persist_busy_batches, 1); + assert_eq!(usage.persist_admission_skips, 1); + assert_eq!(usage.persist_flush_batches, 0); + + store.close().await.unwrap(); + fs::remove_dir_all(root).unwrap(); + } + + #[tokio::test] + async fn persist_commit_memory_evict_and_ssd_load_roundtrip() { + let root = test_root("route-roundtrip"); + let store = KvSsdStorage::new(KvSsdStorageInit { + roots: vec![KvSsdStorageRootLimit { + root_dir: root.clone(), + limit_bytes: MIN_CAPACITY_BYTES, + }], + write_rate_limit_bytes_per_sec: None, + write_burst_bytes: None, + }) + .await + .unwrap(); + let owner: NodeID = "owner".to_string().into(); + let put_id = (19, 4); + let input = vec![0xa5u8; 4096]; + let persist_guard = store.persist("route-key", put_id, &input).await.unwrap(); + + let route = Arc::new(OneKvNodesRoutes { + put_id, + lease_id: None, + atomic_group: None, + node_replicas: RwLock::new(HashMap::from([( + owner.clone(), + KvNodeReplicas::memory( + NodeTombTag::new(), + KvMemoryReplica { + backing: KvReplicaBacking::CommittedSlot(CommittedSlotReplica { + owner_node_id: owner.clone(), + grant_id: 7, + slot_index: 3, + slot_size: input.len() as u64, + addr: input.as_ptr() as u64, + len: input.len() as u64, + base_addr: input.as_ptr() as u64, + }), + owner_local_indexed: true, + get_durable_reservation: None, + capacity_reservation: None, + }, + ), + )])), + get_durable_slots_used: AtomicU32::new(0), + }); + assert_eq!( + route.commit_ssd_replica(&owner, input.len() as u64), + SsdReplicaCommitStatus::Committed + ); + + // This is the terminal state produced by the already-covered exact + // owner-memory reclaim transaction: the node and SSD route remain, + // while DRAM is no longer readable. + route.node_replicas.write().get_mut(&owner).unwrap().memory = None; + { + let replicas = route.node_replicas.read(); + let owner_backings = replicas.get(&owner).unwrap(); + assert!(owner_backings.memory.is_none()); + assert_eq!( + owner_backings.ssd.as_ref().map(|ssd| ssd.len), + Some(input.len() as u64) + ); + } + + let mut output = vec![0u8; input.len()]; + store + .load_into_addr( + "route-key", + put_id, + output.as_mut_ptr() as u64, + output.len() as u64, + output.len() as u64, + ) + .await + .unwrap(); + assert_eq!(output, input); + + drop(persist_guard); + store.close().await.unwrap(); + fs::remove_dir_all(root).unwrap(); + } +} diff --git a/fluxon_rs/fluxon_kv/src/kv_test.rs b/fluxon_rs/fluxon_kv/src/kv_test.rs index d8331ea..a8c60c1 100644 --- a/fluxon_rs/fluxon_kv/src/kv_test.rs +++ b/fluxon_rs/fluxon_kv/src/kv_test.rs @@ -1057,6 +1057,7 @@ fn build_client_launch( &instance_key, &contribute_to_cluster_pool_size, ), + ssd_storage: None, // Mirror round intent into the generated config so logs and runtime behavior // agree on whether this launch is transfer_only vs transfer_with_rpc. test_spec_config: kv_test_round_test_spec_config(round.round_profile), @@ -2470,7 +2471,7 @@ async fn run_kv_round(round: &KvTestRoundOptions) { .kv_routes .get(CLIENT_COMMUNICATION_KEY) { - let replicas = one_kv_nodes_routes.nodes_replicas.read(); + let replicas = one_kv_nodes_routes.node_replicas.read(); let active_replica_count = replicas .iter() .filter(|(_, kv_info)| !kv_info.tomb_tag.is_tomb()) diff --git a/fluxon_rs/fluxon_kv/src/kvcore_test_lib.rs b/fluxon_rs/fluxon_kv/src/kvcore_test_lib.rs index d17dc57..aba139c 100644 --- a/fluxon_rs/fluxon_kv/src/kvcore_test_lib.rs +++ b/fluxon_rs/fluxon_kv/src/kvcore_test_lib.rs @@ -152,6 +152,7 @@ fn new_client_config_with_cluster_and_dram( large_file_paths: crate::config::LargeFilePaths { paths: vec![format!("{}/large/{}", base, instance_key)], }, + ssd_storage: None, test_spec_config: TestSpecConfig::default(), }; println!("fluxonkv core created client config for test: {:?}", conf); @@ -225,6 +226,35 @@ pub async fn start_master_and_client_with_client_dram( (master_fw, client_fw) } +/// Start a test owner after applying one focused configuration mutation. This +/// keeps integration tests on the same canonical startup path while allowing +/// storage-tier tests to enable their local SSD root explicitly. +pub async fn start_master_and_client_with_client_config( + master_key: &str, + client_key: &str, + configure: impl FnOnce(&mut ClientConfig), +) -> (Arc, Arc) { + let cluster_name = test_cluster_name(master_key); + clean_etcd_members(&cluster_name).await; + + let (master_fw, _) = run_master(ConfigArg::Config(new_master_config_with_cluster( + master_key, + None, + &cluster_name, + ))) + .await + .expect("start master"); + let mut client_config = + new_client_config_with_cluster_and_dram(client_key, &cluster_name, 1024 * 1024 * 160); + configure(&mut client_config); + let (client_fw, _) = run_client(ConfigArg::Config(client_config)) + .await + .expect("start client"); + + sleep(Duration::from_secs(3)).await; + (master_fw, client_fw) +} + pub async fn stop_master_and_client(master_fw: Arc, client_fw: Arc) { let _ = client_fw.shutdown().await; let _ = master_fw.shutdown().await; diff --git a/fluxon_rs/fluxon_kv/src/lib.rs b/fluxon_rs/fluxon_kv/src/lib.rs index a9d38ae..e09061f 100644 --- a/fluxon_rs/fluxon_kv/src/lib.rs +++ b/fluxon_rs/fluxon_kv/src/lib.rs @@ -7,6 +7,7 @@ pub mod external_client_api; pub mod panel_proxy; // #[cfg(test)] pub mod key_prefix; +pub mod kv_ssd_storage; #[cfg(feature = "test_bins")] pub mod kv_test; pub mod kvlease; @@ -86,6 +87,7 @@ use crate::cluster_manager::ClusterManagerViewTrait; use crate::external_client_api::ExternalClientApiAccessTrait; use crate::external_client_api::ExternalClientApiView; use crate::external_client_api::ExternalClientApiViewTrait; +use crate::kv_ssd_storage::{KvSsdStorageInit, KvSsdStorageRootLimit}; use crate::master_kv_router::MasterKvRouterAccessTrait; use crate::master_kv_router::MasterKvRouterView; use crate::master_kv_router::MasterKvRouterViewTrait; @@ -862,6 +864,7 @@ fn build_side_transfer_worker_config( }, share_mem_path: owner_config.share_mem_path.clone(), large_file_paths: owner_config.large_file_paths.clone(), + ssd_storage: None, test_spec_config, }) } @@ -907,6 +910,9 @@ fn build_side_transfer_worker_config_yaml( cluster_name: side_config.cluster_name, share_mem_path: side_config.share_mem_path, large_file_paths: None, + large_limit_size: None, + ssd_write_rate_limit_bytes_per_sec: None, + ssd_write_burst_bytes: None, p2p_listen_port: side_config.fluxonkv_spec.p2p_listen_port, redis_compat: None, sub_cluster: None, @@ -1992,6 +1998,12 @@ async fn run_client_impl( // Owner nodes are the global relay set. Keeping a single metadata marker converges // route selection, observability proxy eligibility, and ops topology rendering. metadata.insert("p2p_relay".to_string(), "true".to_string()); + if config.ssd_storage.is_some() { + metadata.insert( + crate::cluster_manager::META_KEY_KV_SSD_STORAGE.to_string(), + "true".to_string(), + ); + } } merge_startup_member_metadata(&mut metadata, startup_member_metadata)?; @@ -2026,6 +2038,24 @@ async fn run_client_impl( )); info!("Initializing client framework..."); + let ssd_storage_init = config + .ssd_storage + .as_ref() + .map(|ssd| { + config + .large_file_paths + .kv_ssd_storage_root(&config.cluster_name, &config.instance_key) + .map(|root_dir| KvSsdStorageInit { + roots: vec![KvSsdStorageRootLimit { + root_dir, + limit_bytes: ssd.limit_bytes, + }], + write_rate_limit_bytes_per_sec: ssd.write_rate_limit_bytes_per_sec, + write_burst_bytes: ssd.write_burst_bytes, + }) + }) + .transpose()?; + if is_external && !is_side_transfer_worker { let init_args = InitArgsExternal { cluster_manager_arg: ClusterManagerNewArg { @@ -2133,6 +2163,7 @@ async fn run_client_impl( (config.contribute_to_cluster_pool_size.dram as f64 * ratio).floor() as u64 }, ), + ssd_storage: ssd_storage_init, }, client_seg_pool_arg: ClientSegPoolNewArg { contribute_size: config.contribute_to_cluster_pool_size.clone(), @@ -2566,6 +2597,7 @@ mod tests { large_file_paths: crate::config::LargeFilePaths { paths: vec!["/tmp/fluxon_side_transfer_test_large".to_string()], }, + ssd_storage: None, test_spec_config: TestSpecConfig { enable_side_transfer: true, side_transfer_worker_count: 4, @@ -2872,6 +2904,7 @@ mod tests { }, share_mem_path: share_mem_root.to_string_lossy().into_owned(), large_file_paths: crate::config::LargeFilePaths { paths: Vec::new() }, + ssd_storage: None, test_spec_config: TestSpecConfig::default(), }; diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/delete.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/delete.rs index 87a18da..2a2f758 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/delete.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/delete.rs @@ -113,8 +113,8 @@ pub fn evict_one_kv_replica_for_node( } let removed_replica = { - let mut nodes_replicas = route.nodes_replicas.write(); - nodes_replicas.remove(&node_id).is_some() + let mut node_replicas = route.node_replicas.write(); + node_replicas.remove(&node_id).is_some() }; if !removed_replica { tracing::debug!( @@ -127,7 +127,7 @@ pub fn evict_one_kv_replica_for_node( return Ok(()); } - let last_replica_gone = route.nodes_replicas.read().is_empty(); + let last_replica_gone = route.node_replicas.read().is_empty(); if last_replica_gone { let removed = view .master_kv_router() @@ -136,7 +136,7 @@ pub fn evict_one_kv_replica_for_node( .remove_if(&key, |_, current| { Arc::ptr_eq(current, &route) && current.put_id == put_id - && current.nodes_replicas.read().is_empty() + && current.node_replicas.read().is_empty() }) .is_some(); if removed && view.master_kv_router().prefix_index_enabled() { diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs index 533127d..5e08ec7 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/get.rs @@ -1,6 +1,6 @@ use super::{ - CommittedSlotReplica, CompletedGetInfo, InflightGetInfo, InflightGetTarget, KvRouteInfo, - MasterKeyActivityCompletionGuard, MasterKvRouterView, OwnerHoldingGetInfo, + CommittedSlotReplica, CompletedGetInfo, InflightGetInfo, InflightGetTarget, KvMemoryReplica, + KvNodeReplicas, MasterKeyActivityCompletionGuard, MasterKvRouterView, OwnerHoldingGetInfo, ReservedCapacityReason, msg_pack::{ BatchGetBindItemReq, BatchGetBindReq, BatchGetBindResp, BatchGetDoneItemResp, @@ -8,12 +8,15 @@ use super::{ BatchGetRevokeItemResp, BatchGetRevokeReq, BatchGetRevokeResp, BatchGetStartItemResp, BatchGetStartReq, BatchGetStartResp, BatchIsExistReq, BatchIsExistResp, GetAllocationMode, GetBindTarget, GetDoneReq, GetDoneResp, GetExternalSinkTarget, GetMetaReq, GetMetaResp, - GetPreparedLocalReserveTarget, GetRevokeReq, GetRevokeResp, GetStartReq, GetStartResp, - MemHolderKeepAliveReq, MemHolderKeepAliveResp, MemHolderReleaseReq, MemHolderReleaseResp, + GetPreparedLocalReserveTarget, GetRevokeReq, GetRevokeResp, GetSourceKind, GetStartReq, + GetStartResp, MemHolderKeepAliveReq, MemHolderKeepAliveResp, MemHolderReleaseReq, + MemHolderReleaseResp, SsdStageBeginReq, SsdStageBeginResp, SsdStageDoneReq, + SsdStageDoneResp, }, node_generation_is_current_live, publish_route_replica_tomb_fenced, route_maintenance::{RoutePublishEvent, apply_post_route_maintenance_batch}, }; +use crate::config::SsdReadSourcePolicy; use crate::master_kv_router::OneKvNodesRoutes; use crate::master_kv_router::put::PutIDForAKey; use crate::memholder::MemholderManagerTrait; @@ -79,10 +82,10 @@ fn touch_moka_for_node(view: MasterKvRouterView, node_id: String, key: String) { fn one_kv_routes_has_live_replica(one_kv_nodes_routes: &OneKvNodesRoutes) -> bool { one_kv_nodes_routes - .nodes_replicas + .node_replicas .read() .values() - .any(|kv_info| !kv_info.tomb_tag.is_tomb()) + .any(KvNodeReplicas::has_live_backing) } fn validate_prepared_local_reserve_target( @@ -267,20 +270,57 @@ struct PlannedGetSourceSnapshot { len: u64, addr: u64, base_addr: u64, + source_kind: GetSourceKind, +} + +fn planned_get_source_rank( + policy: SsdReadSourcePolicy, + source_kind: GetSourceKind, + requester_local: bool, +) -> Option { + match policy { + SsdReadSourcePolicy::LegacyRemoteFirst => match (source_kind, requester_local) { + (GetSourceKind::Memory, false) => Some(0), + (GetSourceKind::Memory, true) => Some(1), + (GetSourceKind::Ssd, false) => Some(2), + (GetSourceKind::Ssd, true) => Some(3), + }, + SsdReadSourcePolicy::LocalSsdOnlyFirst => match (source_kind, requester_local) { + (GetSourceKind::Memory, true) => Some(0), + (GetSourceKind::Ssd, true) => Some(1), + (GetSourceKind::Memory, false) => Some(2), + (GetSourceKind::Ssd, false) => None, + }, + } } fn snapshot_live_get_sources(route: &OneKvNodesRoutes) -> Vec { route - .nodes_replicas + .node_replicas .read() - .values() - .filter(|replica| !replica.tomb_tag.is_tomb()) - .map(|replica| PlannedGetSourceSnapshot { - node_id: replica.node_id.clone(), - tomb_tag: replica.tomb_tag.clone(), - len: replica.backing.len(), - addr: replica.backing.abs_addr(), - base_addr: replica.backing.base_addr(), + .iter() + .filter_map(|(node_id, replicas)| { + if replicas.tomb_tag.is_tomb() { + return None; + } + if let Some(memory) = replicas.memory.as_ref() { + return Some(PlannedGetSourceSnapshot { + node_id: node_id.clone(), + tomb_tag: replicas.tomb_tag.clone(), + len: memory.backing.len(), + addr: memory.backing.abs_addr(), + base_addr: memory.backing.base_addr(), + source_kind: GetSourceKind::Memory, + }); + } + replicas.ssd.as_ref().map(|ssd| PlannedGetSourceSnapshot { + node_id: node_id.clone(), + tomb_tag: replicas.tomb_tag.clone(), + len: ssd.len, + addr: 0, + base_addr: 0, + source_kind: GetSourceKind::Ssd, + }) }) .collect() } @@ -293,24 +333,71 @@ fn planned_get_source_is_current( return false; } route - .nodes_replicas + .node_replicas .read() .get(&planned.src_node_id) - .is_some_and(|replica| { - !replica.tomb_tag.is_tomb() - && replica.tomb_tag.same_generation(&planned.src_tomb_tag) - && replica.backing.abs_addr() == planned.src_addr - && replica.backing.base_addr() == planned.src_base_addr - && replica.backing.len() == planned.len + .is_some_and(|replicas| { + !replicas.tomb_tag.is_tomb() + && replicas.tomb_tag.same_generation(&planned.src_tomb_tag) + && match planned.source_kind { + GetSourceKind::Memory => replicas.memory.as_ref().is_some_and(|memory| { + memory.backing.abs_addr() == planned.src_addr + && memory.backing.base_addr() == planned.src_base_addr + && memory.backing.len() == planned.len + }), + GetSourceKind::Ssd => replicas + .ssd + .as_ref() + .is_some_and(|ssd| ssd.len == planned.len), + } }) } +fn allocate_ssd_source_stage( + view: &MasterKvRouterView, + source_node_id: &NodeID, + len: u64, +) -> Result, msg_and_error::KvError> { + let allocators = view + .master_seg_manager() + .get_node_allocators(source_node_id); + if allocators.is_empty() { + return Err(msg_and_error::KvError::Unreachable( + msg_and_error::UnreachableError::OwnerNoSeg { + detail: format!("SSD source owner has no registered segment: {source_node_id}"), + }, + )); + } + let allocator = allocators + .choose(&mut rand::thread_rng()) + .expect("non-empty SSD source allocators"); + for _ in 0..3 { + if let Ok(allocation) = allocator.allocate(len) { + return Ok(Arc::new(allocation)); + } + } + let capacity = allocator.node_pool_capacity_snapshot(); + Err(msg_and_error::KvError::Api( + msg_and_error::ApiError::NoSpace { + node: source_node_id.to_string(), + segment: allocator.seg_device_id.clone(), + total_capacity: capacity.active_capacity_bytes, + free_capacity: capacity.available_capacity_bytes, + }, + )) +} + #[cfg(test)] mod planned_get_tests { - use super::{planned_get_source_is_current, snapshot_live_get_sources}; + use super::{ + planned_get_source_is_current, planned_get_source_rank, snapshot_live_get_sources, + }; use crate::cluster_manager::NodeID; + use crate::config::SsdReadSourcePolicy; + use crate::master_kv_router::msg_pack::GetSourceKind; use crate::master_kv_router::{ - CommittedSlotReplica, KvReplicaBacking, KvRouteInfo, OneKvNodesRoutes, PlannedGetInfo, + CommittedSlotReplica, KvMemoryReplica, KvNodeReplicas, KvReplicaBacking, KvSsdReplica, + OneKvNodesRoutes, PlannedGetInfo, }; use crate::master_seg_manager::NodeTombTag; use parking_lot::RwLock; @@ -325,24 +412,25 @@ mod planned_get_tests { put_id: (7, 3), lease_id: None, atomic_group: None, - nodes_replicas: RwLock::new(HashMap::from([( + node_replicas: RwLock::new(HashMap::from([( source.clone(), - KvRouteInfo { - node_id: source.clone(), - backing: KvReplicaBacking::CommittedSlot(CommittedSlotReplica { - owner_node_id: source.clone(), - grant_id: 11, - slot_index: 2, - slot_size: 8192, - addr: 0x3000, - len: 4096, - base_addr: 0x1000, - }), - owner_local_indexed: true, - get_durable_reservation: None, - capacity_reservation: None, - tomb_tag: source_tag.clone(), - }, + KvNodeReplicas::memory( + source_tag.clone(), + KvMemoryReplica { + backing: KvReplicaBacking::CommittedSlot(CommittedSlotReplica { + owner_node_id: source.clone(), + grant_id: 11, + slot_index: 2, + slot_size: 8192, + addr: 0x3000, + len: 4096, + base_addr: 0x1000, + }), + owner_local_indexed: true, + get_durable_reservation: None, + capacity_reservation: None, + }, + ), )])), get_durable_slots_used: AtomicU32::new(0), }); @@ -356,6 +444,7 @@ mod planned_get_tests { len: 4096, src_addr: 0x3000, src_base_addr: 0x1000, + source_kind: GetSourceKind::Memory, atomic_group: None, }; (planned, route, source_tag) @@ -367,10 +456,13 @@ mod planned_get_tests { assert!(planned_get_source_is_current(&planned, &route)); route - .nodes_replicas + .node_replicas .write() .get_mut(&planned.src_node_id) .unwrap() + .memory + .as_mut() + .unwrap() .backing = KvReplicaBacking::CommittedSlot(CommittedSlotReplica { owner_node_id: planned.src_node_id.clone(), grant_id: 11, @@ -383,10 +475,13 @@ mod planned_get_tests { assert!(!planned_get_source_is_current(&planned, &route)); route - .nodes_replicas + .node_replicas .write() .get_mut(&planned.src_node_id) .unwrap() + .memory + .as_mut() + .unwrap() .backing = KvReplicaBacking::CommittedSlot(CommittedSlotReplica { owner_node_id: planned.src_node_id.clone(), grant_id: 11, @@ -405,7 +500,7 @@ mod planned_get_tests { let (planned, route, _) = planned_route(); let replacement_tag = NodeTombTag::new(); route - .nodes_replicas + .node_replicas .write() .get_mut(&planned.src_node_id) .unwrap() @@ -413,6 +508,37 @@ mod planned_get_tests { assert!(!planned_get_source_is_current(&planned, &route)); } + #[test] + fn ssd_plan_and_bind_revalidate_the_same_owner_backing() { + let (mut planned, route, _) = planned_route(); + planned.source_kind = GetSourceKind::Ssd; + planned.src_addr = 0; + planned.src_base_addr = 0; + let mut replicas = route.node_replicas.write(); + let source = replicas.get_mut(&planned.src_node_id).unwrap(); + source.memory = None; + source.ssd = Some(KvSsdReplica { len: planned.len }); + drop(replicas); + + let sources = snapshot_live_get_sources(&route); + assert_eq!(sources.len(), 1); + assert_eq!(sources[0].source_kind, GetSourceKind::Ssd); + assert_eq!(sources[0].addr, 0); + assert_eq!(sources[0].base_addr, 0); + assert!(planned_get_source_is_current(&planned, &route)); + + route + .node_replicas + .write() + .get_mut(&planned.src_node_id) + .unwrap() + .ssd + .as_mut() + .unwrap() + .len += 1; + assert!(!planned_get_source_is_current(&planned, &route)); + } + #[test] fn metadata_plan_does_not_retain_the_route() { let (planned, route, _) = planned_route(); @@ -423,6 +549,47 @@ mod planned_get_tests { assert_eq!(sources.len(), 1); assert_eq!(planned.key, "key"); } + + #[test] + fn ssd_read_source_policies_have_distinct_explicit_orders() { + let order = |policy| { + let classes = vec![ + (GetSourceKind::Memory, false, "remote_memory"), + (GetSourceKind::Memory, true, "local_memory"), + (GetSourceKind::Ssd, false, "remote_ssd"), + (GetSourceKind::Ssd, true, "local_ssd"), + ]; + let mut classes = classes + .into_iter() + .filter_map(|(kind, local, label)| { + planned_get_source_rank(policy, kind, local).map(|rank| (rank, label)) + }) + .collect::>(); + classes.sort_by_key(|(rank, _)| *rank); + classes + .into_iter() + .map(|(_, label)| label) + .collect::>() + }; + + assert_eq!( + order(SsdReadSourcePolicy::LegacyRemoteFirst), + ["remote_memory", "local_memory", "remote_ssd", "local_ssd"] + ); + assert_eq!( + order(SsdReadSourcePolicy::LocalSsdOnlyFirst), + ["local_memory", "local_ssd", "remote_memory"] + ); + assert_eq!( + planned_get_source_rank( + SsdReadSourcePolicy::LocalSsdOnlyFirst, + GetSourceKind::Ssd, + false, + ), + None, + "remote SSD must not be a fallback for the local-only policy" + ); + } } async fn handle_get_plan_item( @@ -478,14 +645,51 @@ async fn handle_get_plan_item( let local_owner = external_sink_local_owner_id(&view, &controller_node_id, controller.node_start_time); - let mut candidates = snapshot_live_get_sources(&route); + let source_policy = view + .master_kv_router() + .inner() + .test_spec_config + .ssd_read_source_policy; + let mut filtered_remote_ssd_items = 0u64; + let mut filtered_remote_ssd_bytes = 0u64; + let mut candidates = snapshot_live_get_sources(&route) + .into_iter() + .filter_map(|source| { + let requester_local = local_owner + .as_deref() + .is_some_and(|owner| source.node_id.as_ref() == owner); + match planned_get_source_rank(source_policy, source.source_kind, requester_local) { + Some(rank) => Some((source, rank)), + None => { + filtered_remote_ssd_items = filtered_remote_ssd_items.saturating_add(1); + filtered_remote_ssd_bytes = + filtered_remote_ssd_bytes.saturating_add(source.len); + None + } + } + }) + .collect::>(); + if filtered_remote_ssd_items != 0 { + view.master_kv_router() + .inner() + .planned_get_counters + .remote_ssd_filtered_items + .fetch_add(filtered_remote_ssd_items, Ordering::Relaxed); + view.master_kv_router() + .inner() + .planned_get_counters + .remote_ssd_filtered_bytes + .fetch_add(filtered_remote_ssd_bytes, Ordering::Relaxed); + } candidates.shuffle(&mut rand::thread_rng()); - candidates.sort_by_key(|replica| { - local_owner - .as_deref() - .is_some_and(|owner| replica.node_id.as_ref() == owner) + candidates.sort_by_key(|(_, rank)| *rank); + let has_remote_memory_alternative = candidates.iter().any(|(candidate, _)| { + candidate.source_kind == GetSourceKind::Memory + && local_owner + .as_deref() + .is_none_or(|owner| candidate.node_id.as_ref() != owner) }); - let Some(source) = candidates.into_iter().next() else { + let Some((source, _)) = candidates.into_iter().next() else { view.master_kv_router() .inner() .planned_get_counters @@ -495,15 +699,36 @@ async fn handle_get_plan_item( msg_and_error::ApiError::KeyNotFound { key }, )); }; + let selected_requester_local_ssd = source.source_kind == GetSourceKind::Ssd + && local_owner + .as_deref() + .is_some_and(|owner| source.node_id.as_ref() == owner); + if selected_requester_local_ssd { + let counters = &view.master_kv_router().inner().ssd_tier_counters; + let (items, bytes) = if has_remote_memory_alternative { + ( + &counters.local_ssd_selected_with_remote_memory_items, + &counters.local_ssd_selected_with_remote_memory_bytes, + ) + } else { + ( + &counters.local_ssd_selected_without_remote_memory_items, + &counters.local_ssd_selected_without_remote_memory_bytes, + ) + }; + items.fetch_add(1, Ordering::Relaxed); + bytes.fetch_add(source.len, Ordering::Relaxed); + } let get_id = view .master_kv_router() .inner() .next_get_id .fetch_add(1, Ordering::Relaxed); - let gpu_direct_eligible = local_owner - .as_deref() - .is_none_or(|owner| source.node_id.as_ref() != owner); + let gpu_direct_eligible = source.source_kind == GetSourceKind::Memory + && local_owner + .as_deref() + .is_none_or(|owner| source.node_id.as_ref() != owner); let planned = super::PlannedGetInfo { put_id: route.put_id, src_node_id: source.node_id.clone(), @@ -514,6 +739,7 @@ async fn handle_get_plan_item( len: source.len, src_addr: source.addr, src_base_addr: source.base_addr, + source_kind: source.source_kind, atomic_group: route.atomic_group.as_deref().cloned(), }; drop(route); @@ -534,6 +760,7 @@ async fn handle_get_plan_item( src_addr: planned.src_addr, src_base_addr: planned.src_base_addr, len: planned.len, + source_kind: planned.source_kind, atomic_group: planned.atomic_group, gpu_direct_eligible, error_code: msg_and_error::OK, @@ -570,6 +797,7 @@ fn bound_get_start_item(get_id: u64, info: &InflightGetInfo) -> BatchGetStartIte target_base_addr: info.target.base_addr(), src_base_addr: info.src_base_addr, len: info.len, + source_kind: info.source_kind, prepared_target: match &info.target { InflightGetTarget::PreparedLocalReserveSlot(slot) => { Some(GetPreparedLocalReserveTarget { @@ -639,6 +867,16 @@ async fn handle_get_bind_item( let (target, target_tomb_tag, allocation_mode, prepared_requester_lease) = match &request.target { GetBindTarget::ExternalSink(target) => { + if planned.source_kind == GetSourceKind::Ssd { + return get_bind_item_error( + get_id, + &msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { + detail: format!( + "SSD Get source requires owner-local CPU staging before an external GPU sink: get_id={get_id}" + ), + }), + ); + } if req_node_id != planned.controller_node_id { return get_bind_item_error( get_id, @@ -755,10 +993,10 @@ async fn handle_get_bind_item( }; if matches!(&request.target, GetBindTarget::PreparedLocalReserve(_)) && current_route - .nodes_replicas + .node_replicas .read() .get(&req_node_id) - .is_some_and(|replica| !replica.tomb_tag.is_tomb()) + .is_some_and(|replica| !replica.tomb_tag.is_tomb() && replica.memory.is_some()) { return get_bind_item_error( get_id, @@ -771,6 +1009,22 @@ async fn handle_get_bind_item( ); } + let (src_addr, src_base_addr, ssd_source_allocation) = match planned.source_kind { + GetSourceKind::Memory => (planned.src_addr, planned.src_base_addr, None), + GetSourceKind::Ssd => { + let allocation = + match allocate_ssd_source_stage(&view, &planned.src_node_id, planned.len) { + Ok(allocation) => allocation, + Err(err) => return get_bind_item_error(get_id, &err), + }; + ( + allocation.base_addr() + allocation.addr(), + allocation.base_addr(), + Some(allocation), + ) + } + }; + let Some(planned) = view .master_kv_router() .inner() @@ -792,8 +1046,12 @@ async fn handle_get_bind_item( req_node_id: req_node_id.clone(), controller_node_id: Some(planned.controller_node_id), len: planned.len, - src_addr: planned.src_addr, - src_base_addr: planned.src_base_addr, + src_addr, + src_base_addr, + source_kind: planned.source_kind, + ssd_source_allocation, + ssd_stage_lifecycle: (planned.source_kind == GetSourceKind::Ssd) + .then(|| Arc::new(super::SsdStageLifecycle::new())), atomic_group: planned.atomic_group, target, target_tomb_tag, @@ -809,6 +1067,8 @@ async fn handle_get_bind_item( inflight.src_node_id.as_ref(), inflight.len, allocation_mode, + inflight.source_kind, + inflight.src_node_id == inflight.req_node_id, ); view.master_kv_router() .inner() @@ -820,7 +1080,7 @@ async fn handle_get_bind_item( .planned_get_counters .bind_succeeded .fetch_add(1, Ordering::Relaxed); - if current_route.lease_id.is_none() { + if current_route.lease_id.is_none() && planned.source_kind == GetSourceKind::Memory { touch_moka_for_node(view, response.node_id.to_string(), planned.key); } response @@ -880,7 +1140,7 @@ pub async fn handle_get_start( let mut remove_in_kv_routes = false; if let Some(one_kv_nodes_routes) = view.master_kv_router().inner().kv_routes.get(key) { one_kv_nodes_routes.clean_up_tomb_nodes_replicas(put_id, tombs, view); - if one_kv_nodes_routes.nodes_replicas.read().is_empty() { + if one_kv_nodes_routes.node_replicas.read().is_empty() { remove_in_kv_routes = true; } } @@ -966,30 +1226,44 @@ pub async fn handle_get_start( return failed_resp_err(err, None, &view, &req.serialize_part.key); }; - let replicas: HashMap = one_kv_nodes_routes.nodes_replicas.read().clone(); + let replicas: HashMap = + one_kv_nodes_routes.node_replicas.read().clone(); let prepared_target = req.serialize_part.prepared_target.clone(); let external_sink_target = req.serialize_part.external_sink_target.clone(); let external_sink_local_owner = external_sink_target.as_ref().and_then(|target| { external_sink_local_owner_id(&view, &req_node_id, target.requester_node_start_time) }); - // Currently we are holding the lock with `replicas` - // 选择一个replica (这里可以实现更复杂的选择逻辑) - let mut replica_keys = replicas.keys().collect::>(); - let mut tombs = HashSet::new(); + let mut tombs = replicas + .iter() + .filter_map(|(node_id, replicas)| replicas.tomb_tag.is_tomb().then_some(node_id.clone())) + .collect::>(); + let mut memory_sources = replicas + .iter() + .filter_map(|(node_id, replicas)| { + (!replicas.tomb_tag.is_tomb() && replicas.memory.is_some()) + .then_some((node_id.clone(), GetSourceKind::Memory)) + }) + .collect::>(); + let mut ssd_sources = replicas + .iter() + .filter_map(|(node_id, replicas)| { + (!replicas.tomb_tag.is_tomb() && replicas.memory.is_none() && replicas.ssd.is_some()) + .then_some((node_id.clone(), GetSourceKind::Ssd)) + }) + .collect::>(); + memory_sources.shuffle(&mut rand::thread_rng()); + ssd_sources.shuffle(&mut rand::thread_rng()); + memory_sources.extend(ssd_sources); let mut target = None; let mut allocation_mode = GetAllocationMode::Temporary; let mut durable_reservation = None; - for _ in 0..replicas.len() { - let to_remove_idx = rand::thread_rng().gen_range(0..replica_keys.len()); - let selected_replica_key = replica_keys.remove(to_remove_idx); - let selected_replica = replicas.get(&*selected_replica_key).unwrap(); - if selected_replica.tomb_tag.is_tomb() { - tombs.insert(selected_replica_key.to_owned()); - continue; - } + for (selected_replica_key, source_kind) in memory_sources { + let selected_replicas = replicas + .get(&selected_replica_key) + .expect("selected Get source must exist"); if external_sink_local_owner .as_deref() - .is_some_and(|owner_id| selected_replica.node_id.as_ref() == owner_id) + .is_some_and(|owner_id| selected_replica_key.as_ref() == owner_id) { // The explicit GPU path is RDMA-only. The requester's share-group // owner is local IPC/P2P topology, whose fallback would require @@ -997,10 +1271,47 @@ pub async fn handle_get_start( // ordinary CPU-buffered Get path and search for a remote route. continue; } - let src_node_id = selected_replica.node_id.clone(); - let src_len = selected_replica.backing.len(); - let src_abs_addr = selected_replica.backing.abs_addr(); - let src_base = selected_replica.backing.base_addr(); + if source_kind == GetSourceKind::Ssd && external_sink_target.is_some() { + continue; + } + let src_node_id = selected_replica_key; + let (src_len, src_abs_addr, src_base, ssd_source_allocation) = match source_kind { + GetSourceKind::Memory => { + let selected_replica = selected_replicas + .memory + .as_ref() + .expect("memory source candidate must retain memory"); + ( + selected_replica.backing.len(), + selected_replica.backing.abs_addr(), + selected_replica.backing.base_addr(), + None, + ) + } + GetSourceKind::Ssd => { + let ssd = selected_replicas + .ssd + .as_ref() + .expect("SSD source candidate must retain SSD"); + let allocation = match allocate_ssd_source_stage(&view, &src_node_id, ssd.len) { + Ok(allocation) => allocation, + Err(err) => { + return failed_resp_err( + err, + Some((tombs.clone(), one_kv_nodes_routes.put_id)), + &view, + &req.serialize_part.key, + ); + } + }; + ( + ssd.len, + allocation.base_addr() + allocation.addr(), + allocation.base_addr(), + Some(allocation), + ) + } + }; // For committed-slot replicas on the requester node, we still allocate a // normal target buffer here instead of reusing the committed slot as a @@ -1045,14 +1356,12 @@ pub async fn handle_get_start( } if allocated_addr.is_none() { tracing::info!("No space left for target(Requesting node) allocation"); - let total = target_allocator.total_size_bytes(); - let used = target_allocator.used_size_bytes(); - let free = total.saturating_sub(used); + let capacity = target_allocator.node_pool_capacity_snapshot(); let err = msg_and_error::KvError::Api(msg_and_error::ApiError::NoSpace { node: req_node_id.as_ref().to_string(), segment: target_allocator.seg_device_id.clone(), - total_capacity: total, - free_capacity: free, + total_capacity: capacity.active_capacity_bytes, + free_capacity: capacity.available_capacity_bytes, }); return Err(failed_resp_err( err, @@ -1092,10 +1401,9 @@ pub async fn handle_get_start( allocation_mode = GetAllocationMode::ExternalSink; InflightGetTarget::ExternalSink(external_sink_target.clone()) } else if let Some(prepared_target) = prepared_target.as_ref() { - if replicas - .get(&req_node_id) - .is_some_and(|replica| !replica.tomb_tag.is_tomb()) - { + if replicas.get(&req_node_id).is_some_and(|replicas| { + !replicas.tomb_tag.is_tomb() && replicas.memory.is_some() + }) { let err = msg_and_error::KvError::Api( msg_and_error::ApiError::InvalidArgument { detail: format!( @@ -1129,7 +1437,11 @@ pub async fn handle_get_start( }; allocation_mode = GetAllocationMode::LocalCommittedSlot; InflightGetTarget::PreparedLocalReserveSlot(slot) - } else if let Some(replica_on_recv_node) = replicas.get(&req_node_id) { + } else if let Some(replica_on_recv_node) = replicas + .get(&req_node_id) + .filter(|replicas| !replicas.tomb_tag.is_tomb()) + .and_then(|replicas| replicas.memory.as_ref()) + { match &replica_on_recv_node.backing { super::KvReplicaBacking::Allocation(allocation) => { allocation_mode = GetAllocationMode::ReuseReplica; @@ -1219,6 +1531,7 @@ pub async fn handle_get_start( src_base_addr: resp_src_base, target_base_addr: resp_target_base, len: src_len, + source_kind, prepared_target: (allocation_mode == GetAllocationMode::LocalCommittedSlot) .then(|| prepared_target.clone()) .flatten(), @@ -1232,6 +1545,8 @@ pub async fn handle_get_start( resp_node_id.as_ref(), src_len, allocation_mode, + source_kind, + src_node_id == req_node_id, ); // 创建在途的Get操作信息 let info = InflightGetInfo { @@ -1243,6 +1558,10 @@ pub async fn handle_get_start( len: src_len, src_addr: resp_src_addr, src_base_addr: resp_src_base, + source_kind, + ssd_source_allocation, + ssd_stage_lifecycle: (source_kind == GetSourceKind::Ssd) + .then(|| Arc::new(super::SsdStageLifecycle::new())), atomic_group: one_kv_nodes_routes.atomic_group.as_deref().cloned(), target, target_tomb_tag, @@ -1263,7 +1582,7 @@ pub async fn handle_get_start( // source node's moka to keep the kv alive during transfer (weight=0 => touch). // For leased keys, there should be no moka entry; skip touching to avoid // unnecessary cache work. - if one_kv_nodes_routes.lease_id.is_none() { + if one_kv_nodes_routes.lease_id.is_none() && source_kind == GetSourceKind::Memory { touch_moka_for_node( view.clone(), src_node_id.to_string(), @@ -1298,6 +1617,179 @@ pub async fn handle_get_start( } } +pub async fn handle_ssd_stage_begin( + view: MasterKvRouterView, + req: MsgPack, + req_node_id: NodeID, +) -> MsgPack { + let get_id = req.serialize_part.get_id; + let operation_lock = view + .master_kv_router() + .inner() + .get_done_locks + .get_lock(get_id); + let _operation_guard = operation_lock.lock().await; + let result = view + .master_kv_router() + .inner() + .inflight_gets + .get(&get_id) + .await + .and_then(|inflight| { + (inflight.source_kind == GetSourceKind::Ssd + && inflight.src_node_id == req_node_id + && inflight.ssd_source_allocation.is_some()) + .then(|| inflight.ssd_stage_lifecycle.as_ref().cloned()) + .flatten() + }) + .is_some_and(|lifecycle| lifecycle.begin()); + MsgPack { + serialize_part: SsdStageBeginResp { + started: result, + error_code: msg_and_error::OK, + error_json: String::new(), + }, + raw_bytes: Vec::new(), + } +} + +pub async fn handle_ssd_stage_done( + view: MasterKvRouterView, + req: MsgPack, + req_node_id: NodeID, +) -> MsgPack { + let get_id = req.serialize_part.get_id; + let operation_lock = view + .master_kv_router() + .inner() + .get_done_locks + .get_lock(get_id); + let _operation_guard = operation_lock.lock().await; + let Some(inflight) = view + .master_kv_router() + .inner() + .inflight_gets + .get(&get_id) + .await + else { + return MsgPack { + serialize_part: SsdStageDoneResp { + error_code: msg_and_error::OK, + error_json: String::new(), + }, + raw_bytes: Vec::new(), + }; + }; + if inflight.source_kind != GetSourceKind::Ssd + || !ssd_stage_done_request_authorized( + &inflight.src_node_id, + &inflight.req_node_id, + &req_node_id, + req.serialize_part.drop_ssd_source, + ) + { + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { + detail: format!( + "SSD stage terminal requester mismatch: get_id={} source={} target={} got={} drop_ssd_source={}", + get_id, + inflight.src_node_id, + inflight.req_node_id, + req_node_id, + req.serialize_part.drop_ssd_source, + ), + }); + return MsgPack { + serialize_part: SsdStageDoneResp { + error_code: err.code(), + error_json: err.to_json(), + }, + raw_bytes: Vec::new(), + }; + } + if let Some(lifecycle) = inflight.ssd_stage_lifecycle.as_ref() { + lifecycle.finish(); + } + + let mut removed_empty_route = None; + if req.serialize_part.drop_ssd_source { + let route = inflight.route.clone(); + if route.put_id == inflight.put_id && route.remove_ssd_replica(&inflight.src_node_id) { + let key = inflight.key.clone(); + if route.node_replicas.read().is_empty() + && view + .master_kv_router() + .inner() + .kv_routes + .remove_if(&key, |_, current| { + Arc::ptr_eq(current, &route) + && current.put_id == inflight.put_id + && current.node_replicas.read().is_empty() + }) + .is_some() + { + removed_empty_route = Some((key, inflight.put_id)); + } + } + } + drop(inflight); + if let Some((key, put_id)) = removed_empty_route + && view.master_kv_router().prefix_index_enabled() + { + view.master_kv_router() + .inner() + .prefix_index + .write() + .await + .remove(&key, put_id); + } + + MsgPack { + serialize_part: SsdStageDoneResp { + error_code: msg_and_error::OK, + error_json: String::new(), + }, + raw_bytes: Vec::new(), + } +} + +fn ssd_stage_done_request_authorized( + source_node_id: &NodeID, + target_node_id: &NodeID, + requester_node_id: &NodeID, + drop_ssd_source: bool, +) -> bool { + requester_node_id == source_node_id || (!drop_ssd_source && requester_node_id == target_node_id) +} + +#[cfg(test)] +mod ssd_stage_done_authorization_tests { + use super::ssd_stage_done_request_authorized; + use crate::cluster_manager::NodeID; + + #[test] + fn source_may_close_or_drop_but_target_may_only_close() { + let source: NodeID = "cpu-source".to_string().into(); + let target: NodeID = "gpu-target".to_string().into(); + let stranger: NodeID = "other-owner".to_string().into(); + + assert!(ssd_stage_done_request_authorized( + &source, &target, &source, false + )); + assert!(ssd_stage_done_request_authorized( + &source, &target, &source, true + )); + assert!(ssd_stage_done_request_authorized( + &source, &target, &target, false + )); + assert!(!ssd_stage_done_request_authorized( + &source, &target, &target, true + )); + assert!(!ssd_stage_done_request_authorized( + &source, &target, &stranger, false + )); + } +} + pub async fn handle_get_revoke( view: MasterKvRouterView, req: MsgPack, @@ -1311,7 +1803,27 @@ pub async fn handle_get_revoke( .inner() .get_done_locks .get_lock(get_id); - let _done_guard = done_lock.lock().await; + let _done_guard = loop { + let guard = done_lock.lock().await; + let active_lifecycle = view + .master_kv_router() + .inner() + .inflight_gets + .get(&get_id) + .await + .and_then(|inflight| { + inflight + .ssd_stage_lifecycle + .as_ref() + .filter(|lifecycle| lifecycle.is_active()) + .cloned() + }); + let Some(lifecycle) = active_lifecycle else { + break guard; + }; + drop(guard); + lifecycle.wait_until_not_active().await; + }; if let Some(planned) = view .master_kv_router() @@ -1695,8 +2207,7 @@ async fn handle_get_done_locked( target_cap, ) { Ok(capacity_reservation) => { - let replica = KvRouteInfo { - node_id: req_node_id.clone(), + let replica = KvMemoryReplica { backing: super::KvReplicaBacking::Allocation(match &inflight_info .target { @@ -1711,12 +2222,12 @@ async fn handle_get_done_locked( owner_local_indexed: true, get_durable_reservation: inflight_info.durable_reservation.clone(), capacity_reservation, - tomb_tag: target_tomb_tag.clone(), }; if publish_route_replica_tomb_fenced( &one_kv_nodes_routes, req_node_id.clone(), replica, + target_tomb_tag.clone(), ) { promote_committed = true; route_publish_event = Some(RoutePublishEvent::replica_append( @@ -1787,20 +2298,26 @@ async fn handle_get_done_locked( { if current_route.put_id == inflight_info.put_id { route_lease_id = current_route.lease_id; - let mut replicas = current_route.nodes_replicas.write(); - if let Some(replica) = replicas.get_mut(&req_node_id) { - local_index_published = !replica.tomb_tag.is_tomb() - && replica.tomb_tag.same_generation(target_tomb_tag) - && matches!( - &replica.backing, - super::KvReplicaBacking::Allocation(allocation) - if matches!( - &inflight_info.target, - InflightGetTarget::Allocation(target) - if Arc::ptr_eq(allocation, target) - ) - ); + let mut replicas = current_route.node_replicas.write(); + if let Some(node_replicas) = replicas.get_mut(&req_node_id) { + local_index_published = !node_replicas.tomb_tag.is_tomb() + && node_replicas.tomb_tag.same_generation(target_tomb_tag) + && node_replicas.memory.as_ref().is_some_and(|replica| { + matches!( + &replica.backing, + super::KvReplicaBacking::Allocation(allocation) + if matches!( + &inflight_info.target, + InflightGetTarget::Allocation(target) + if Arc::ptr_eq(allocation, target) + ) + ) + }); if local_index_published { + let replica = node_replicas + .memory + .as_mut() + .expect("matched live memory replica"); replica.owner_local_indexed = true; replica.capacity_reservation = capacity_reservation; } @@ -1867,18 +2384,17 @@ async fn handle_get_done_locked( let mut route_publish_event = None; if let Some(current_route) = view.master_kv_router().inner().kv_routes.get(&key) { if current_route.put_id == inflight_info.put_id { - let replica = KvRouteInfo { - node_id: req_node_id.clone(), + let replica = KvMemoryReplica { backing: super::KvReplicaBacking::CommittedSlot(slot), owner_local_indexed: true, get_durable_reservation: None, capacity_reservation: None, - tomb_tag: target_tomb_tag.clone(), }; if publish_route_replica_tomb_fenced( ¤t_route, req_node_id.clone(), replica, + target_tomb_tag.clone(), ) { published = true; route_publish_event = Some(RoutePublishEvent::replica_append( @@ -2118,15 +2634,22 @@ pub async fn handle_get_meta( .get(&req.serialize_part.key) { // lock and clone, release the lock quickly - let nodes_replicas: HashMap = - (*one_kv_nodes_routes.nodes_replicas.read()).clone(); + let node_replicas: HashMap = + (*one_kv_nodes_routes.node_replicas.read()).clone(); // Key exists, get metadata from the first replica - for (_, kv_info) in nodes_replicas.iter() { - if kv_info.tomb_tag.is_tomb() { + for replicas in node_replicas.values() { + if replicas.tomb_tag.is_tomb() { continue; } - let len = kv_info.backing.len(); + let Some(len) = replicas + .memory + .as_ref() + .map(|memory| memory.backing.len()) + .or_else(|| replicas.ssd.as_ref().map(|ssd| ssd.len)) + else { + continue; + }; return MsgPack { serialize_part: GetMetaResp { exists: true, @@ -2308,6 +2831,7 @@ pub async fn handle_batch_get_start( target_base_addr: part.target_base_addr, src_base_addr: part.src_base_addr, len: part.len, + source_kind: part.source_kind, prepared_target: part.prepared_target, atomic_group: part.atomic_group, error_code: part.error_code, diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs index d5c43ee..f09f84e 100644 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/mod.rs @@ -17,27 +17,29 @@ use self::{ get::{ handle_batch_get_bind, handle_batch_get_done, handle_batch_get_plan, handle_batch_get_revoke, handle_batch_get_start, handle_batch_is_exist, handle_get_done, - handle_get_meta, handle_get_revoke, handle_get_start, + handle_get_meta, handle_get_revoke, handle_get_start, handle_ssd_stage_begin, + handle_ssd_stage_done, }, msg_pack::{ BatchDeleteAckReq, BatchDeleteClientKvMetaCacheReq, BatchEnqueueReplicaTaskReq, BatchEvictOwnerSourceReq, BatchGetBindReq, BatchGetDoneReq, BatchGetPlanReq, BatchGetRevokeReq, BatchGetStartReq, BatchIsExistReq, BatchOwnerReclaimReq, - BatchPreparePutKeysReq, BatchPutAppendDoneReq, BatchPutAppendStartReq, BatchPutDoneReq, - BatchPutRevokeReq, BatchPutStartReq, BatchReleasePutKeyReservationsReq, CountPrefixReq, - CountPrefixResp, DeleteAckReq, DeleteReq, GetAllocationMode, GetDoneReq, GetDoneResp, - GetMetaReq, GetRevokeReq, GetStartReq, GroupedBatchPutDoneReq, OwnerReclaimItem, - PutAppendDoneReq, PutAppendRevokeReq, PutAppendStartReq, PutAtomicGroup, PutDoneReq, - PutRevokeReq, PutStartReq, ReleaseLocalGrantReq, ReserveLocalGrantReq, + BatchPreparePutKeysReq, BatchPublishOwnerSsdReq, BatchPutAppendDoneReq, + BatchPutAppendStartReq, BatchPutDoneReq, BatchPutRevokeReq, BatchPutStartReq, + BatchReleasePutKeyReservationsReq, CountPrefixReq, CountPrefixResp, DeleteAckReq, + DeleteReq, GetAllocationMode, GetDoneReq, GetDoneResp, GetMetaReq, GetRevokeReq, + GetSourceKind, GetStartReq, GroupedBatchPutDoneReq, OwnerReclaimItem, PutAppendDoneReq, + PutAppendRevokeReq, PutAppendStartReq, PutAtomicGroup, PutDoneReq, PutRevokeReq, + PutStartReq, ReleaseLocalGrantReq, ReserveLocalGrantReq, SsdStageBeginReq, SsdStageDoneReq, }, placement::{PlacementPolicy, build_placement_policy}, put::{ - handle_batch_prepare_put_keys, handle_batch_put_append_done, handle_batch_put_append_start, - handle_batch_put_done, handle_batch_put_revoke, handle_batch_put_start, - handle_batch_release_put_key_reservations, handle_grouped_batch_put_done, - handle_put_append_done, handle_put_append_revoke, handle_put_append_start, handle_put_done, - handle_put_revoke, handle_put_start, handle_release_local_grant, - handle_reserve_local_grant, + handle_batch_prepare_put_keys, handle_batch_publish_owner_ssd, + handle_batch_put_append_done, handle_batch_put_append_start, handle_batch_put_done, + handle_batch_put_revoke, handle_batch_put_start, handle_batch_release_put_key_reservations, + handle_grouped_batch_put_done, handle_put_append_done, handle_put_append_revoke, + handle_put_append_start, handle_put_done, handle_put_revoke, handle_put_start, + handle_release_local_grant, handle_reserve_local_grant, }, reclaim::handle_batch_evict_owner_source, }; @@ -53,16 +55,20 @@ use crate::master_lease_manager::{MasterLeaseManager, MasterLeaseManagerAccessTr use crate::master_seg_manager::MasterSegManager; use crate::master_seg_manager::MasterSegManagerAccessTrait; use crate::master_seg_manager::NodeTombTag; -use crate::master_seg_manager::one_seg_allocator::Allocation; +use crate::master_seg_manager::one_seg_allocator::{Allocation, NodePoolCapacitySnapshot}; use crate::memholder::{EnsureMemholderMgmtDeleteHandle, MasterOwnerMemMgr, MemholderManagerTrait}; use crate::metric_reporter::{MetricReporter, MetricReporterAccessTrait}; use crate::p2p::msg_pack::{MsgPack, RPCCaller, RPCHandler}; -use crate::p2p::p2p_module::{P2pModule, P2pModuleAccessTrait}; -use crate::rpcresp_kvresult_convert::msg_and_error::{KvError, OK}; +use crate::p2p::p2p_module::{ + P2pModule, P2pModuleAccessTrait, UserRpcAsyncHandler, UserRpcFuture, + user_rpc_register_handler_async, +}; +use crate::rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, KvResult, OK}; use fluxon_framework::{LogicalModule, define_module}; use fluxon_util::map_lock::AMapLock; use fluxon_util::pin_aware_moka::{PinAwareMoka, PinGuard}; +use ::tokio::sync::watch; use async_trait::async_trait; use chrono::Utc; use dashmap::{DashMap, DashSet}; @@ -71,6 +77,7 @@ use limit_thirdparty::tokio::{self, sync::ampsc}; use moka::notification::RemovalCause; use parking_lot::Mutex; use parking_lot::RwLock; +use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::collections::HashSet; use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering}; @@ -84,6 +91,7 @@ const INFLIGHT_PUT_TTL_SECONDS: u64 = 60; const INFLIGHT_PUT_TTL_SECONDS_SKIP_PUT_END_COMMIT: u64 = 5; const POST_ROUTE_MAINTENANCE_QUEUE_CAPACITY: usize = 512; const TIER1_WRITEBACK_QUEUE_CAPACITY: usize = 4096; +pub const NODE_POOL_CAPACITY_USER_RPC_PATH: &str = "fluxon_kv/node_pool_capacity"; fn subtract_pending_eviction_weight( pending_weight: &AtomicU64, @@ -300,6 +308,14 @@ pub struct RequesterTargetPair { #[derive(Clone, Debug, Default)] pub struct ReplicaCacheNodeObserveSnapshot { pub owner_node: String, + pub owner_node_start_time: i64, + pub pool_physical_capacity_bytes: u64, + pub pool_active_capacity_bytes: u64, + pub pool_used_capacity_bytes: u64, + pub pool_parked_capacity_bytes: u64, + pub pool_draining_capacity_bytes: u64, + pub pool_available_capacity_bytes: u64, + pub pool_capacity_epoch: u64, pub entries: u64, pub weighted_bytes: u64, pub effective_capacity_bytes: u64, @@ -343,6 +359,93 @@ pub struct MasterRuntimeObserveSnapshot { pub replica_cache_nodes: Vec, } +/// Generation- and epoch-fenced runtime control request for one owner's preallocated pool. +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[serde(tag = "operation", rename_all = "snake_case", deny_unknown_fields)] +pub enum NodePoolCapacityControlRequest { + Get { + owner_node_id: String, + }, + SetActive { + owner_node_id: String, + expected_owner_node_start_time: i64, + expected_capacity_epoch: u64, + active_capacity_bytes: u64, + }, +} + +/// One coherent snapshot returned by both query and mutation operations. +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct NodePoolCapacityControlResponse { + pub owner_node_id: String, + pub owner_node_start_time: i64, + pub physical_capacity_bytes: u64, + pub active_capacity_bytes: u64, + pub used_capacity_bytes: u64, + pub parked_capacity_bytes: u64, + pub draining_capacity_bytes: u64, + pub available_capacity_bytes: u64, + pub capacity_epoch: u64, + pub ring_b_base_capacity_bytes: u64, + pub ring_b_effective_capacity_bytes: u64, + pub ring_b_weighted_bytes: u64, + pub ring_b_pending_reclaim_bytes: u64, + pub tier1_capacity_bytes: u64, + pub settled: bool, +} + +struct NodePoolCapacityUserRpcHandler { + view: MasterKvRouterView, +} + +impl UserRpcAsyncHandler for NodePoolCapacityUserRpcHandler { + fn handle(&self, from_node: NodeID, payload: Vec) -> UserRpcFuture { + let view = self.view.clone(); + Box::pin(async move { + let request: NodePoolCapacityControlRequest = serde_json::from_slice(&payload) + .map_err(|err| { + KvError::Api(ApiError::InvalidArgument { + detail: format!("invalid node pool capacity request: {err}"), + }) + })?; + let response = match request { + NodePoolCapacityControlRequest::Get { owner_node_id } => view + .master_kv_router() + .node_pool_capacity_control_snapshot(&owner_node_id)?, + NodePoolCapacityControlRequest::SetActive { + owner_node_id, + expected_owner_node_start_time, + expected_capacity_epoch, + active_capacity_bytes, + } => { + tracing::info!( + caller = %from_node, + owner = %owner_node_id, + expected_owner_node_start_time, + expected_capacity_epoch, + active_capacity_bytes, + "applying node pool active capacity" + ); + view.master_kv_router() + .set_node_pool_active_capacity( + owner_node_id.into(), + expected_owner_node_start_time, + expected_capacity_epoch, + active_capacity_bytes, + ) + .await? + } + }; + serde_json::to_vec(&response).map_err(|err| { + KvError::Api(ApiError::Unknown { + detail: format!("serialize node pool capacity response failed: {err}"), + }) + }) + }) + } +} + impl RequesterTargetPair { fn new(requester_node_id: &str, target_node_id: &str) -> Self { Self { @@ -435,6 +538,10 @@ pub struct InflightGetInfo { pub len: u64, pub src_addr: u64, pub src_base_addr: u64, + pub source_kind: crate::master_kv_router::msg_pack::GetSourceKind, + /// Registered source staging owned by the master only for SSD reads. + pub ssd_source_allocation: Option>, + pub(crate) ssd_stage_lifecycle: Option>, pub atomic_group: Option, pub target: InflightGetTarget, /// Exact requester segment-registration generation that owns an @@ -451,6 +558,70 @@ pub struct InflightGetInfo { pub(crate) _prepared_requester_lease: Option>, } +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum SsdStagePhase { + NotStarted, + Active, + Quiescent, +} + +pub(crate) struct SsdStageLifecycle { + phase: Mutex, + phase_changed: watch::Sender, +} + +impl SsdStageLifecycle { + fn new() -> Self { + let (phase_changed, _receiver) = watch::channel(SsdStagePhase::NotStarted); + Self { + phase: Mutex::new(SsdStagePhase::NotStarted), + phase_changed, + } + } + + pub(crate) fn begin(&self) -> bool { + let mut phase = self.phase.lock(); + match *phase { + SsdStagePhase::NotStarted => { + *phase = SsdStagePhase::Active; + self.phase_changed.send_replace(SsdStagePhase::Active); + true + } + // An RPC response can be lost after the master accepted Begin. + // Replaying the exact source/get operation must not make the owner + // abandon a stage which the master already considers active. + SsdStagePhase::Active => true, + SsdStagePhase::Quiescent => false, + } + } + + pub(crate) fn finish(&self) -> bool { + let mut phase = self.phase.lock(); + if *phase != SsdStagePhase::Active { + return false; + } + *phase = SsdStagePhase::Quiescent; + self.phase_changed.send_replace(SsdStagePhase::Quiescent); + true + } + + pub(crate) fn is_active(&self) -> bool { + *self.phase.lock() == SsdStagePhase::Active + } + + pub(crate) async fn wait_until_not_active(&self) { + let mut phase_changed = self.phase_changed.subscribe(); + loop { + if *phase_changed.borrow_and_update() != SsdStagePhase::Active { + return; + } + if phase_changed.changed().await.is_err() { + return; + } + } + } +} + /// A metadata-only Get source snapshot before caller-owned destination binding. /// /// This type must not own a route, allocation, activity lease, cache pin, or @@ -467,6 +638,7 @@ pub struct PlannedGetInfo { pub len: u64, pub src_addr: u64, pub src_base_addr: u64, + pub source_kind: crate::master_kv_router::msg_pack::GetSourceKind, pub atomic_group: Option, } @@ -602,6 +774,24 @@ pub(crate) struct MasterPlannedGetCounters { bind_stale: AtomicU64, bind_activity_busy: AtomicU64, plan_revoked: AtomicU64, + remote_ssd_filtered_items: AtomicU64, + remote_ssd_filtered_bytes: AtomicU64, +} + +#[derive(Default)] +pub(crate) struct MasterSsdTierCounters { + local_ssd_selected_with_remote_memory_items: AtomicU64, + local_ssd_selected_with_remote_memory_bytes: AtomicU64, + local_ssd_selected_without_remote_memory_items: AtomicU64, + local_ssd_selected_without_remote_memory_bytes: AtomicU64, + local_ssd_published_with_remote_memory_items: AtomicU64, + local_ssd_published_with_remote_memory_bytes: AtomicU64, + local_ssd_published_without_remote_memory_items: AtomicU64, + local_ssd_published_without_remote_memory_bytes: AtomicU64, + memory_removed_ssd_survived_items: AtomicU64, + memory_removed_ssd_survived_bytes: AtomicU64, + memory_removed_ssd_became_only_items: AtomicU64, + memory_removed_ssd_became_only_bytes: AtomicU64, } #[derive(Clone, Copy, Debug)] @@ -1009,8 +1199,7 @@ impl KvReplicaBacking { } #[derive(Clone, Debug)] -pub struct KvRouteInfo { - pub node_id: NodeID, +pub struct KvMemoryReplica { pub backing: KvReplicaBacking, /// Whether this owner also published the route backing into its local key index. /// Replica-task and remote-put targets are raw master-owned allocations and have no @@ -1023,7 +1212,44 @@ pub struct KvRouteInfo { /// Excludes a non-ring-B backing from the unindexed-Allocation budget and /// is released with the exact route lifetime. pub capacity_reservation: Option>, +} + +#[derive(Clone, Debug)] +pub struct KvSsdReplica { + pub len: u64, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(crate) enum SsdReplicaCommitStatus { + Committed, + MissingMemory, + TombedNode, + LengthMismatch, +} + +/// All physical backings contributed by one owner generation for one key-version. +/// +/// Route, version, and owner generation stay common. Storage tiers only own their +/// medium-specific state, so adding SSD does not create a second route lifecycle. +#[derive(Clone, Debug)] +pub struct KvNodeReplicas { pub tomb_tag: NodeTombTag, + pub memory: Option, + pub ssd: Option, +} + +impl KvNodeReplicas { + pub fn memory(tomb_tag: NodeTombTag, memory: KvMemoryReplica) -> Self { + Self { + tomb_tag, + memory: Some(memory), + ssd: None, + } + } + + pub fn has_live_backing(&self) -> bool { + !self.tomb_tag.is_tomb() && (self.memory.is_some() || self.ssd.is_some()) + } } pub struct GetDurableSlotReservation { @@ -1080,24 +1306,55 @@ pub struct OneKvNodesRoutes { /// Version-scoped multi-key group supplied by the put caller. pub atomic_group: Option>, - /// node_id -> KvRouteInfo - pub nodes_replicas: RwLock>, + /// node_id -> all backings owned by that exact node generation. + pub node_replicas: RwLock>, pub get_durable_slots_used: AtomicU32, } impl OneKvNodesRoutes { + pub(crate) fn commit_ssd_replica(&self, node_id: &NodeID, len: u64) -> SsdReplicaCommitStatus { + let mut replicas = self.node_replicas.write(); + let Some(node_replicas) = replicas.get_mut(node_id) else { + return SsdReplicaCommitStatus::MissingMemory; + }; + if node_replicas.tomb_tag.is_tomb() { + return SsdReplicaCommitStatus::TombedNode; + } + let Some(memory) = node_replicas.memory.as_ref() else { + return SsdReplicaCommitStatus::MissingMemory; + }; + if memory.backing.len() != len { + return SsdReplicaCommitStatus::LengthMismatch; + } + node_replicas.ssd = Some(KvSsdReplica { len }); + SsdReplicaCommitStatus::Committed + } + + pub(crate) fn remove_ssd_replica(&self, node_id: &NodeID) -> bool { + let mut replicas = self.node_replicas.write(); + let Some(node_replicas) = replicas.get_mut(node_id) else { + return false; + }; + let removed = node_replicas.ssd.take().is_some(); + if node_replicas.memory.is_none() { + replicas.remove(node_id); + } + removed + } + fn clean_up_tomb_nodes_replicas( &self, verify_put_id: PutIDForAKey, tombs: HashSet, - view: &MasterKvRouterView, + _view: &MasterKvRouterView, ) -> bool { if self.put_id != verify_put_id { return false; } - let mut nodes_replicas = self.nodes_replicas.write(); - nodes_replicas.retain(|_, kv_info| !tombs.contains(&kv_info.node_id)); + let mut node_replicas = self.node_replicas.write(); + node_replicas + .retain(|node_id, replicas| !tombs.contains(node_id) || !replicas.tomb_tag.is_tomb()); return true; } @@ -1139,9 +1396,10 @@ fn ring_b_route_replica_desc( if route.lease_id.is_some() { return None; } - let replicas = route.nodes_replicas.read(); - let replica = replicas.get(node_id)?; - if replica.tomb_tag.is_tomb() + let replicas = route.node_replicas.read(); + let node_replicas = replicas.get(node_id)?; + let replica = node_replicas.memory.as_ref()?; + if node_replicas.tomb_tag.is_tomb() || replica.owner_local_indexed || !matches!(&replica.backing, KvReplicaBacking::Allocation(_)) { @@ -1181,32 +1439,41 @@ pub(crate) fn node_generation_is_current_live( pub(crate) fn publish_route_replica_tomb_fenced( route: &OneKvNodesRoutes, node_id: NodeID, - replica: KvRouteInfo, + replica: KvMemoryReplica, + publish_tag: NodeTombTag, ) -> bool { - let publish_tag = replica.tomb_tag.clone(); if publish_tag.is_tomb() { return false; } - let mut replicas = route.nodes_replicas.write(); + let mut replicas = route.node_replicas.write(); if publish_tag.is_tomb() { return false; } - // A completion pre-check is necessarily racy with another completion for - // the same requester. Never replace a live replica here: only a tombed - // generation may be superseded. - if replicas - .get(&node_id) - .is_some_and(|current| !current.tomb_tag.is_tomb()) - { - return false; - } - let previous = replicas.insert(node_id.clone(), replica); + let previous = match replicas.get_mut(&node_id) { + Some(current) + if !current.tomb_tag.is_tomb() && current.tomb_tag.same_generation(&publish_tag) => + { + // A completion pre-check is necessarily racy with another completion. + // Preserve an already-published memory backing, while allowing the same + // generation to regain DRAM from an SSD-only route. + if current.memory.is_some() { + return false; + } + current.memory = Some(replica); + None + } + Some(current) if !current.tomb_tag.is_tomb() => return false, + _ => replicas.insert( + node_id.clone(), + KvNodeReplicas::memory(publish_tag.clone(), replica), + ), + }; if publish_tag.is_tomb() { - let published_is_current = replicas.get(&node_id).is_some_and(|current| { - current.node_id == node_id && current.tomb_tag.same_generation(&publish_tag) - }); + let published_is_current = replicas + .get(&node_id) + .is_some_and(|current| current.tomb_tag.same_generation(&publish_tag)); if published_is_current { replicas.remove(&node_id); if let Some(previous) = previous.filter(|old| !old.tomb_tag.is_tomb()) { @@ -1282,11 +1549,9 @@ fn remove_departed_generation_from_route( departed_tag: &NodeTombTag, ) -> Option { let became_empty = { - let mut replicas = route.nodes_replicas.write(); + let mut replicas = route.node_replicas.write(); let remove = replicas.get(node_id).is_some_and(|replica| { - replica.node_id.as_ref() == node_id - && replica.tomb_tag.is_tomb() - && replica.tomb_tag.same_generation(departed_tag) + replica.tomb_tag.is_tomb() && replica.tomb_tag.same_generation(departed_tag) }); if !remove { return None; @@ -1304,7 +1569,7 @@ fn remove_departed_generation_from_route( // `Arc::ptr_eq` prevents an old cleanup from removing a replacement route (ABA). // Recheck emptiness under the per-route read lock because another replica may have // joined after the write lock above was released. - Arc::ptr_eq(current, route) && current.nodes_replicas.read().is_empty() + Arc::ptr_eq(current, route) && current.node_replicas.read().is_empty() }) .map(|(_, removed)| removed.put_id) } @@ -1366,13 +1631,11 @@ async fn cleanup_departed_generation_routes( continue; }; let had_departed_replica = route - .nodes_replicas + .node_replicas .read() .get(node_id.as_str()) .is_some_and(|replica| { - replica.node_id.as_ref() == node_id.as_str() - && replica.tomb_tag.is_tomb() - && replica.tomb_tag.same_generation(&departed_tag) + replica.tomb_tag.is_tomb() && replica.tomb_tag.same_generation(&departed_tag) }); if !had_departed_replica { continue; @@ -1443,7 +1706,7 @@ mod tests { put_id: (1, 0), lease_id: None, atomic_group: None, - nodes_replicas: RwLock::new(HashMap::new()), + node_replicas: RwLock::new(HashMap::new()), get_durable_slots_used: AtomicU32::new(0), }); @@ -1456,13 +1719,36 @@ mod tests { drop(second); } + #[test] + fn ssd_stage_lifecycle_replays_begin_and_never_loses_quiescence() { + futures::executor::block_on(async { + let lifecycle = Arc::new(SsdStageLifecycle::new()); + assert!(lifecycle.begin()); + assert!( + lifecycle.begin(), + "a lost Begin response must replay Active as accepted" + ); + + let waiter = lifecycle.wait_until_not_active(); + let finisher = async { + assert!(lifecycle.is_active()); + assert!(lifecycle.finish()); + }; + futures::future::join(waiter, finisher).await; + + assert!(!lifecycle.finish()); + assert!(!lifecycle.begin()); + lifecycle.wait_until_not_active().await; + }); + } + #[test] fn durable_slot_token_returns_capacity_across_ten_fill_demote_cycles() { let routes = Arc::new(OneKvNodesRoutes { put_id: (1, 0), lease_id: None, atomic_group: None, - nodes_replicas: RwLock::new(HashMap::new()), + node_replicas: RwLock::new(HashMap::new()), get_durable_slots_used: AtomicU32::new(0), }); @@ -1680,9 +1966,8 @@ mod tests { ); } - fn test_route_info_with_tag(node_id: &str, tomb_tag: NodeTombTag) -> KvRouteInfo { - KvRouteInfo { - node_id: node_id.to_string().into(), + fn test_memory_replica(node_id: &str) -> KvMemoryReplica { + KvMemoryReplica { backing: KvReplicaBacking::CommittedSlot(CommittedSlotReplica { owner_node_id: node_id.to_string().into(), grant_id: 1, @@ -1695,11 +1980,14 @@ mod tests { owner_local_indexed: true, get_durable_reservation: None, capacity_reservation: None, - tomb_tag, } } - fn test_route_info(node_id: &str, tomb: bool) -> KvRouteInfo { + fn test_route_info_with_tag(node_id: &str, tomb_tag: NodeTombTag) -> KvNodeReplicas { + KvNodeReplicas::memory(tomb_tag, test_memory_replica(node_id)) + } + + fn test_route_info(node_id: &str, tomb: bool) -> KvNodeReplicas { let tomb_tag = NodeTombTag::new(); if tomb { tomb_tag.set_tomb(); @@ -1707,7 +1995,7 @@ mod tests { test_route_info_with_tag(node_id, tomb_tag) } - fn test_allocation_route_info(node_id: &str, owner_local_indexed: bool) -> KvRouteInfo { + fn test_allocation_route_info(node_id: &str, owner_local_indexed: bool) -> KvNodeReplicas { let allocator = Arc::new( crate::master_seg_manager::one_seg_allocator::OneSegAllocator::new( format!("{node_id}-segment"), @@ -1718,14 +2006,15 @@ mod tests { .unwrap(), ); let allocation = allocator.allocate(1024).unwrap(); - KvRouteInfo { - node_id: node_id.to_string().into(), - backing: KvReplicaBacking::Allocation(Arc::new(allocation)), - owner_local_indexed, - get_durable_reservation: None, - capacity_reservation: None, - tomb_tag: NodeTombTag::new(), - } + KvNodeReplicas::memory( + NodeTombTag::new(), + KvMemoryReplica { + backing: KvReplicaBacking::Allocation(Arc::new(allocation)), + owner_local_indexed, + get_durable_reservation: None, + capacity_reservation: None, + }, + ) } fn test_route( @@ -1737,7 +2026,7 @@ mod tests { put_id, lease_id, atomic_group: None, - nodes_replicas: RwLock::new( + node_replicas: RwLock::new( replicas .into_iter() .map(|(node_id, tomb)| { @@ -1756,7 +2045,7 @@ mod tests { put_id: (91, 3), lease_id, atomic_group: None, - nodes_replicas: RwLock::new(HashMap::from([(node.clone(), replica)])), + node_replicas: RwLock::new(HashMap::from([(node.clone(), replica)])), get_durable_slots_used: AtomicU32::new(0), }; @@ -1773,11 +2062,48 @@ mod tests { assert!(ring_b_route_replica_desc(&leased, "same-node").is_none()); let mut committed = test_route_info("same-node", false); - committed.owner_local_indexed = false; + committed + .memory + .as_mut() + .expect("test route has memory") + .owner_local_indexed = false; let committed = make_route(None, committed); assert!(ring_b_route_replica_desc(&committed, "same-node").is_none()); } + #[test] + fn ssd_commit_reuses_the_live_owner_route_and_validates_memory_length() { + let owner: NodeID = "owner".to_string().into(); + let route = test_route((92, 1), None, vec![("owner", false)]); + + assert_eq!( + route.commit_ssd_replica(&owner, 2048), + SsdReplicaCommitStatus::LengthMismatch + ); + assert_eq!( + route.commit_ssd_replica(&owner, 1024), + SsdReplicaCommitStatus::Committed + ); + { + let replicas = route.node_replicas.read(); + let owner_replicas = replicas.get(&owner).unwrap(); + assert!(owner_replicas.memory.is_some()); + assert_eq!(owner_replicas.ssd.as_ref().map(|ssd| ssd.len), Some(1024)); + } + + route.node_replicas.write().get_mut(&owner).unwrap().memory = None; + assert_eq!( + route.commit_ssd_replica(&owner, 1024), + SsdReplicaCommitStatus::MissingMemory + ); + assert!(route.remove_ssd_replica(&owner)); + assert!( + route.node_replicas.read().is_empty(), + "a stale SSD-only owner entry must converge to an empty route" + ); + assert!(!route.remove_ssd_replica(&owner)); + } + #[test] fn member_left_cleanup_removes_only_the_exact_tomb_generation() { let routes = DashMap::new(); @@ -1791,7 +2117,7 @@ mod tests { put_id: (10, 0), lease_id: None, atomic_group: None, - nodes_replicas: RwLock::new(HashMap::from([( + node_replicas: RwLock::new(HashMap::from([( "owner".to_string().into(), test_route_info_with_tag("owner", departed_tag.clone()), )])), @@ -1801,7 +2127,7 @@ mod tests { put_id: (11, 0), lease_id: None, atomic_group: None, - nodes_replicas: RwLock::new(HashMap::from([( + node_replicas: RwLock::new(HashMap::from([( "owner".to_string().into(), test_route_info_with_tag("owner", live_reconnect_tag), )])), @@ -1811,7 +2137,7 @@ mod tests { put_id: (12, 0), lease_id: None, atomic_group: None, - nodes_replicas: RwLock::new(HashMap::from([( + node_replicas: RwLock::new(HashMap::from([( "owner".to_string().into(), test_route_info_with_tag("owner", newer_tomb_tag), )])), @@ -1844,7 +2170,7 @@ mod tests { ); assert!( live_route - .nodes_replicas + .node_replicas .read() .get("owner") .is_some_and(|replica| !replica.tomb_tag.is_tomb()) @@ -1859,7 +2185,7 @@ mod tests { ), None ); - assert!(newer_tomb_route.nodes_replicas.read().contains_key("owner")); + assert!(newer_tomb_route.node_replicas.read().contains_key("owner")); } #[test] @@ -1871,7 +2197,7 @@ mod tests { put_id: (20, 0), lease_id: None, atomic_group: None, - nodes_replicas: RwLock::new(HashMap::from([( + node_replicas: RwLock::new(HashMap::from([( "owner".to_string().into(), test_route_info_with_tag("owner", departed_tag.clone()), )])), @@ -1895,7 +2221,7 @@ mod tests { assert!(Arc::ptr_eq(current.value(), &replacement)); assert!( current - .nodes_replicas + .node_replicas .read() .get("peer") .is_some_and(|replica| !replica.tomb_tag.is_tomb()) @@ -1906,7 +2232,7 @@ mod tests { fn replica_publish_fence_never_overwrites_live_or_publishes_tomb_generation() { let old_tag = NodeTombTag::new(); let route = test_route((30, 0), None, vec![]); - route.nodes_replicas.write().insert( + route.node_replicas.write().insert( "owner".to_string().into(), test_route_info_with_tag("owner", old_tag.clone()), ); @@ -1915,11 +2241,12 @@ mod tests { assert!(!publish_route_replica_tomb_fenced( &route, "owner".to_string().into(), - test_route_info_with_tag("owner", contender_tag), + test_memory_replica("owner"), + contender_tag, )); assert!( route - .nodes_replicas + .node_replicas .read() .get("owner") .is_some_and(|replica| replica.tomb_tag.same_generation(&old_tag)) @@ -1930,11 +2257,12 @@ mod tests { assert!(publish_route_replica_tomb_fenced( &route, "owner".to_string().into(), - test_route_info_with_tag("owner", replacement_tag.clone()), + test_memory_replica("owner"), + replacement_tag.clone(), )); assert!( route - .nodes_replicas + .node_replicas .read() .get("owner") .is_some_and(|replica| replica.tomb_tag.same_generation(&replacement_tag)) @@ -1945,9 +2273,10 @@ mod tests { assert!(!publish_route_replica_tomb_fenced( &route, "departed".to_string().into(), - test_route_info_with_tag("departed", departed_tag), + test_memory_replica("departed"), + departed_tag, )); - assert!(!route.nodes_replicas.read().contains_key("departed")); + assert!(!route.node_replicas.read().contains_key("departed")); } #[test] @@ -1962,7 +2291,7 @@ mod tests { put_id: (41, 0), lease_id: None, atomic_group: None, - nodes_replicas: RwLock::new(HashMap::from([( + node_replicas: RwLock::new(HashMap::from([( "owner".to_string().into(), test_route_info_with_tag("owner", departed_tag.clone()), )])), @@ -1982,7 +2311,7 @@ mod tests { put_id: (42, 0), lease_id: None, atomic_group: None, - nodes_replicas: RwLock::new(HashMap::from([( + node_replicas: RwLock::new(HashMap::from([( "owner".to_string().into(), test_route_info_with_tag("owner", live_tag.clone()), )])), @@ -2068,6 +2397,52 @@ mod tests { assert_eq!(cache.max_capacity(), Some(2048)); } + #[test] + fn ring_b_shrink_selects_single_entries_to_the_new_active_boundary() { + let selected = Arc::new(AtomicU64::new(0)); + let selected_for_listener = selected.clone(); + let cache = MasterNodeCache::builder(1024) + .weigher(|_key: &String, desc: &NodeValueReplicaDesc| desc.weight_bytes) + .eviction_listener(move |_key, _desc, cause| { + assert_eq!(cause, RemovalCause::Size); + selected_for_listener.fetch_add(1, Ordering::Relaxed); + }) + .build(); + for key in 0..8 { + insert_master_cache_entry( + &cache, + key.to_string(), + NodeValueReplicaDesc { + weight_bytes: 128, + put_id: (10, key), + }, + ); + } + cache.run_pending_tasks(); + assert_eq!(cache.weighted_size(), 1024); + + cache.set_max_capacity(512).unwrap(); + cache.run_pending_tasks(); + assert!(cache.weighted_size() <= 512); + assert_eq!(selected.load(Ordering::Relaxed), 4); + } + + #[test] + fn node_pool_capacity_control_json_is_a_finite_generation_fenced_contract() { + let request = NodePoolCapacityControlRequest::SetActive { + owner_node_id: "cpu-owner".to_string(), + expected_owner_node_start_time: 17, + expected_capacity_epoch: 3, + active_capacity_bytes: 240 * 1024 * 1024 * 1024, + }; + let encoded = serde_json::to_vec(&request).unwrap(); + let decoded: NodePoolCapacityControlRequest = serde_json::from_slice(&encoded).unwrap(); + assert_eq!(decoded, request); + let json: serde_json::Value = serde_json::from_slice(&encoded).unwrap(); + assert_eq!(json["operation"], "set_active"); + assert_eq!(json["expected_capacity_epoch"], 3); + } + #[test] fn synchronous_restore_re_eviction_keeps_new_pending_weight() { let weight = 8 * 1024 * 1024; @@ -2312,6 +2687,7 @@ pub struct MasterKvRouterInner { /// `inflight_gets` after re-reading and validating the current route. pub planned_gets: moka::future::Cache, pub(crate) planned_get_counters: MasterPlannedGetCounters, + pub(crate) ssd_tier_counters: MasterSsdTierCounters, /// Idempotent terminal GetDone results retained across response loss/retry. pub completed_gets: moka::future::Cache, pub get_done_locks: AMapLock, @@ -2388,6 +2764,11 @@ pub struct MasterKvRouterInner { /// request lock, and no cache/global scan occurs under it. pub(crate) owner_cache_operation_locks: AMapLock, + /// Serializes the active pool target, reservation counters, and their derived Moka limits. + /// The critical section contains only local metadata/housekeeping and is shared with + /// synchronous reservation Drop paths, so it intentionally uses a short parking_lot lock. + node_capacity_boundary_locks: DashMap>>, + /// Historical final put placement decisions by target node. pub put_target_decision_counts: DashMap>, @@ -2406,6 +2787,11 @@ pub struct MasterKvRouterInner { /// Historical get source choices by requester->source pair. pub get_requester_source_counts: DashMap>, pub get_requester_source_bytes: DashMap>, + /// Source-tier/locality matrix for planned and ordinary Gets. This keeps + /// local SSD, remote SSD, local memory, and remote memory separable in + /// evidence instead of inferring them from per-owner aggregate loads. + pub get_source_class_counts: DashMap<&'static str, Arc>, + pub get_source_class_bytes: DashMap<&'static str, Arc>, pub get_allocation_mode_counts: DashMap<&'static str, Arc>, /// Support replicas: key -> version_id @@ -2569,6 +2955,7 @@ impl MasterKvRouter { inflight_gets, planned_gets, planned_get_counters: MasterPlannedGetCounters::default(), + ssd_tier_counters: MasterSsdTierCounters::default(), completed_gets, get_done_locks: AMapLock::new(Duration::from_secs(10 * 60)), key_activity, @@ -2595,6 +2982,7 @@ impl MasterKvRouter { eviction_reclaim_inflight: DashSet::new(), eviction_reclaim_counters: DashMap::new(), owner_cache_operation_locks: AMapLock::new(Duration::from_secs(10 * 60)), + node_capacity_boundary_locks: DashMap::new(), put_target_decision_counts: DashMap::new(), put_requester_target_decision_counts: DashMap::new(), put_placement_mode_counts: DashMap::new(), @@ -2602,6 +2990,8 @@ impl MasterKvRouter { replica_done_terminal_replay_count: AtomicU64::new(0), get_requester_source_counts: DashMap::new(), get_requester_source_bytes: DashMap::new(), + get_source_class_counts: DashMap::new(), + get_source_class_bytes: DashMap::new(), get_allocation_mode_counts: DashMap::new(), recent_key_versionid_allocator: moka::sync::SegmentedCache::builder(8) .time_to_idle(Duration::from_secs(5)) @@ -2700,33 +3090,47 @@ impl MasterKvRouter { .ring_b_bytes } - /// Refresh already-created node controllers after segment metadata or - /// reservation inputs change. Generation-scoped reservations reduce only - /// the physical ring-B allocation boundary. Tier1 is an inclusive metadata - /// policy window and always remains ratio-derived from the owner segment. - fn reconcile_node_cache_capacity(&self, node_id: &str) { + fn node_capacity_boundary_lock(&self, node_id: &str) -> Arc> { + self.inner() + .node_capacity_boundary_locks + .entry(node_id.to_string()) + .or_insert_with(|| Arc::new(Mutex::new(()))) + .value() + .clone() + } + + /// Apply the current active pool size to every derived Moka boundary. + fn apply_node_cache_capacity_locked(&self, node_id: &str) -> KvResult<()> { + if !self.replica_cache_enabled() { + return Ok(()); + } let node_space_size = self .inner() .view() .master_seg_manager() - .get_node_space_size(node_id); + .get_node_active_space_size(node_id); if node_space_size == 0 { - return; + return Err(KvError::Api(ApiError::NodeNotFound { + desc: format!("{node_id} (no live active pool)"), + })); } let capacity = self.replica_cache_effective_capacity(node_id, node_space_size); - if let Some(cache) = self - .inner() - .node_kv_cache_controller - .get(node_id) - .map(|entry| entry.value().clone()) - { - if let Err(err) = cache.set_max_capacity(capacity) { - error!( - "failed to refresh ring-B cache capacity: node={} capacity={} err={}", - node_id, capacity, err, - ); - } - } + let cache = self.get_node_cache_controller(node_id).ok_or_else(|| { + KvError::Api(ApiError::NodeNotFound { + desc: format!("{node_id} (ring-B controller unavailable)"), + }) + })?; + cache.set_max_capacity(capacity).map_err(|err| { + KvError::Api(ApiError::Allocator { + detail: format!( + "failed to set ring-B capacity: node={} capacity={} err={}", + node_id, capacity, err + ), + }) + })?; + // Drive Size selection now. Physical release remains asynchronous and continues through + // the existing generation-fenced single-KV reclaim actor. + cache.run_pending_tasks(); if let Some(cache) = self .inner() .node_writeback_tier1_controller @@ -2736,12 +3140,50 @@ impl MasterKvRouter { let tier1_capacity = self .writeback_tier1_base_capacity(node_space_size) .unwrap_or(0); - if let Err(err) = cache.set_max_capacity(tier1_capacity) { - error!( - "failed to refresh tier1 cache capacity: node={} capacity={} err={}", - node_id, tier1_capacity, err, - ); - } + cache.set_max_capacity(tier1_capacity).map_err(|err| { + KvError::Api(ApiError::Allocator { + detail: format!( + "failed to set tier1 capacity: node={} capacity={} err={}", + node_id, tier1_capacity, err + ), + }) + })?; + cache.run_pending_tasks(); + } + Ok(()) + } + + fn apply_node_cache_capacity(&self, node_id: &str) -> KvResult<()> { + let capacity_lock = self.node_capacity_boundary_lock(node_id); + let _capacity_guard = capacity_lock.lock(); + self.apply_node_cache_capacity_locked(node_id) + } + + /// Refresh controllers after registration or reservation changes. Runtime resize uses the + /// fallible helper directly so a control response never reports an unapplied target. + fn reconcile_node_cache_capacity(&self, node_id: &str) { + // Member discovery can precede segment registration. There is no pool boundary to + // reconcile during that normal startup window; registration success will call us again. + // Keep the fallible runtime-control path strict, but do not emit a false operational + // error for this transient internal reconcile. + if self + .inner() + .view() + .master_seg_manager() + .get_node_active_space_size(node_id) + == 0 + { + debug!( + "deferring node cache capacity refresh until pool registration: node={}", + node_id + ); + return; + } + if let Err(err) = self.apply_node_cache_capacity(node_id) { + error!( + "failed to refresh node cache capacity: node={} err={}", + node_id, err + ); } } @@ -2755,6 +3197,191 @@ impl MasterKvRouter { .tier1_bytes } + fn node_pool_capacity_response( + &self, + owner_node_id: &str, + owner_node_start_time: i64, + pool: NodePoolCapacitySnapshot, + ) -> NodePoolCapacityControlResponse { + let ring_b_base_capacity_bytes = + self.replica_cache_base_capacity(pool.active_capacity_bytes); + let reserved_capacity_bytes = self + .inner() + .node_cache_reserved_capacity + .get(owner_node_id) + .filter(|reserved| !reserved.generation.is_tomb()) + .map(|reserved| reserved.total_reserved_bytes()) + .unwrap_or(0); + let derived_effective = ring_b_base_capacity_bytes.saturating_sub(reserved_capacity_bytes); + let cache = self + .inner() + .node_kv_cache_controller + .get(owner_node_id) + .map(|entry| entry.value().clone()); + let ring_b_effective_capacity_bytes = cache + .as_ref() + .and_then(|cache| cache.max_capacity()) + .unwrap_or(derived_effective); + let ring_b_weighted_bytes = cache + .as_ref() + .map(|cache| cache.weighted_size()) + .unwrap_or(0); + let ring_b_pending_reclaim_bytes = self.eviction_reclaim_pending_weight(owner_node_id); + let tier1_capacity_bytes = self + .inner() + .node_writeback_tier1_controller + .get(owner_node_id) + .and_then(|entry| entry.value().max_capacity()) + .unwrap_or_else(|| { + self.writeback_tier1_base_capacity(pool.active_capacity_bytes) + .unwrap_or(0) + }); + let settled = pool.draining_capacity_bytes == 0 + && ring_b_weighted_bytes <= ring_b_effective_capacity_bytes + && ring_b_pending_reclaim_bytes == 0; + NodePoolCapacityControlResponse { + owner_node_id: owner_node_id.to_string(), + owner_node_start_time, + physical_capacity_bytes: pool.physical_capacity_bytes, + active_capacity_bytes: pool.active_capacity_bytes, + used_capacity_bytes: pool.used_capacity_bytes, + parked_capacity_bytes: pool.parked_capacity_bytes, + draining_capacity_bytes: pool.draining_capacity_bytes, + available_capacity_bytes: pool.available_capacity_bytes, + capacity_epoch: pool.capacity_epoch, + ring_b_base_capacity_bytes, + ring_b_effective_capacity_bytes, + ring_b_weighted_bytes, + ring_b_pending_reclaim_bytes, + tier1_capacity_bytes, + settled, + } + } + + pub fn node_pool_capacity_control_snapshot( + &self, + owner_node_id: &str, + ) -> KvResult { + let capacity_lock = self.node_capacity_boundary_lock(owner_node_id); + let _capacity_guard = capacity_lock.lock(); + let (owner_node_start_time, pool) = self + .inner() + .view() + .master_seg_manager() + .get_node_pool_capacity(owner_node_id) + .ok_or_else(|| { + KvError::Api(ApiError::NodeNotFound { + desc: owner_node_id.to_string(), + }) + })?; + Ok(self.node_pool_capacity_response(owner_node_id, owner_node_start_time, pool)) + } + + /// Atomically close the allocator admission gate before lowering Moka's derived boundaries. + /// The returned response is an initiation snapshot; callers poll `Get` until `settled=true`. + pub async fn set_node_pool_active_capacity( + &self, + owner_node_id: NodeID, + expected_owner_node_start_time: i64, + expected_capacity_epoch: u64, + active_capacity_bytes: u64, + ) -> KvResult { + let owner_cache_lock = self + .inner() + .owner_cache_operation_locks + .get_lock(owner_node_id.to_string()); + let _owner_cache_guard = owner_cache_lock.lock().await; + let capacity_lock = self.node_capacity_boundary_lock(owner_node_id.as_ref()); + let _capacity_guard = capacity_lock.lock(); + + let (_, before) = self + .inner() + .view() + .master_seg_manager() + .get_node_pool_capacity(owner_node_id.as_ref()) + .ok_or_else(|| { + KvError::Api(ApiError::NodeNotFound { + desc: owner_node_id.to_string(), + }) + })?; + let reserved_capacity_bytes = self + .inner() + .node_cache_reserved_capacity + .get(owner_node_id.as_ref()) + .filter(|reserved| !reserved.generation.is_tomb()) + .map(|reserved| reserved.total_reserved_bytes()) + .unwrap_or(0); + let prospective_ring_b = node_cache_capacity_boundaries( + active_capacity_bytes, + self.inner().replica_cache_capacity_ratio, + self.inner().replica_writeback_tier1_capacity_ratio, + reserved_capacity_bytes, + ) + .ring_b_bytes; + if self.replica_cache_enabled() && prospective_ring_b == 0 { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "active capacity leaves no ring-B allocation budget: owner={} active={} reserved={}", + owner_node_id, active_capacity_bytes, reserved_capacity_bytes + ), + })); + } + + let updated = self + .inner() + .view() + .master_seg_manager() + .set_node_active_capacity( + &owner_node_id, + expected_owner_node_start_time, + expected_capacity_epoch, + active_capacity_bytes, + )?; + if let Err(apply_err) = self.apply_node_cache_capacity_locked(owner_node_id.as_ref()) { + let rollback = self + .inner() + .view() + .master_seg_manager() + .set_node_active_capacity( + &owner_node_id, + expected_owner_node_start_time, + updated.capacity_epoch, + before.active_capacity_bytes, + ) + .and_then(|_| self.apply_node_cache_capacity_locked(owner_node_id.as_ref())); + error!( + owner = %owner_node_id, + requested_active_capacity_bytes = active_capacity_bytes, + error = %apply_err, + rollback = ?rollback, + "node pool capacity apply failed" + ); + return Err(apply_err); + } + + let response = self.node_pool_capacity_response( + owner_node_id.as_ref(), + expected_owner_node_start_time, + updated, + ); + info!( + owner = %owner_node_id, + owner_node_start_time = response.owner_node_start_time, + capacity_epoch = response.capacity_epoch, + physical_capacity_bytes = response.physical_capacity_bytes, + active_capacity_bytes = response.active_capacity_bytes, + parked_capacity_bytes = response.parked_capacity_bytes, + used_capacity_bytes = response.used_capacity_bytes, + draining_capacity_bytes = response.draining_capacity_bytes, + ring_b_effective_capacity_bytes = response.ring_b_effective_capacity_bytes, + ring_b_weighted_bytes = response.ring_b_weighted_bytes, + ring_b_pending_reclaim_bytes = response.ring_b_pending_reclaim_bytes, + settled = response.settled, + "node pool active capacity applied" + ); + Ok(response) + } + pub fn tiered_writeback_enabled(&self) -> bool { self.inner() .replica_writeback_tier1_capacity_ratio @@ -2935,20 +3562,21 @@ impl MasterKvRouter { .map(|route| { let put_id = route.put_id; route - .nodes_replicas + .node_replicas .read() .iter() - .filter_map(|(node_id, replica)| { - (!replica.tomb_tag.is_tomb()).then(|| { - ( - node_id.as_ref().to_string(), - NodeValueReplicaDesc { - weight_bytes: u32::try_from(replica.backing.capacity_bytes()) - .unwrap_or(u32::MAX), - put_id, - }, - ) - }) + .filter_map(|(node_id, replicas)| { + let memory = (!replicas.tomb_tag.is_tomb()) + .then(|| replicas.memory.as_ref()) + .flatten()?; + Some(( + node_id.as_ref().to_string(), + NodeValueReplicaDesc { + weight_bytes: u32::try_from(memory.backing.capacity_bytes()) + .unwrap_or(u32::MAX), + put_id, + }, + )) }) .collect::>() }) @@ -2964,7 +3592,7 @@ impl MasterKvRouter { .get(key) .map(|one_kv_nodes_routes| { one_kv_nodes_routes - .nodes_replicas + .node_replicas .read() .values() .any(|kv_info| !kv_info.tomb_tag.is_tomb()) @@ -3307,20 +3935,21 @@ impl MasterKvRouter { route: &OneKvNodesRoutes, ) { let replicas = route - .nodes_replicas + .node_replicas .read() .iter() - .filter_map(|(node_id, replica)| { - (!replica.tomb_tag.is_tomb()).then(|| { - ( - node_id.as_ref().to_string(), - NodeValueReplicaDesc { - weight_bytes: u32::try_from(replica.backing.capacity_bytes()) - .unwrap_or(u32::MAX), - put_id: route.put_id, - }, - ) - }) + .filter_map(|(node_id, replicas)| { + let memory = (!replicas.tomb_tag.is_tomb()) + .then(|| replicas.memory.as_ref()) + .flatten()?; + Some(( + node_id.as_ref().to_string(), + NodeValueReplicaDesc { + weight_bytes: u32::try_from(memory.backing.capacity_bytes()) + .unwrap_or(u32::MAX), + put_id: route.put_id, + }, + )) }) .collect::>(); for (node_id, desc) in replicas { @@ -3362,6 +3991,14 @@ impl MasterKvRouter { fn register_rpc_handlers(&self) { let p2p = self.0.view().p2p_module(); + user_rpc_register_handler_async( + p2p, + NODE_POOL_CAPACITY_USER_RPC_PATH.to_string(), + Arc::new(NodePoolCapacityUserRpcHandler { + view: self.0.view().clone(), + }), + ); + // --- Get Handlers --- let view = self.0.view().clone(); RPCHandler::::new().regist(p2p, move |resp, msg| { @@ -3427,6 +4064,30 @@ impl MasterKvRouter { Ok(()) }); + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let task_view = view.clone(); + let req_node_id = resp.node_id().clone(); + view.spawn("rpc_ssd_stage_begin", async move { + let ack = handle_ssd_stage_begin(task_view, msg, req_node_id).await; + let _ = resp.send_resp(ack).await; + }); + Ok(()) + }); + + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let task_view = view.clone(); + let req_node_id = resp.node_id().clone(); + view.spawn("rpc_ssd_stage_done", async move { + let ack = handle_ssd_stage_done(task_view, msg, req_node_id).await; + let _ = resp.send_resp(ack).await; + }); + Ok(()) + }); + // --- CountPrefix Handler --- let view = self.0.view().clone(); RPCHandler::::new().regist(p2p, move |resp, msg| { @@ -3694,6 +4355,20 @@ impl MasterKvRouter { Ok(()) }); + let view = self.0.view().clone(); + RPCHandler::::new().regist(p2p, move |resp, msg| { + let view = view.clone(); + let owner = resp.node_id().clone(); + let view_task = view.clone(); + let _ = view.spawn("rpc_batch_publish_owner_ssd", async move { + let ack = handle_batch_publish_owner_ssd(view_task, msg, owner).await; + if let Err(err) = resp.send_resp(ack).await { + error!("Failed to send BatchPublishOwnerSsdResp: {:?}", err); + } + }); + Ok(()) + }); + let view = self.0.view().clone(); RPCHandler::::new().regist(p2p, move |resp, msg| { let view = view.clone(); @@ -4582,6 +5257,8 @@ impl MasterKvRouter { source_node_id: &str, bytes: u64, allocation_mode: GetAllocationMode, + source_kind: GetSourceKind, + source_is_requester_local_owner: bool, ) { let requester_source_key = RequesterTargetPair::new(requester_node_id, source_node_id); let source_count = self @@ -4602,6 +5279,25 @@ impl MasterKvRouter { .clone(); source_bytes.fetch_add(bytes, Ordering::Relaxed); + let source_class = match (source_kind, source_is_requester_local_owner) { + (GetSourceKind::Memory, true) => "local_memory", + (GetSourceKind::Memory, false) => "remote_memory", + (GetSourceKind::Ssd, true) => "local_ssd", + (GetSourceKind::Ssd, false) => "remote_ssd", + }; + self.inner() + .get_source_class_counts + .entry(source_class) + .or_insert_with(|| Arc::new(AtomicU64::new(0))) + .value() + .fetch_add(1, Ordering::Relaxed); + self.inner() + .get_source_class_bytes + .entry(source_class) + .or_insert_with(|| Arc::new(AtomicU64::new(0))) + .value() + .fetch_add(bytes, Ordering::Relaxed); + let mode_key = match allocation_mode { GetAllocationMode::Temporary => "temporary", GetAllocationMode::ReuseReplica => "reuse_replica", @@ -4684,6 +5380,22 @@ impl MasterKvRouter { .collect(); get_source_bytes.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(&b.0))); + let mut get_source_class_counts: Vec<(String, u64)> = router + .inner() + .get_source_class_counts + .iter() + .map(|entry| (entry.key().to_string(), entry.value().load(Ordering::Relaxed))) + .collect(); + get_source_class_counts.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(&b.0))); + + let mut get_source_class_bytes: Vec<(String, u64)> = router + .inner() + .get_source_class_bytes + .iter() + .map(|entry| (entry.key().to_string(), entry.value().load(Ordering::Relaxed))) + .collect(); + get_source_class_bytes.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(&b.0))); + let mut get_allocation_mode_counts: Vec<(String, u64)> = router .inner() .get_allocation_mode_counts @@ -4693,7 +5405,7 @@ impl MasterKvRouter { get_allocation_mode_counts.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(&b.0))); info!( - "placement historical distribution | put_target_counts={:?} | put_mode_counts={:?} | put_requester_target_counts={:?} | replica_task_target_counts={:?} | replica_done_terminal_replays={} | get_requester_source_counts={:?} | get_requester_source_bytes={:?} | get_allocation_mode_counts={:?}", + "placement historical distribution | put_target_counts={:?} | put_mode_counts={:?} | put_requester_target_counts={:?} | replica_task_target_counts={:?} | replica_done_terminal_replays={} | get_requester_source_counts={:?} | get_requester_source_bytes={:?} | get_source_class_counts={:?} | get_source_class_bytes={:?} | get_allocation_mode_counts={:?}", target_counts, mode_counts, requester_target_counts, @@ -4701,6 +5413,8 @@ impl MasterKvRouter { replica_done_terminal_replays, get_source_counts, get_source_bytes, + get_source_class_counts, + get_source_class_bytes, get_allocation_mode_counts, ); } @@ -4720,7 +5434,7 @@ impl MasterKvRouter { .inner() .view() .master_seg_manager() - .get_node_space_size(node_id); + .get_node_active_space_size(node_id); if node_space_size == 0 { return None; } @@ -4806,7 +5520,7 @@ impl MasterKvRouter { .inner() .view() .master_seg_manager() - .get_node_space_size(node_id); + .get_node_active_space_size(node_id); let base_capacity = self.writeback_tier1_base_capacity(node_space_size)?; if base_capacity == 0 { return None; @@ -4862,11 +5576,13 @@ impl MasterKvRouter { if route.put_id != desc.put_id || route.lease_id.is_some() { return false; } - let replicas = route.nodes_replicas.read(); - replicas.values().any(|replica| { - replica.node_id.as_ref() == source_node_id && !replica.tomb_tag.is_tomb() - }) && replicas.values().all(|replica| { - replica.tomb_tag.is_tomb() || replica.node_id.as_ref() == source_node_id + let replicas = route.node_replicas.read(); + replicas.iter().any(|(node_id, replica)| { + node_id.as_ref() == source_node_id + && !replica.tomb_tag.is_tomb() + && replica.memory.is_some() + }) && replicas.iter().all(|(node_id, replica)| { + !replica.has_live_backing() || node_id.as_ref() == source_node_id }) }) } @@ -4974,6 +5690,8 @@ impl MasterKvRouter { if !self.replica_cache_enabled() { return Ok(()); } + let capacity_lock = self.node_capacity_boundary_lock(node_id); + let _capacity_guard = capacity_lock.lock(); if !reserved_capacity.generation.same_generation(generation) { return Err( crate::rpcresp_kvresult_convert::msg_and_error::KvError::Api( @@ -5021,91 +5739,20 @@ impl MasterKvRouter { return Ok(()); } - // Recompute target capacity from the configured base ratio minus live reservations. - let reserved_total = reserved_capacity.total_reserved_bytes(); - let node_space_size = self - .inner() - .view() - .master_seg_manager() - .get_node_space_size(node_id); - if node_space_size == 0 { + if let Err(err) = self.apply_node_cache_capacity_locked(node_id) { if delta_bytes >= 0 { reserved_capacity.apply_delta(reason, -delta_bytes); - } - return Err( - crate::rpcresp_kvresult_convert::msg_and_error::KvError::Unreachable( - crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::OwnerNoSeg { - detail: format!( - "node_id={} has no segment (node_space_size=0) while adjusting cache capacity", - node_id - ), - }, - ), - ); - } - let boundaries = node_cache_capacity_boundaries( - node_space_size, - self.inner().replica_cache_capacity_ratio, - self.inner().replica_writeback_tier1_capacity_ratio, - reserved_total, - ); - let new_capacity = boundaries.ring_b_bytes; - - if let Some(cache) = self.get_node_cache_controller(node_id) { - if let Some(tier1_cache) = self - .inner() - .node_writeback_tier1_controller - .get(node_id) - .map(|entry| entry.value().clone()) - { - // Local-reserve and owner-indexed reservations consume the - // physical ring-B allocation domain. They must not collapse - // the independent inclusive tier1 metadata window. - let tier1_capacity = boundaries.tier1_bytes.unwrap_or(0); - if let Err(e) = tier1_cache.set_max_capacity(tier1_capacity) { - if delta_bytes >= 0 { - reserved_capacity.apply_delta(reason, -delta_bytes); - } - return Err( - crate::rpcresp_kvresult_convert::msg_and_error::KvError::Unreachable( - crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::RpcDecodeError { - rpc_input_json: format!( - "tier1 moka.set_max_capacity failed: node_id={}, new_capacity={}, err={}", - node_id, tier1_capacity, e - ), - }, - ), + if let Err(rollback_err) = self.apply_node_cache_capacity_locked(node_id) { + error!( + node = node_id, + error = %rollback_err, + "failed to restore node cache boundary after reservation rollback" ); } } - if let Err(e) = cache.set_max_capacity(new_capacity) { - if delta_bytes >= 0 { - reserved_capacity.apply_delta(reason, -delta_bytes); - } - return Err( - crate::rpcresp_kvresult_convert::msg_and_error::KvError::Unreachable( - crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::RpcDecodeError { - rpc_input_json: format!( - "ring-B allocation moka.set_max_capacity failed: node_id={}, new_capacity={}, err={}", - node_id, new_capacity, e - ), - }, - ), - ); - } - Ok(()) - } else { - if delta_bytes >= 0 { - reserved_capacity.apply_delta(reason, -delta_bytes); - } - Err( - crate::rpcresp_kvresult_convert::msg_and_error::KvError::Unreachable( - crate::rpcresp_kvresult_convert::msg_and_error::UnreachableError::OwnerNoSeg { - detail: format!("node_id={} cache_controller not found", node_id), - }, - ), - ) + return Err(err); } + Ok(()) } /// Reserve cache capacity for one exact live node generation. The returned @@ -5256,11 +5903,15 @@ impl MasterKvRouter { for entry in self.inner().node_kv_cache_controller.iter() { let owner_node = entry.key().clone(); let cache = entry.value().clone(); - let node_space_size = self + let Some((owner_node_start_time, pool_capacity)) = self .inner() .view() .master_seg_manager() - .get_node_space_size(owner_node.as_str()); + .get_node_pool_capacity(owner_node.as_str()) + else { + continue; + }; + let node_space_size = pool_capacity.active_capacity_bytes; let base_capacity_bytes = self.replica_cache_base_capacity(node_space_size); let reserved_capacity_bytes = self .inner() @@ -5284,6 +5935,14 @@ impl MasterKvRouter { .map(|entry| entry.value().clone()); replica_cache_nodes.push(ReplicaCacheNodeObserveSnapshot { owner_node: owner_node.clone(), + owner_node_start_time, + pool_physical_capacity_bytes: pool_capacity.physical_capacity_bytes, + pool_active_capacity_bytes: pool_capacity.active_capacity_bytes, + pool_used_capacity_bytes: pool_capacity.used_capacity_bytes, + pool_parked_capacity_bytes: pool_capacity.parked_capacity_bytes, + pool_draining_capacity_bytes: pool_capacity.draining_capacity_bytes, + pool_available_capacity_bytes: pool_capacity.available_capacity_bytes, + pool_capacity_epoch: pool_capacity.capacity_epoch, entries: cache.entry_count(), weighted_bytes: cache.weighted_size(), effective_capacity_bytes, @@ -5467,9 +6126,73 @@ impl MasterKvRouter { .planned_get_counters .plan_revoked .load(Ordering::Relaxed), + remote_ssd_filtered_items = view_task + .master_kv_router() + .inner() + .planned_get_counters + .remote_ssd_filtered_items + .load(Ordering::Relaxed), + remote_ssd_filtered_bytes = view_task + .master_kv_router() + .inner() + .planned_get_counters + .remote_ssd_filtered_bytes + .load(Ordering::Relaxed), "master metadata-only Get plan runtime" ); + let ssd_tier = &view_task.master_kv_router().inner().ssd_tier_counters; + tracing::info!( + local_ssd_selected_with_remote_memory_items = ssd_tier + .local_ssd_selected_with_remote_memory_items + .load(Ordering::Relaxed), + local_ssd_selected_with_remote_memory_bytes = ssd_tier + .local_ssd_selected_with_remote_memory_bytes + .load(Ordering::Relaxed), + local_ssd_selected_without_remote_memory_items = ssd_tier + .local_ssd_selected_without_remote_memory_items + .load(Ordering::Relaxed), + local_ssd_selected_without_remote_memory_bytes = ssd_tier + .local_ssd_selected_without_remote_memory_bytes + .load(Ordering::Relaxed), + local_ssd_published_with_remote_memory_items = ssd_tier + .local_ssd_published_with_remote_memory_items + .load(Ordering::Relaxed), + local_ssd_published_with_remote_memory_bytes = ssd_tier + .local_ssd_published_with_remote_memory_bytes + .load(Ordering::Relaxed), + local_ssd_published_without_remote_memory_items = ssd_tier + .local_ssd_published_without_remote_memory_items + .load(Ordering::Relaxed), + local_ssd_published_without_remote_memory_bytes = ssd_tier + .local_ssd_published_without_remote_memory_bytes + .load(Ordering::Relaxed), + memory_removed_ssd_survived_items = ssd_tier + .memory_removed_ssd_survived_items + .load(Ordering::Relaxed), + memory_removed_ssd_survived_bytes = ssd_tier + .memory_removed_ssd_survived_bytes + .load(Ordering::Relaxed), + memory_removed_ssd_became_only_items = ssd_tier + .memory_removed_ssd_became_only_items + .load(Ordering::Relaxed), + memory_removed_ssd_became_only_bytes = ssd_tier + .memory_removed_ssd_became_only_bytes + .load(Ordering::Relaxed), + "master SSD substitution runtime" + ); for node in snapshot.replica_cache_nodes { + tracing::info!( + "node pool capacity runtime: owner={} owner_node_start_time={} capacity_epoch={} physical_capacity_bytes={} active_capacity_bytes={} used_capacity_bytes={} parked_capacity_bytes={} draining_capacity_bytes={} available_capacity_bytes={}", + node.owner_node, + node.owner_node_start_time, + node.pool_capacity_epoch, + node.pool_physical_capacity_bytes, + node.pool_active_capacity_bytes, + node.pool_used_capacity_bytes, + node.pool_parked_capacity_bytes, + node.pool_draining_capacity_bytes, + node.pool_available_capacity_bytes, + ); tracing::info!( "replica cache runtime: owner={} entries={} weighted_bytes={} effective_capacity_bytes={} base_capacity_bytes={} reserved_capacity_bytes={} pending_eviction_reclaim_bytes={} writeback_tier1_entries={} writeback_tier1_weighted_bytes={} writeback_tier1_capacity_bytes={} writeback_tier1_triggered={} writeback_tier1_owner_accepted={} writeback_tier1_failed={} reclaim_master_activity_deferred={} reclaim_owner_holder_deferred={} reclaim_owner_other_deferred={} reclaim_route_changed={} reclaim_retry_queued={} reclaim_retry_completed={} reclaim_retry_restored={} reclaim_completed={} source_evict_rpc_requests={} source_evict_victims={} source_evict_requested_bytes={} source_evict_accepted={} source_evict_in_progress={} source_evict_completed={} source_evict_retryable_busy={} source_evict_stale={} source_evict_rejected={} last_route_removed_members={} last_route_removed_bytes={} capacity_eviction_non_ring_b_entry_total={} capacity_eviction_hit_committed_slot={} eviction_reclaim_deduplicated={}", node.owner_node, @@ -5541,6 +6264,31 @@ impl MasterKvRouter { "writeback_tier1", node.writeback_tier1_capacity_bytes, ); + metrics.set_kv_replica_cache_capacity_bytes( + node.owner_node.as_str(), + "pool_physical", + node.pool_physical_capacity_bytes, + ); + metrics.set_kv_replica_cache_capacity_bytes( + node.owner_node.as_str(), + "pool_active", + node.pool_active_capacity_bytes, + ); + metrics.set_kv_replica_cache_capacity_bytes( + node.owner_node.as_str(), + "pool_used", + node.pool_used_capacity_bytes, + ); + metrics.set_kv_replica_cache_capacity_bytes( + node.owner_node.as_str(), + "pool_parked", + node.pool_parked_capacity_bytes, + ); + metrics.set_kv_replica_cache_capacity_bytes( + node.owner_node.as_str(), + "pool_draining", + node.pool_draining_capacity_bytes, + ); } } } diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs index b873956..6cbfca9 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/msg_pack.rs @@ -23,6 +23,13 @@ pub enum GetAllocationMode { ExternalSink = 4, } +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)] +pub enum GetSourceKind { + #[default] + Memory = 0, + Ssd = 1, +} + #[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)] pub struct GetPreparedLocalReserveTarget { pub grant_id: u64, @@ -68,6 +75,7 @@ pub struct GetStartResp { pub target_base_addr: u64, pub src_base_addr: u64, pub len: u64, + pub source_kind: GetSourceKind, /// Echoes the owner-local slot accepted as this Get's target. pub prepared_target: Option, pub atomic_group: Option, @@ -135,6 +143,62 @@ impl RPCReq for GetDoneReq { type Resp = GetDoneResp; } +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct SsdStageBeginReq { + pub get_id: u64, +} + +impl MsgPackSerializePart for SsdStageBeginReq { + fn msg_id(&self) -> u32 { + MsgId::SsdStageBeginReq as u32 + } +} + +impl RPCReq for SsdStageBeginReq { + type Resp = SsdStageBeginResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct SsdStageBeginResp { + pub started: bool, + pub error_code: ErrorCode, + pub error_json: String, +} + +impl MsgPackSerializePart for SsdStageBeginResp { + fn msg_id(&self) -> u32 { + MsgId::SsdStageBeginResp as u32 + } +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct SsdStageDoneReq { + pub get_id: u64, + pub drop_ssd_source: bool, +} + +impl MsgPackSerializePart for SsdStageDoneReq { + fn msg_id(&self) -> u32 { + MsgId::SsdStageDoneReq as u32 + } +} + +impl RPCReq for SsdStageDoneReq { + type Resp = SsdStageDoneResp; +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct SsdStageDoneResp { + pub error_code: ErrorCode, + pub error_json: String, +} + +impl MsgPackSerializePart for SsdStageDoneResp { + fn msg_id(&self) -> u32 { + MsgId::SsdStageDoneResp as u32 + } +} + #[derive(Default, Debug, Clone, Encode, Decode)] pub struct BatchGetStartReq { pub keys: Vec, @@ -161,6 +225,7 @@ pub struct BatchGetStartItemResp { pub target_base_addr: u64, pub src_base_addr: u64, pub len: u64, + pub source_kind: GetSourceKind, pub prepared_target: Option, pub atomic_group: Option, pub error_code: ErrorCode, @@ -203,9 +268,11 @@ pub struct BatchGetPlanItemResp { pub src_addr: u64, pub src_base_addr: u64, pub len: u64, + pub source_kind: GetSourceKind, pub atomic_group: Option, - /// False when the selected source is the external requester's local - /// share-group owner and therefore cannot use the RDMA-only GPU sink. + /// True only for remote memory. Requester-local memory and every SSD + /// source must materialize through an owner CPU holder instead of binding + /// the RDMA-only GPU sink. pub gpu_direct_eligible: bool, pub error_code: ErrorCode, pub error_json: String, @@ -507,9 +574,21 @@ pub enum OwnerReclaimBacking { slot_index: u32, slot_size: u64, }, - /// A master-owned allocation with no owner-side key index. The master reclaims this - /// backing directly after installing its key-activity fence and never sends it to the owner. - UnindexedAllocation, + /// A master-owned allocation with no owner-side key index. + /// + /// SSD-capable owners use this exact source identity to persist the bytes while the + /// master's route and key-activity fence keep the allocation alive. Owners without SSD + /// still skip owner coordination and let the master reclaim the allocation directly. + UnindexedAllocation { + /// Absolute address in the owner's registered CPU segment. + addr: u64, + /// Base address of the exact registered segment generation. + base_addr: u64, + /// Logical KV payload length. + len: u64, + /// Physical allocator capacity released when the master drops the allocation. + capacity_bytes: u64, + }, } #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)] @@ -519,12 +598,31 @@ pub enum OwnerReclaimReason { MasterAllocationCapacity, } +/// Per-victim SSD action for owner-local capacity reclaim. Selection and +/// deletion remain single-KV decisions even when one RPC carries a vector. +#[derive(Default, Debug, Clone, Copy, Hash, PartialEq, Eq, Encode, Decode)] +pub enum OwnerSourceSsdPolicy { + /// Delete the exact memory source without preserving it on SSD. + #[default] + Drop, + /// Ask the master to return `SsdCandidate` only if this is the last live + /// backing. Sources with another backing are deleted immediately. + SelectLastLive, + /// The owner has durably persisted this generation and supplied its exact + /// length in `ssd_backing_len`. + Persisted, +} + /// One exact owner-local source selected for capacity eviction. #[derive(Default, Debug, Clone, Hash, PartialEq, Eq, Encode, Decode)] pub struct OwnerSourceEvictionVictim { pub key: String, pub put_id: PutIDForAKey, pub backing: OwnerReclaimBacking, + /// Durable owner-local SSD bytes prepared under the exact source fence. + /// The master installs this backing immediately before deleting `memory`. + pub ssd_backing_len: Option, + pub ssd_policy: OwnerSourceSsdPolicy, } pub(crate) fn owner_source_eviction_epoch(operation_id: u64, victim_index: usize) -> u64 { @@ -554,6 +652,7 @@ pub enum OwnerSourceEvictionOutcome { Accepted, AlreadyInProgress, Completed, + SsdCandidate, RetryableBusy, Stale, RejectedNotEvictable, @@ -563,6 +662,7 @@ pub enum OwnerSourceEvictionOutcome { pub struct OwnerSourceEvictionVictimResp { pub victim_index: u32, pub outcome: OwnerSourceEvictionOutcome, + pub ssd_backing_committed: bool, pub detail: String, } @@ -584,6 +684,63 @@ impl RPCReq for BatchEvictOwnerSourceReq { type Resp = BatchEvictOwnerSourceResp; } +/// One durable same-owner SSD generation to publish without removing memory. +#[derive(Default, Debug, Clone, Hash, PartialEq, Eq, Encode, Decode)] +pub struct OwnerSsdPublishItem { + pub key: String, + pub put_id: PutIDForAKey, + pub len: u64, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPublishOwnerSsdReq { + /// Membership generation of the authenticated owner. + pub owner_node_start_time: i64, + pub items: Vec, +} + +impl MsgPackSerializePart for BatchPublishOwnerSsdReq { + fn msg_id(&self) -> u32 { + MsgId::BatchPublishOwnerSsdReq as u32 + } +} + +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)] +pub enum OwnerSsdPublishOutcome { + #[default] + Unspecified, + Published, + AlreadyPresent, + RetryableBusy, + Obsolete, + Rejected, +} + +#[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)] +pub struct OwnerSsdPublishItemResp { + pub key: String, + pub put_id: PutIDForAKey, + pub outcome: OwnerSsdPublishOutcome, + pub detail: String, +} + +#[derive(Default, Debug, Clone, Encode, Decode)] +pub struct BatchPublishOwnerSsdResp { + pub items: Vec, + pub error_code: ErrorCode, + pub error_json: String, +} + +impl MsgPackSerializePart for BatchPublishOwnerSsdResp { + fn msg_id(&self) -> u32 { + MsgId::BatchPublishOwnerSsdResp as u32 + } +} + +impl RPCReq for BatchPublishOwnerSsdReq { + type Resp = BatchPublishOwnerSsdResp; +} + #[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)] pub struct OwnerReclaimItem { pub key: String, @@ -610,6 +767,10 @@ pub struct OwnerReclaimItemResp { pub key: String, pub epoch: u64, pub state: OwnerReclaimItemState, + /// Durable bytes persisted by the owner while the exact memory source is + /// hidden behind the Prepare fence. The master publishes this backing on + /// the existing route before it asks the owner to Commit/free DRAM. + pub ssd_backing_len: Option, pub detail: String, } @@ -1623,6 +1784,22 @@ mod put_atomic_group_tests { assert_eq!(decoded.items[0].atomic_group.as_ref(), Some(&group)); } + #[test] + fn owner_ssd_publish_only_batch_round_trips_exact_generation() { + let req = BatchPublishOwnerSsdReq { + owner_node_start_time: 41, + items: vec![OwnerSsdPublishItem { + key: "ssd-key".to_string(), + put_id: (17, 3), + len: 4_718_592, + }], + }; + let decoded: BatchPublishOwnerSsdReq = + bitcode::decode(&bitcode::encode(&req)).expect("decode owner SSD publication"); + assert_eq!(decoded.owner_node_start_time, 41); + assert_eq!(decoded.items, req.items); + } + #[test] fn grouped_batch_put_done_wire_is_linear_and_round_trips() { let keys_and_put_ids = (0..128) diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/placement.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/placement.rs index 1880278..161d950 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/placement.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/placement.rs @@ -119,9 +119,9 @@ impl PlacementPolicy for LocalFirstPlacementPolicy { continue; }; - let total = allocator.total_size_bytes(); - let used = allocator.used_size_bytes(); - let free = total.saturating_sub(used); + let capacity = allocator.node_pool_capacity_snapshot(); + let total = capacity.active_capacity_bytes; + let free = capacity.available_capacity_bytes; last_no_space_ctx = Some(( node_id.as_ref().to_string(), allocator.seg_device_id.clone(), @@ -152,9 +152,9 @@ impl PlacementPolicy for LocalFirstPlacementPolicy { let all_segs = seg_manager.get_all_segments_allocator(); if let Some((nodeid, allocator)) = all_segs.choose(&mut rand::thread_rng()).cloned() { let node_id: NodeID = nodeid.into(); - let total = allocator.total_size_bytes(); - let used = allocator.used_size_bytes(); - let free = total.saturating_sub(used); + let capacity = allocator.node_pool_capacity_snapshot(); + let total = capacity.active_capacity_bytes; + let free = capacity.available_capacity_bytes; last_no_space_ctx = Some(( node_id.as_ref().to_string(), allocator.seg_device_id.clone(), @@ -260,9 +260,9 @@ impl PlacementPolicy for RandomPlacementPolicy { continue; }; - let total = allocator.total_size_bytes(); - let used = allocator.used_size_bytes(); - let free = total.saturating_sub(used); + let capacity = allocator.node_pool_capacity_snapshot(); + let total = capacity.active_capacity_bytes; + let free = capacity.available_capacity_bytes; last_no_space_ctx = Some(( node_id.as_ref().to_string(), allocator.seg_device_id.clone(), @@ -294,9 +294,9 @@ impl PlacementPolicy for RandomPlacementPolicy { continue; } - let total = allocator.total_size_bytes(); - let used = allocator.used_size_bytes(); - let free = total.saturating_sub(used); + let capacity = allocator.node_pool_capacity_snapshot(); + let total = capacity.active_capacity_bytes; + let free = capacity.available_capacity_bytes; last_no_space_ctx = Some(( node_id.as_ref().to_string(), allocator.seg_device_id.clone(), @@ -449,9 +449,10 @@ fn collect_remote_candidates( continue; } - let total = allocator.total_size_bytes(); - let used = allocator.used_size_bytes(); - let free = total.saturating_sub(used); + let capacity = allocator.node_pool_capacity_snapshot(); + let total = capacity.active_capacity_bytes; + let used = capacity.used_capacity_bytes; + let free = capacity.available_capacity_bytes; let node_key = node_id.as_ref().to_string(); let node_write_count = view .master_kv_router() @@ -798,9 +799,9 @@ fn choose_random_remote_target_with_allocator( let Some(allocator) = node_allocators.choose(&mut rand::thread_rng()).cloned() else { continue; }; - let total = allocator.total_size_bytes(); - let used = allocator.used_size_bytes(); - let free = total.saturating_sub(used); + let capacity = allocator.node_pool_capacity_snapshot(); + let total = capacity.active_capacity_bytes; + let free = capacity.available_capacity_bytes; last_no_space_ctx = Some(( node_id.as_ref().to_string(), allocator.seg_device_id.clone(), @@ -825,9 +826,9 @@ fn choose_random_remote_target_with_allocator( .collect(); candidates.shuffle(&mut rand::thread_rng()); for (node_id, allocator) in candidates { - let total = allocator.total_size_bytes(); - let used = allocator.used_size_bytes(); - let free = total.saturating_sub(used); + let capacity = allocator.node_pool_capacity_snapshot(); + let total = capacity.active_capacity_bytes; + let free = capacity.available_capacity_bytes; last_no_space_ctx = Some(( node_id.as_ref().to_string(), allocator.seg_device_id.clone(), diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs index f5bdef4..4ce99a6 100755 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/put.rs @@ -1,19 +1,21 @@ use super::{ CommittedSlotReplica, CompletedReplicaTaskInfo, InflightPutAllocation, InflightPutCommitInfo, - InflightPutInfo, InflightReplicaTaskInfo, KvReplicaBacking, KvRouteInfo, LocalReserveGrantInfo, - MasterKeyActivityCompletionGuard, MasterKvRouterView, NodeCacheCapacityReservation, - OwnerHoldingGetInfo, PreparedPutKeyReservationInfo, PutPlacementMode, ReservedCapacityReason, + InflightPutInfo, InflightReplicaTaskInfo, KvMemoryReplica, KvNodeReplicas, KvReplicaBacking, + LocalReserveGrantInfo, MasterKeyActivityCompletionGuard, MasterKvRouterView, + NodeCacheCapacityReservation, OwnerHoldingGetInfo, PreparedPutKeyReservationInfo, + PutPlacementMode, ReservedCapacityReason, SsdReplicaCommitStatus, msg_pack::{ - BatchPreparePutKeysReq, BatchPreparePutKeysResp, BatchPutAppendDoneItemResp, - BatchPutAppendDoneReq, BatchPutAppendDoneResp, BatchPutAppendStartItemResp, - BatchPutAppendStartReq, BatchPutAppendStartResp, BatchPutDoneItemResp, BatchPutDoneReq, - BatchPutDoneResp, BatchPutRevokeItemResp, BatchPutRevokeReq, BatchPutRevokeResp, - BatchPutStartItemResp, BatchPutStartReq, BatchPutStartResp, - BatchReleasePutKeyReservationsReq, BatchReleasePutKeyReservationsResp, - GroupedBatchPutDoneReq, GroupedBatchPutDoneResp, PutAppendDoneReq, PutAppendDoneResp, - PutAppendRevokeReq, PutAppendRevokeResp, PutAppendStartOutcome, PutAppendStartReq, - PutAppendStartResp, PutAtomicGroup, PutDoneCommittedSlot, PutDoneReq, PutDoneResp, - PutRevokeReq, PutRevokeResp, PutStartReq, PutStartResp, ReleaseLocalGrantReq, + BatchPreparePutKeysReq, BatchPreparePutKeysResp, BatchPublishOwnerSsdReq, + BatchPublishOwnerSsdResp, BatchPutAppendDoneItemResp, BatchPutAppendDoneReq, + BatchPutAppendDoneResp, BatchPutAppendStartItemResp, BatchPutAppendStartReq, + BatchPutAppendStartResp, BatchPutDoneItemResp, BatchPutDoneReq, BatchPutDoneResp, + BatchPutRevokeItemResp, BatchPutRevokeReq, BatchPutRevokeResp, BatchPutStartItemResp, + BatchPutStartReq, BatchPutStartResp, BatchReleasePutKeyReservationsReq, + BatchReleasePutKeyReservationsResp, GroupedBatchPutDoneReq, GroupedBatchPutDoneResp, + OwnerSsdPublishItem, OwnerSsdPublishItemResp, OwnerSsdPublishOutcome, PutAppendDoneReq, + PutAppendDoneResp, PutAppendRevokeReq, PutAppendRevokeResp, PutAppendStartOutcome, + PutAppendStartReq, PutAppendStartResp, PutAtomicGroup, PutDoneCommittedSlot, PutDoneReq, + PutDoneResp, PutRevokeReq, PutRevokeResp, PutStartReq, PutStartResp, ReleaseLocalGrantReq, ReleaseLocalGrantResp, ReserveLocalGrantOutcome, ReserveLocalGrantReq, ReserveLocalGrantResp, build_shared_put_atomic_group_assignments, }, @@ -44,11 +46,168 @@ use parking_lot::RwLock; use rand::seq::SliceRandom; use std::{ collections::{HashMap, HashSet}, - sync::{Arc, atomic::AtomicU32}, + sync::{ + Arc, + atomic::{AtomicU32, Ordering}, + }, }; pub type PutIDForAKey = (u64, u32); +fn publish_owner_ssd_item( + view: &MasterKvRouterView, + owner: &NodeID, + item: OwnerSsdPublishItem, +) -> OwnerSsdPublishItemResp { + let response = |outcome, detail: String| OwnerSsdPublishItemResp { + key: item.key.clone(), + put_id: item.put_id, + outcome, + detail, + }; + let _activity = match view + .master_kv_router() + .reserve_inflight_replica_key(&item.key) + { + Ok(activity) => activity, + Err(err) => { + return response( + OwnerSsdPublishOutcome::RetryableBusy, + format!("master key activity is busy: {err}"), + ); + } + }; + + let Some(route) = view.master_kv_router().inner().kv_routes.get(&item.key) else { + return response( + OwnerSsdPublishOutcome::Obsolete, + "route is absent".to_string(), + ); + }; + if route.put_id != item.put_id { + return response( + OwnerSsdPublishOutcome::Obsolete, + format!( + "route generation changed: current=({},{})", + route.put_id.0, route.put_id.1 + ), + ); + } + + let has_remote_memory = { + let replicas = route.node_replicas.read(); + let Some(owner_replicas) = replicas.get(owner) else { + return response( + OwnerSsdPublishOutcome::Obsolete, + "same-owner route entry is absent".to_string(), + ); + }; + if owner_replicas.tomb_tag.is_tomb() { + return response( + OwnerSsdPublishOutcome::Obsolete, + "same-owner generation is tombed".to_string(), + ); + } + if let Some(existing) = owner_replicas.ssd.as_ref() { + return if existing.len == item.len { + response( + OwnerSsdPublishOutcome::AlreadyPresent, + "same-owner SSD backing is already published".to_string(), + ) + } else { + response( + OwnerSsdPublishOutcome::Rejected, + format!( + "existing SSD length mismatch: existing={} requested={}", + existing.len, item.len + ), + ) + }; + } + replicas.iter().any(|(node_id, replicas)| { + node_id != owner && !replicas.tomb_tag.is_tomb() && replicas.memory.is_some() + }) + }; + + match route.commit_ssd_replica(owner, item.len) { + SsdReplicaCommitStatus::Committed => { + let counters = &view.master_kv_router().inner().ssd_tier_counters; + let (items, bytes) = if has_remote_memory { + ( + &counters.local_ssd_published_with_remote_memory_items, + &counters.local_ssd_published_with_remote_memory_bytes, + ) + } else { + ( + &counters.local_ssd_published_without_remote_memory_items, + &counters.local_ssd_published_without_remote_memory_bytes, + ) + }; + items.fetch_add(1, Ordering::Relaxed); + bytes.fetch_add(item.len, Ordering::Relaxed); + response( + OwnerSsdPublishOutcome::Published, + "same-owner SSD backing published while memory remains live".to_string(), + ) + } + SsdReplicaCommitStatus::MissingMemory | SsdReplicaCommitStatus::TombedNode => response( + OwnerSsdPublishOutcome::Obsolete, + "exact live same-owner memory generation is absent".to_string(), + ), + SsdReplicaCommitStatus::LengthMismatch => response( + OwnerSsdPublishOutcome::Rejected, + format!( + "SSD length does not match same-owner memory: requested={}", + item.len + ), + ), + } +} + +/// Publish durable same-owner SSD bytes onto the current route without +/// deleting or replacing the memory backing. +pub async fn handle_batch_publish_owner_ssd( + view: MasterKvRouterView, + req: MsgPack, + owner: NodeID, +) -> MsgPack { + let current_generation = view + .cluster_manager() + .get_member_info_cached(owner.as_ref()) + .map(|member| member.node_start_time); + if current_generation != Some(req.serialize_part.owner_node_start_time) { + let err = msg_and_error::KvError::Api(msg_and_error::ApiError::InvalidArgument { + detail: format!( + "owner SSD publication generation mismatch: owner={} requested={} current={:?}", + owner, req.serialize_part.owner_node_start_time, current_generation + ), + }); + return MsgPack { + serialize_part: BatchPublishOwnerSsdResp { + items: Vec::new(), + error_code: err.code(), + error_json: err.to_json(), + }, + raw_bytes: Vec::new(), + }; + } + + let items = req + .serialize_part + .items + .into_iter() + .map(|item| publish_owner_ssd_item(&view, &owner, item)) + .collect(); + MsgPack { + serialize_part: BatchPublishOwnerSsdResp { + items, + error_code: msg_and_error::OK, + error_json: String::new(), + }, + raw_bytes: Vec::new(), + } +} + fn validate_put_start_source_node_override( view: &MasterKvRouterView, requester_node_id: &NodeID, @@ -155,10 +314,10 @@ fn current_route_append_outcome( verify_put_id: PutIDForAKey, ) -> PutAppendStartOutcome { let has_complete_remote = route - .nodes_replicas + .node_replicas .read() - .values() - .any(|replica| !replica.tomb_tag.is_tomb() && replica.node_id != *source_node_id); + .iter() + .any(|(node_id, replicas)| node_id != source_node_id && replicas.has_live_backing()); classify_put_append_start_outcome(route.put_id == verify_put_id, has_complete_remote) } @@ -265,14 +424,13 @@ fn append_current_route_replica_if_matching( let published = publish_route_replica_tomb_fenced( &one_kv_nodes_routes, node_id.clone(), - KvRouteInfo { - node_id: node_id.clone(), + KvMemoryReplica { backing: KvReplicaBacking::Allocation(Arc::new(allocation)), owner_local_indexed: false, get_durable_reservation: None, capacity_reservation, - tomb_tag: target_tomb_tag, }, + target_tomb_tag, ); if !published { tracing::warn!( @@ -326,15 +484,13 @@ fn allocate_from_node_local_segment( ); } - let total = allocator.total_size_bytes(); - let used = allocator.used_size_bytes(); - let free = total.saturating_sub(used); + let capacity = allocator.node_pool_capacity_snapshot(); Err(msg_and_error::KvError::Api( msg_and_error::ApiError::NoSpace { node: node_id.as_ref().to_string(), segment: allocator.seg_device_id.clone(), - total_capacity: total, - free_capacity: free, + total_capacity: capacity.active_capacity_bytes, + free_capacity: capacity.available_capacity_bytes, }, )) } @@ -558,22 +714,25 @@ async fn publish_completed_put_route( lease_id_opt: Option, atomic_group: Option>, node_id: NodeID, - completed_info: KvRouteInfo, + publish_tag: crate::master_seg_manager::NodeTombTag, + completed_info: KvMemoryReplica, target_cap_bytes: u64, local_cache_holder_id: Option, ) -> MsgPack { - let publish_tag = completed_info.tomb_tag.clone(); let new_route = Arc::new(OneKvNodesRoutes { put_id, lease_id: lease_id_opt, atomic_group: atomic_group.clone(), - nodes_replicas: RwLock::new(HashMap::from([(node_id.clone(), completed_info)])), + node_replicas: RwLock::new(HashMap::from([( + node_id.clone(), + KvNodeReplicas::memory(publish_tag.clone(), completed_info), + )])), get_durable_slots_used: AtomicU32::new(0), }); let old_one_kv_routes = match publish_primary_route_tomb_fenced( &view.master_kv_router().inner().kv_routes, &key, - new_route, + new_route.clone(), &publish_tag, ) { Ok(previous) => previous, @@ -1485,13 +1644,11 @@ async fn handle_put_done_with_resolved_group( drop(target_allocation); ( target_cap_bytes, - KvRouteInfo { - node_id: node_id.clone(), + KvMemoryReplica { backing: KvReplicaBacking::CommittedSlot(committed_slot), owner_local_indexed: true, get_durable_reservation: None, capacity_reservation, - tomb_tag: slot_tomb_tag, }, false, ) @@ -1527,13 +1684,11 @@ async fn handle_put_done_with_resolved_group( }; ( target_cap_bytes, - KvRouteInfo { - node_id: node_id.clone(), + KvMemoryReplica { backing: KvReplicaBacking::Allocation(Arc::new(target_allocation)), owner_local_indexed: req.serialize_part.publish_local_cache, get_durable_reservation: None, capacity_reservation, - tomb_tag, }, true, ) @@ -1565,13 +1720,11 @@ async fn handle_put_done_with_resolved_group( }; ( target_cap_bytes, - KvRouteInfo { - node_id: node_id.clone(), + KvMemoryReplica { backing: KvReplicaBacking::Allocation(Arc::new(target)), owner_local_indexed: false, get_durable_reservation: None, capacity_reservation, - tomb_tag, }, false, ) @@ -1602,13 +1755,11 @@ async fn handle_put_done_with_resolved_group( }; ( target_cap_bytes, - KvRouteInfo { - node_id: node_id.clone(), + KvMemoryReplica { backing: KvReplicaBacking::CommittedSlot(slot), owner_local_indexed: true, get_durable_reservation: None, capacity_reservation, - tomb_tag, }, false, ) @@ -1666,18 +1817,21 @@ async fn handle_put_done_with_resolved_group( // Publish the primary route under the node-generation fence. This // closes the gap where MemberLeft marked/snapshotted routes between a // pre-check and a later DashMap insert. - let publish_tag = completed_info.tomb_tag.clone(); + let publish_tag = tomb_tag.clone(); let new_route = Arc::new(OneKvNodesRoutes { put_id, lease_id: lease_id_opt, atomic_group: atomic_group.clone(), - nodes_replicas: RwLock::new(HashMap::from([(node_id.clone(), completed_info)])), + node_replicas: RwLock::new(HashMap::from([( + node_id.clone(), + KvNodeReplicas::memory(publish_tag.clone(), completed_info), + )])), get_durable_slots_used: AtomicU32::new(0), }); let old_one_kv_routes = match publish_primary_route_tomb_fenced( &view.master_kv_router().inner().kv_routes, &key, - new_route, + new_route.clone(), &publish_tag, ) { Ok(previous) => previous, @@ -1830,13 +1984,11 @@ async fn handle_put_done_with_resolved_group( }; } }; - let completed_info = KvRouteInfo { - node_id: node_id.clone(), + let completed_info = KvMemoryReplica { backing: KvReplicaBacking::CommittedSlot(committed_slot), owner_local_indexed: true, get_durable_reservation: None, capacity_reservation, - tomb_tag, }; return publish_completed_put_route( view, @@ -1845,6 +1997,7 @@ async fn handle_put_done_with_resolved_group( lease_id_opt, atomic_group, node_id, + tomb_tag, completed_info, target_cap_bytes, None, @@ -2171,11 +2324,11 @@ async fn handle_put_append_start_inner( .as_ref() .map(|route| { route - .nodes_replicas + .node_replicas .read() - .values() - .filter_map(|replica| { - (!replica.tomb_tag.is_tomb()).then_some(replica.node_id.clone()) + .iter() + .filter_map(|(node_id, replicas)| { + replicas.has_live_backing().then_some(node_id.clone()) }) .collect::>() }) diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs index f42cd24..ac5736b 100644 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/reclaim.rs @@ -4,7 +4,7 @@ use crate::master_kv_router::msg_pack::{ BatchEvictOwnerSourceReq, BatchEvictOwnerSourceResp, BatchOwnerReclaimReq, OwnerReclaimBacking, OwnerReclaimItem, OwnerReclaimItemResp, OwnerReclaimItemState, OwnerReclaimPhase, OwnerReclaimReason, OwnerSourceEvictionOutcome, OwnerSourceEvictionVictim, - OwnerSourceEvictionVictimResp, owner_source_eviction_epoch, + OwnerSourceEvictionVictimResp, OwnerSourceSsdPolicy, owner_source_eviction_epoch, }; use crate::p2p::msg_pack::{MIN_EXPLICIT_RPC_TIMEOUT_SECS, MsgPack, RPCCaller}; use crate::rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, OK}; @@ -17,6 +17,10 @@ use std::time::Duration; const OWNER_RECLAIM_RPC_TIMEOUT: Duration = Duration::from_secs(MIN_EXPLICIT_RPC_TIMEOUT_SECS); const OWNER_RECLAIM_MAX_BATCH: usize = 256; +// Keep each transport/SSD transaction small enough to release physical slots +// continuously. Every entry remains an independently fenced single-KV +// victim; this is only an RPC and bounded-I/O aggregation limit. +const OWNER_RECLAIM_RPC_BATCH: usize = 32; const OWNER_RECLAIM_MERGE_WINDOW: Duration = Duration::from_millis(5); const EVICTION_RECLAIM_RETRY_INITIAL: Duration = Duration::from_millis(100); const EVICTION_RECLAIM_RETRY_MAX: Duration = Duration::from_secs(1); @@ -72,8 +76,8 @@ mod single_victim_transaction_tests { OwnerSourceEvictionVictim, PutAtomicGroup, PutAtomicGroupMember, }; use crate::master_kv_router::{ - CommittedSlotReplica, KvRouteInfo, MasterKeyActivityKind, MasterKeyActivityTable, - OneKvNodesRoutes, + CommittedSlotReplica, KvMemoryReplica, KvNodeReplicas, KvSsdReplica, MasterKeyActivityKind, + MasterKeyActivityTable, OneKvNodesRoutes, }; use crate::master_seg_manager::NodeTombTag; use parking_lot::RwLock; @@ -150,6 +154,8 @@ mod single_victim_transaction_tests { slot_index, slot_size: 4096, }, + ssd_backing_len: None, + ssd_policy: OwnerSourceSsdPolicy::Drop, } } @@ -167,50 +173,52 @@ mod single_victim_transaction_tests { else { unreachable!() }; - let owner_replica = KvRouteInfo { - node_id: owner.clone(), - backing: KvReplicaBacking::CommittedSlot(CommittedSlotReplica { - owner_node_id: owner.clone(), - grant_id: *grant_id, - slot_index: *slot_index, - slot_size: *slot_size, - addr: 0, - len: *slot_size, - base_addr: 0, - }), - owner_local_indexed: true, - get_durable_reservation: None, - capacity_reservation: None, - tomb_tag: NodeTombTag::new(), - }; + let owner_replica = KvNodeReplicas::memory( + NodeTombTag::new(), + KvMemoryReplica { + backing: KvReplicaBacking::CommittedSlot(CommittedSlotReplica { + owner_node_id: owner.clone(), + grant_id: *grant_id, + slot_index: *slot_index, + slot_size: *slot_size, + addr: 0, + len: *slot_size, + base_addr: 0, + }), + owner_local_indexed: true, + get_durable_reservation: None, + capacity_reservation: None, + }, + ); let mut replicas = HashMap::from([(owner.clone(), owner_replica)]); if include_cpu_replica { let cpu: NodeID = "cpu0".to_string().into(); replicas.insert( cpu.clone(), - KvRouteInfo { - node_id: cpu.clone(), - backing: KvReplicaBacking::CommittedSlot(CommittedSlotReplica { - owner_node_id: cpu, - grant_id: 900 + *grant_id, - slot_index: *slot_index, - slot_size: *slot_size, - addr: 0, - len: *slot_size, - base_addr: 0, - }), - owner_local_indexed: false, - get_durable_reservation: None, - capacity_reservation: None, - tomb_tag: NodeTombTag::new(), - }, + KvNodeReplicas::memory( + NodeTombTag::new(), + KvMemoryReplica { + backing: KvReplicaBacking::CommittedSlot(CommittedSlotReplica { + owner_node_id: cpu, + grant_id: 900 + *grant_id, + slot_index: *slot_index, + slot_size: *slot_size, + addr: 0, + len: *slot_size, + base_addr: 0, + }), + owner_local_indexed: false, + get_durable_reservation: None, + capacity_reservation: None, + }, + ), ); } Arc::new(OneKvNodesRoutes { put_id: member.put_id, lease_id: None, atomic_group, - nodes_replicas: RwLock::new(replicas), + node_replicas: RwLock::new(replicas), get_durable_slots_used: AtomicU32::new(0), }) } @@ -260,14 +268,16 @@ mod single_victim_transaction_tests { let counters = crate::master_kv_router::EvictionReclaimCounters::default(); record_last_route_removal(&counters, &removed); assert!(!removed.removed_last_route); + assert!(!removed.ssd_survived); + assert!(!removed.ssd_became_only_backing); assert_eq!( counters.last_route_removed_members.load(Ordering::Relaxed), 0 ); assert_eq!(counters.last_route_removed_bytes.load(Ordering::Relaxed), 0); let remaining = routes.get(&member.key).expect("CPU route must remain"); - assert!(!remaining.nodes_replicas.read().contains_key(&owner)); - assert!(remaining.nodes_replicas.read().contains_key("cpu0")); + assert!(!remaining.node_replicas.read().contains_key(&owner)); + assert!(remaining.node_replicas.read().contains_key("cpu0")); let last = source_victim("last", (10, 3), 7, 5); routes.insert(last.key.clone(), source_route(&owner, &last, None, false)); @@ -299,6 +309,141 @@ mod single_victim_transaction_tests { assert!(routes.contains_key(&stale.key)); } + #[test] + fn exact_source_memory_removal_preserves_same_owner_ssd_backing() { + let owner: NodeID = "gpu0".to_string().into(); + let member = source_victim("ssd-backed", (10, 5), 7, 7); + let route = source_route(&owner, &member, None, false); + route + .node_replicas + .write() + .get_mut(&owner) + .expect("owner route must exist") + .ssd = Some(KvSsdReplica { len: 4096 }); + let routes = dashmap::DashMap::new(); + routes.insert(member.key.clone(), route.clone()); + + let removed = + remove_exact_owner_source_route(&routes, &owner, &source_reclaim_item(&member)) + .expect("exact memory backing must be removed"); + + assert!(!removed.removed_last_route); + assert!(removed.ssd_survived); + assert!(removed.ssd_became_only_backing); + let current = routes + .get(&member.key) + .expect("SSD backing must keep the key route alive"); + let replicas = current.node_replicas.read(); + let owner_backings = replicas.get(&owner).expect("owner route must remain"); + assert!(owner_backings.memory.is_none()); + assert_eq!(owner_backings.ssd.as_ref().map(|ssd| ssd.len), Some(4096)); + } + + #[test] + fn ssd_preservation_selects_only_an_exact_last_live_backing() { + let owner: NodeID = "gpu0".to_string().into(); + let last = source_victim("last-for-ssd", (20, 1), 11, 1); + let last_route = source_route(&owner, &last, None, false); + let last_item = source_reclaim_item(&last); + assert!(exact_memory_reclaim_needs_ssd_with( + &owner, + &last_item, + &|key| (key == last.key).then(|| last_route.clone()), + )); + + let with_other = source_victim("other-live", (20, 2), 12, 2); + let with_other_route = source_route(&owner, &with_other, None, true); + let with_other_item = source_reclaim_item(&with_other); + assert!(!exact_memory_reclaim_needs_ssd_with( + &owner, + &with_other_item, + &|key| (key == with_other.key).then(|| with_other_route.clone()), + )); + + let already_on_ssd = source_victim("already-on-ssd", (20, 3), 13, 3); + let already_on_ssd_route = source_route(&owner, &already_on_ssd, None, false); + already_on_ssd_route + .node_replicas + .write() + .get_mut(&owner) + .expect("owner route must exist") + .ssd = Some(KvSsdReplica { len: 4096 }); + let already_on_ssd_item = source_reclaim_item(&already_on_ssd); + assert!(!exact_memory_reclaim_needs_ssd_with( + &owner, + &already_on_ssd_item, + &|key| (key == already_on_ssd.key).then(|| already_on_ssd_route.clone()), + )); + + let stale = source_victim("stale-for-ssd", (20, 4), 14, 4); + let stale_route = source_route(&owner, &stale, None, false); + let wrong_identity = source_victim("stale-for-ssd", stale.put_id, 999, 4); + assert!(!exact_memory_reclaim_needs_ssd_with( + &owner, + &source_reclaim_item(&wrong_identity), + &|key| (key == stale.key).then(|| stale_route.clone()), + )); + } + + #[test] + fn direct_delete_filters_before_ssd_and_drop_finishes_without_waiting() { + let owner: NodeID = "gpu0".to_string().into(); + let mut last = source_victim("last-candidate", (21, 1), 15, 1); + last.ssd_policy = OwnerSourceSsdPolicy::SelectLastLive; + let mut backed = source_victim("already-backed", (21, 2), 16, 2); + backed.ssd_policy = OwnerSourceSsdPolicy::SelectLastLive; + let routes = dashmap::DashMap::new(); + routes.insert(last.key.clone(), source_route(&owner, &last, None, false)); + routes.insert( + backed.key.clone(), + source_route(&owner, &backed, None, true), + ); + let activity = MasterKeyActivityTable::default(); + let (responses, busy) = direct_delete_exact_owner_source_batch_with( + &activity, + &owner, + 81, + &[last.clone(), backed.clone()], + &|key| routes.get(key).map(|route| route.clone()), + |item| remove_exact_owner_source_route(&routes, &owner, item).is_some(), + ); + assert_eq!(busy, DirectDeleteBatchBusySummary::default()); + assert_eq!( + responses + .iter() + .map(|response| response.outcome) + .collect::>(), + vec![ + OwnerSourceEvictionOutcome::SsdCandidate, + OwnerSourceEvictionOutcome::Completed, + ] + ); + assert!(routes.contains_key(&last.key)); + assert!( + routes + .get(&backed.key) + .unwrap() + .node_replicas + .read() + .contains_key("cpu0") + ); + assert!(!activity.has_reclaim(&last.key)); + + last.ssd_policy = OwnerSourceSsdPolicy::Drop; + let dropped = direct_delete_exact_owner_source_with( + &activity, + &owner, + &last, + owner_source_eviction_epoch(82, 0), + &|key| routes.get(key).map(|route| route.clone()), + |item| remove_exact_owner_source_route(&routes, &owner, item).is_some(), + ); + assert_eq!(dropped.outcome, OwnerSourceEvictionOutcome::Completed); + assert!(!dropped.ssd_backing_committed); + assert!(!routes.contains_key(&last.key)); + assert!(!activity.has_reclaim(&last.key)); + } + #[test] fn singleton_source_is_independent_of_atomic_group_siblings() { let owner: NodeID = "gpu0".to_string().into(); @@ -347,8 +492,12 @@ mod single_victim_transaction_tests { #[test] fn direct_delete_batch_keeps_results_independent_and_replay_idempotent() { let owner: NodeID = "gpu0".to_string().into(); - let ready = source_victim("ready", (14, 0), 11, 0); - let busy = source_victim("busy", (14, 1), 11, 1); + let mut ready = source_victim("ready", (14, 0), 11, 0); + ready.ssd_backing_len = Some(4096); + ready.ssd_policy = OwnerSourceSsdPolicy::Persisted; + let mut busy = source_victim("busy", (14, 1), 11, 1); + busy.ssd_backing_len = Some(4096); + busy.ssd_policy = OwnerSourceSsdPolicy::Persisted; let stale = source_victim("stale", (14, 2), 11, 2); let routes = dashmap::DashMap::new(); for victim in [&ready, &busy, &stale] { @@ -361,7 +510,9 @@ mod single_victim_transaction_tests { let _busy_get = activity .reserve(&busy.key, MasterKeyActivityKind::Get, false) .expect("busy victim must hold a master Get lease"); - let stale_request = source_victim("stale", stale.put_id, 999, 2); + let mut stale_request = source_victim("stale", stale.put_id, 999, 2); + stale_request.ssd_backing_len = Some(4096); + stale_request.ssd_policy = OwnerSourceSsdPolicy::Persisted; let victims = vec![ready.clone(), busy.clone(), stale_request]; let (responses, busy_summary) = direct_delete_exact_owner_source_batch_with( activity.as_ref(), @@ -391,6 +542,14 @@ mod single_victim_transaction_tests { vec![0, 1, 2], "one batch response vector must stay aligned with every input victim" ); + assert_eq!( + responses + .iter() + .map(|response| response.ssd_backing_committed) + .collect::>(), + vec![true, false, false], + "only the exact fenced write-back victim may publish SSD backing" + ); assert_eq!( busy_summary, DirectDeleteBatchBusySummary { @@ -400,9 +559,43 @@ mod single_victim_transaction_tests { ..Default::default() } ); - assert!(!routes.contains_key(&ready.key)); + let ready_route = routes + .get(&ready.key) + .expect("SSD write-back must keep the ready route alive"); + let ready_replicas = ready_route.node_replicas.read(); + let ready_backings = ready_replicas + .get(&owner) + .expect("same-owner SSD backing must remain"); + assert!(ready_backings.memory.is_none()); + assert_eq!(ready_backings.ssd.as_ref().map(|ssd| ssd.len), Some(4096)); + drop(ready_replicas); + drop(ready_route); assert!(routes.contains_key(&busy.key)); assert!(routes.contains_key(&stale.key)); + assert!( + routes + .get(&busy.key) + .unwrap() + .node_replicas + .read() + .get(&owner) + .unwrap() + .ssd + .is_none(), + "a busy key must not publish SSD backing before its master fence" + ); + assert!( + routes + .get(&stale.key) + .unwrap() + .node_replicas + .read() + .get(&owner) + .unwrap() + .ssd + .is_none(), + "a stale exact backing must not publish SSD backing" + ); assert!(!activity.has_reclaim(&ready.key)); let replay_delete_called = AtomicBool::new(false); @@ -418,6 +611,10 @@ mod single_victim_transaction_tests { }, ); assert_eq!(replay.outcome, OwnerSourceEvictionOutcome::Completed); + assert!( + replay.ssd_backing_committed, + "a lost direct-delete response must replay the already-published SSD terminal" + ); assert_eq!(replay.busy_cause, None); assert!(!replay_delete_called.load(Ordering::Relaxed)); } @@ -531,10 +728,14 @@ fn allocation_member_from_route( if route.lease_id.is_some() { return Err(MasterCapacityPlanError::RouteChanged); } - let replicas = route.nodes_replicas.read(); - let replica = replicas + let replicas = route.node_replicas.read(); + let node_replicas = replicas .get(owner) - .filter(|replica| !replica.tomb_tag.is_tomb()) + .filter(|replicas| !replicas.tomb_tag.is_tomb()) + .ok_or(MasterCapacityPlanError::RouteChanged)?; + let replica = node_replicas + .memory + .as_ref() .ok_or(MasterCapacityPlanError::RouteChanged)?; if replica.owner_local_indexed { return Err(MasterCapacityPlanError::WrongRole); @@ -588,17 +789,23 @@ fn route_item( if expected_put_id.is_some_and(|put_id| put_id != route.put_id) || route.lease_id.is_some() { return None; } - let replicas = route.nodes_replicas.read(); - let target = replicas.get(owner_node_id)?; - if target.tomb_tag.is_tomb() { + let replicas = route.node_replicas.read(); + let node_replicas = replicas.get(owner_node_id)?; + if node_replicas.tomb_tag.is_tomb() { return None; } + let target = node_replicas.memory.as_ref()?; let backing = match &target.backing { - KvReplicaBacking::Allocation(_) if required_slot_size.is_none() => { + KvReplicaBacking::Allocation(allocation) if required_slot_size.is_none() => { if target.owner_local_indexed { OwnerReclaimBacking::Allocation } else { - OwnerReclaimBacking::UnindexedAllocation + OwnerReclaimBacking::UnindexedAllocation { + addr: allocation.base_addr().checked_add(allocation.addr())?, + base_addr: allocation.base_addr(), + len: allocation.size(), + capacity_bytes: allocation.capcity(), + } } } KvReplicaBacking::Allocation(_) => return None, @@ -639,7 +846,9 @@ fn item_still_valid(view: &MasterKvRouterView, owner: &NodeID, item: &OwnerRecla &item.key, Some(item.put_id), match &item.backing { - OwnerReclaimBacking::Allocation | OwnerReclaimBacking::UnindexedAllocation => None, + OwnerReclaimBacking::Allocation | OwnerReclaimBacking::UnindexedAllocation { .. } => { + None + } OwnerReclaimBacking::CommittedSlot { slot_size, .. } => Some(*slot_size), }, item.reason, @@ -648,6 +857,81 @@ fn item_still_valid(view: &MasterKvRouterView, owner: &NodeID, item: &OwnerRecla .is_some_and(|current| current.backing == item.backing && current.reason == item.reason) } +/// Publish bytes already persisted by the owner onto the existing route while +/// both master and owner Prepare fences still protect the exact memory +/// generation. Memory remains present until the subsequent Commit succeeds, +/// so Get never observes a route gap between DRAM and SSD. +fn publish_prepared_ssd_backing( + view: &MasterKvRouterView, + owner: &NodeID, + item: &OwnerReclaimItem, + ssd_backing_len: Option, +) -> Result { + let Some(len) = ssd_backing_len else { + return Ok(false); + }; + if !item_still_valid(view, owner, item) { + return Err(format!( + "exact memory route changed before SSD publication: key={} epoch={}", + item.key, item.epoch + )); + } + let route = view + .master_kv_router() + .inner() + .kv_routes + .get(&item.key) + .map(|route| route.clone()) + .ok_or_else(|| format!("route disappeared before SSD publication: key={}", item.key))?; + let existing_ssd_len = route + .node_replicas + .read() + .get(owner) + .and_then(|replicas| replicas.ssd.as_ref()) + .map(|ssd| ssd.len); + if let Some(existing_len) = existing_ssd_len { + return if existing_len == len { + Ok(false) + } else { + Err(format!( + "existing SSD backing length mismatch: key={} existing={} prepared={}", + item.key, existing_len, len + )) + }; + } + match route.commit_ssd_replica(owner, len) { + super::SsdReplicaCommitStatus::Committed => Ok(true), + super::SsdReplicaCommitStatus::MissingMemory => Err(format!( + "memory backing disappeared before SSD publication: key={}", + item.key + )), + super::SsdReplicaCommitStatus::TombedNode => Err(format!( + "owner generation was tombed before SSD publication: owner={} key={}", + owner, item.key + )), + super::SsdReplicaCommitStatus::LengthMismatch => Err(format!( + "persisted SSD length mismatches memory route: key={} len={}", + item.key, len + )), + } +} + +fn rollback_new_ssd_backing( + view: &MasterKvRouterView, + owner: &NodeID, + item: &OwnerReclaimItem, +) -> bool { + if !item_still_valid(view, owner, item) { + return false; + } + view.master_kv_router() + .inner() + .kv_routes + .get(&item.key) + .filter(|route| route.put_id == item.put_id) + .is_some_and(|route| route.remove_ssd_replica(owner)) +} + async fn call_owner_phase( view: &MasterKvRouterView, owner: &NodeID, @@ -657,11 +941,12 @@ async fn call_owner_phase( if items.is_empty() { return Ok(Vec::new()); } - debug_assert!( - items - .iter() - .all(|item| item.backing != OwnerReclaimBacking::UnindexedAllocation) - ); + debug_assert!(items.iter().all(|item| { + !matches!( + &item.backing, + OwnerReclaimBacking::UnindexedAllocation { .. } + ) || item.reason == OwnerReclaimReason::MasterAllocationCapacity + })); let caller = RPCCaller::::new(); caller.regist(view.p2p_module()); let resp = caller @@ -719,11 +1004,11 @@ fn clear_master_fence(view: &MasterKvRouterView, item: &OwnerReclaimItem) { } } -#[cfg(test)] async fn abort_prepared( view: &MasterKvRouterView, owner: &NodeID, items: Vec, + newly_published_ssd: HashSet<(String, u64)>, ) -> Vec { if items.is_empty() { return Vec::new(); @@ -734,9 +1019,22 @@ async fn abort_prepared( for (item, response) in items.into_iter().zip(responses.into_iter()) { match response.state { OwnerReclaimItemState::Committed => already_committed.push(item), - OwnerReclaimItemState::Aborted - | OwnerReclaimItemState::Stale - | OwnerReclaimItemState::Finalized => clear_master_fence(view, &item), + OwnerReclaimItemState::Aborted => { + if newly_published_ssd.contains(&(item.key.clone(), item.epoch)) + && !rollback_new_ssd_backing(view, owner, &item) + { + tracing::warn!( + owner = %owner, + key = %item.key, + epoch = item.epoch, + "new SSD backing was not removable after owner reclaim abort" + ); + } + clear_master_fence(view, &item); + } + OwnerReclaimItemState::Stale | OwnerReclaimItemState::Finalized => { + clear_master_fence(view, &item) + } state => tracing::warn!( "owner reclaim abort returned unresolved state: key={} epoch={} state={:?} detail={}", item.key, @@ -755,14 +1053,18 @@ async fn abort_prepared( items.len(), err ); - spawn_abort_retry(view.clone(), owner.clone(), items); + spawn_abort_retry(view.clone(), owner.clone(), items, newly_published_ssd); Vec::new() } } } -#[cfg(test)] -fn spawn_abort_retry(view: MasterKvRouterView, owner: NodeID, items: Vec) { +fn spawn_abort_retry( + view: MasterKvRouterView, + owner: NodeID, + items: Vec, + newly_published_ssd: HashSet<(String, u64)>, +) { if items.is_empty() { return; } @@ -779,9 +1081,22 @@ fn spawn_abort_retry(view: MasterKvRouterView, owner: NodeID, items: Vec committed.push(item), - OwnerReclaimItemState::Aborted - | OwnerReclaimItemState::Stale - | OwnerReclaimItemState::Finalized => clear_master_fence(&view, &item), + OwnerReclaimItemState::Aborted => { + if newly_published_ssd.contains(&(item.key.clone(), item.epoch)) + && !rollback_new_ssd_backing(&view, &owner, &item) + { + tracing::warn!( + owner = %owner, + key = %item.key, + epoch = item.epoch, + "new SSD backing was not removable after retried owner reclaim abort" + ); + } + clear_master_fence(&view, &item); + } + OwnerReclaimItemState::Stale | OwnerReclaimItemState::Finalized => { + clear_master_fence(&view, &item) + } _ => next.push(item), } } @@ -812,13 +1127,28 @@ fn spawn_abort_retry(view: MasterKvRouterView, owner: NodeID, items: Vec bool { +fn reclaim_backing_matches( + replica: &super::KvMemoryReplica, + expected: &OwnerReclaimBacking, +) -> bool { match (&replica.backing, expected) { (KvReplicaBacking::Allocation(_), OwnerReclaimBacking::Allocation) => { replica.owner_local_indexed } - (KvReplicaBacking::Allocation(_), OwnerReclaimBacking::UnindexedAllocation) => { + ( + KvReplicaBacking::Allocation(allocation), + OwnerReclaimBacking::UnindexedAllocation { + addr, + base_addr, + len, + capacity_bytes, + }, + ) => { !replica.owner_local_indexed + && allocation.base_addr().checked_add(allocation.addr()) == Some(*addr) + && allocation.base_addr() == *base_addr + && allocation.size() == *len + && allocation.capcity() == *capacity_bytes } ( KvReplicaBacking::CommittedSlot(slot), @@ -841,7 +1171,7 @@ fn owner_source_member_weight(backing: &OwnerReclaimBacking) -> Option { OwnerReclaimBacking::CommittedSlot { slot_size, .. } => u32::try_from(*slot_size).ok(), // Allocation does not carry an address/generation identity in the // current wire contract, so accepting it would not be an exact delete. - OwnerReclaimBacking::Allocation | OwnerReclaimBacking::UnindexedAllocation => None, + OwnerReclaimBacking::Allocation | OwnerReclaimBacking::UnindexedAllocation { .. } => None, } } @@ -889,9 +1219,14 @@ fn plan_exact_owner_source_victim_with( )); } let replica_matches = { - let replicas = route.nodes_replicas.read(); + let replicas = route.node_replicas.read(); match replicas.get(owner) { - Some(replica) if !replica.tomb_tag.is_tomb() => { + Some(node_replicas) if !node_replicas.tomb_tag.is_tomb() => { + let Some(replica) = node_replicas.memory.as_ref() else { + return OwnerSourceVictimPlan::Completed( + "exact source memory replica is already absent", + ); + }; if !replica.owner_local_indexed { return OwnerSourceVictimPlan::Rejected(format!( "source route is not owner-local indexed: key={}", @@ -922,6 +1257,7 @@ enum DirectDeleteBusyCause { struct DirectDeleteResult { outcome: OwnerSourceEvictionOutcome, + ssd_backing_committed: bool, detail: String, busy_cause: Option, } @@ -930,6 +1266,7 @@ impl DirectDeleteResult { fn terminal(outcome: OwnerSourceEvictionOutcome, detail: impl Into) -> Self { Self { outcome, + ssd_backing_committed: false, detail: detail.into(), busy_cause: None, } @@ -938,6 +1275,7 @@ impl DirectDeleteResult { fn activity_busy(snapshot: super::MasterKeyActivitySnapshot) -> Self { Self { outcome: OwnerSourceEvictionOutcome::RetryableBusy, + ssd_backing_committed: false, detail: format!( "master key activity is busy: puts={} gets={} replicas={} reclaim_installed={}", snapshot.puts, snapshot.gets, snapshot.replicas, snapshot.reclaim_installed @@ -949,12 +1287,43 @@ impl DirectDeleteResult { fn delete_under_fence_busy() -> Self { Self { outcome: OwnerSourceEvictionOutcome::RetryableBusy, + ssd_backing_committed: false, detail: "exact source route could not be deleted under its master fence".to_string(), busy_cause: Some(DirectDeleteBusyCause::DeleteUnderFence), } } } +fn exact_ssd_writeback_is_published( + owner: &NodeID, + victim: &OwnerSourceEvictionVictim, + route_lookup: &dyn Fn(&str) -> Option>, +) -> bool { + if victim.ssd_policy != OwnerSourceSsdPolicy::Persisted { + return false; + } + let Some(expected_len) = victim.ssd_backing_len else { + return false; + }; + let Some(route) = route_lookup(&victim.key) else { + return false; + }; + if route.put_id != victim.put_id { + return false; + } + route + .node_replicas + .read() + .get(owner) + .is_some_and(|replicas| { + !replicas.tomb_tag.is_tomb() + && replicas + .ssd + .as_ref() + .is_some_and(|ssd| ssd.len == expected_len) + }) +} + #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] struct DirectDeleteBatchBusySummary { activity_busy_items: u64, @@ -1011,7 +1380,11 @@ fn direct_delete_exact_owner_source_with( let member = match plan_exact_owner_source_victim_with(owner, victim, route_lookup) { OwnerSourceVictimPlan::Ready(member) => member, OwnerSourceVictimPlan::Completed(detail) => { - return DirectDeleteResult::terminal(OwnerSourceEvictionOutcome::Completed, detail); + let mut result = + DirectDeleteResult::terminal(OwnerSourceEvictionOutcome::Completed, detail); + result.ssd_backing_committed = + exact_ssd_writeback_is_published(owner, victim, route_lookup); + return result; } OwnerSourceVictimPlan::Stale(detail) => { return DirectDeleteResult::terminal(OwnerSourceEvictionOutcome::Stale, detail); @@ -1038,17 +1411,97 @@ fn direct_delete_exact_owner_source_with( let result = match plan_exact_owner_source_victim_with(owner, victim, route_lookup) { OwnerSourceVictimPlan::Ready(_) => { - if delete(&item) { - DirectDeleteResult::terminal( - OwnerSourceEvictionOutcome::Completed, - "exact source route deleted by batch handler", - ) - } else { - DirectDeleteResult::delete_under_fence_busy() + let ssd_ready = match victim.ssd_policy { + OwnerSourceSsdPolicy::Drop => { + if victim.ssd_backing_len.is_none() { + Ok(()) + } else { + Err(DirectDeleteResult::terminal( + OwnerSourceEvictionOutcome::RejectedNotEvictable, + format!("drop policy must not carry SSD bytes: key={}", victim.key), + )) + } + } + OwnerSourceSsdPolicy::SelectLastLive => { + if victim.ssd_backing_len.is_some() { + Err(DirectDeleteResult::terminal( + OwnerSourceEvictionOutcome::RejectedNotEvictable, + format!( + "SSD selection policy must not carry prepared bytes: key={}", + victim.key + ), + )) + } else if exact_memory_reclaim_needs_ssd_with(owner, &item, route_lookup) { + Err(DirectDeleteResult::terminal( + OwnerSourceEvictionOutcome::SsdCandidate, + "exact source is the last live backing; owner SSD admission required", + )) + } else { + Ok(()) + } + } + OwnerSourceSsdPolicy::Persisted => match victim.ssd_backing_len { + None => Err(DirectDeleteResult::terminal( + OwnerSourceEvictionOutcome::RejectedNotEvictable, + format!( + "persisted SSD policy requires exact bytes: key={}", + victim.key + ), + )), + Some(len) => match route_lookup(&victim.key) + .map(|route| route.commit_ssd_replica(owner, len)) + { + Some(super::SsdReplicaCommitStatus::Committed) => Ok(()), + Some(super::SsdReplicaCommitStatus::LengthMismatch) => { + Err(DirectDeleteResult::terminal( + OwnerSourceEvictionOutcome::RejectedNotEvictable, + format!( + "SSD write-back length does not match the exact source: key={} len={}", + victim.key, len + ), + )) + } + Some( + super::SsdReplicaCommitStatus::MissingMemory + | super::SsdReplicaCommitStatus::TombedNode, + ) + | None => Err(DirectDeleteResult::terminal( + OwnerSourceEvictionOutcome::Stale, + format!( + "exact source changed before SSD write-back publication: key={}", + victim.key + ), + )), + }, + }, + }; + match ssd_ready { + Err(result) => result, + Ok(()) => { + let mut result = if delete(&item) { + DirectDeleteResult::terminal( + OwnerSourceEvictionOutcome::Completed, + if victim.ssd_policy == OwnerSourceSsdPolicy::Persisted { + "SSD backing published and exact memory source deleted by batch handler" + } else { + "exact source route deleted by batch handler" + }, + ) + } else { + DirectDeleteResult::delete_under_fence_busy() + }; + result.ssd_backing_committed = + victim.ssd_policy == OwnerSourceSsdPolicy::Persisted; + result + } } } OwnerSourceVictimPlan::Completed(detail) => { - DirectDeleteResult::terminal(OwnerSourceEvictionOutcome::Completed, detail) + let mut result = + DirectDeleteResult::terminal(OwnerSourceEvictionOutcome::Completed, detail); + result.ssd_backing_committed = + exact_ssd_writeback_is_published(owner, victim, route_lookup); + result } OwnerSourceVictimPlan::Stale(detail) => { DirectDeleteResult::terminal(OwnerSourceEvictionOutcome::Stale, detail) @@ -1090,6 +1543,7 @@ fn direct_delete_exact_owner_source_batch_with( responses.push(OwnerSourceEvictionVictimResp { victim_index: u32::try_from(index).unwrap_or(u32::MAX), outcome: result.outcome, + ssd_backing_committed: result.ssd_backing_committed, detail: result.detail, }); } @@ -1167,6 +1621,7 @@ pub(crate) async fn handle_batch_evict_owner_source( OwnerSourceEvictionOutcome::Accepted => &counters.source_evict_accepted, OwnerSourceEvictionOutcome::AlreadyInProgress => &counters.source_evict_in_progress, OwnerSourceEvictionOutcome::Completed => &counters.source_evict_completed, + OwnerSourceEvictionOutcome::SsdCandidate => &counters.source_evict_accepted, OwnerSourceEvictionOutcome::RetryableBusy | OwnerSourceEvictionOutcome::Unspecified => { &counters.source_evict_retryable_busy } @@ -1184,11 +1639,16 @@ pub(crate) async fn handle_batch_evict_owner_source( .iter() .filter(|response| response.outcome == OwnerSourceEvictionOutcome::RetryableBusy) .count(); + let ssd_candidates = responses + .iter() + .filter(|response| response.outcome == OwnerSourceEvictionOutcome::SsdCandidate) + .count(); tracing::info!( owner = %owner, operation_id, victims = responses.len(), completed, + ssd_candidates, retryable, activity_busy_items = busy.activity_busy_items, put_busy_items = busy.put_busy_items, @@ -1216,7 +1676,10 @@ pub(crate) async fn handle_batch_evict_owner_source( struct RemovedOwnerSource { desc: NodeValueReplicaDesc, capacity_bytes: u64, + logical_bytes: u64, removed_last_route: bool, + ssd_survived: bool, + ssd_became_only_backing: bool, } fn record_last_route_removal( @@ -1244,28 +1707,56 @@ fn remove_exact_owner_source_route( return None; } let removed_desc = { - let mut replicas = route.nodes_replicas.write(); - let Some(replica) = replicas.get(owner) else { + let mut replicas = route.node_replicas.write(); + let Some(node_replicas) = replicas.get_mut(owner) else { + return None; + }; + if node_replicas.tomb_tag.is_tomb() { + return None; + } + let Some(replica) = node_replicas.memory.as_ref() else { return None; }; if !reclaim_backing_matches(replica, &item.backing) { return None; } let capacity_bytes = replica.backing.capacity_bytes(); + let logical_bytes = replica.backing.len(); let desc = NodeValueReplicaDesc { weight_bytes: u32::try_from(capacity_bytes).unwrap_or(u32::MAX), put_id: route.put_id, }; - replicas.remove(owner).map(|_| (desc, capacity_bytes)) + node_replicas.memory.take(); + let ssd_survived = node_replicas.ssd.is_some(); + let remove_node_entry = !ssd_survived; + if remove_node_entry { + replicas.remove(owner); + } + let live_backings = replicas + .values() + .filter(|replicas| !replicas.tomb_tag.is_tomb()) + .map(|replicas| { + usize::from(replicas.memory.is_some()) + usize::from(replicas.ssd.is_some()) + }) + .sum::(); + let ssd_became_only_backing = ssd_survived && live_backings == 1; + Some(( + desc, + capacity_bytes, + logical_bytes, + ssd_survived, + ssd_became_only_backing, + )) }; - let (removed_desc, capacity_bytes) = removed_desc?; + let (removed_desc, capacity_bytes, logical_bytes, ssd_survived, ssd_became_only_backing) = + removed_desc?; - let removed_last_route = if route.nodes_replicas.read().is_empty() { + let removed_last_route = if route.node_replicas.read().is_empty() { routes .remove_if(&item.key, |_, current| { Arc::ptr_eq(current, &route) && current.put_id == item.put_id - && current.nodes_replicas.read().is_empty() + && current.node_replicas.read().is_empty() }) .is_some() } else { @@ -1274,7 +1765,10 @@ fn remove_exact_owner_source_route( Some(RemovedOwnerSource { desc: removed_desc, capacity_bytes, + logical_bytes, removed_last_route, + ssd_survived, + ssd_became_only_backing, }) } @@ -1294,6 +1788,23 @@ fn remove_reclaimed_replica( let removed = remove_exact_owner_source_route(&view.master_kv_router().inner().kv_routes, owner, item); if let Some(removed) = removed { + let ssd_tier = &view.master_kv_router().inner().ssd_tier_counters; + if removed.ssd_survived { + ssd_tier + .memory_removed_ssd_survived_items + .fetch_add(1, Ordering::Relaxed); + ssd_tier + .memory_removed_ssd_survived_bytes + .fetch_add(removed.logical_bytes, Ordering::Relaxed); + } + if removed.ssd_became_only_backing { + ssd_tier + .memory_removed_ssd_became_only_items + .fetch_add(1, Ordering::Relaxed); + ssd_tier + .memory_removed_ssd_became_only_bytes + .fetch_add(removed.logical_bytes, Ordering::Relaxed); + } let counters = view .master_kv_router() .eviction_reclaim_counters(owner.as_ref()); @@ -1340,7 +1851,10 @@ fn finish_unindexed_allocations( ) -> u32 { let mut reclaimed = 0u32; for item in items { - debug_assert_eq!(item.backing, OwnerReclaimBacking::UnindexedAllocation); + debug_assert!(matches!( + &item.backing, + OwnerReclaimBacking::UnindexedAllocation { .. } + )); if remove_reclaimed_replica(view, owner, &item) { clear_master_fence(view, &item); reclaimed = reclaimed.saturating_add(1); @@ -1356,12 +1870,86 @@ fn finish_unindexed_allocations( reclaimed } -fn partition_reclaim_coordination( +/// Return true only when removing this exact memory source would leave the key +/// with no live backing. The caller holds the per-key master reclaim fence, so +/// this route snapshot cannot race another Put/Get/replica/reclaim mutation. +fn exact_memory_reclaim_needs_ssd_with( + owner: &NodeID, + item: &OwnerReclaimItem, + route_lookup: &dyn Fn(&str) -> Option>, +) -> bool { + let Some(route) = route_lookup(&item.key) else { + return false; + }; + if route.put_id != item.put_id || route.lease_id.is_some() { + return false; + } + let replicas = route.node_replicas.read(); + let Some(target) = replicas.get(owner) else { + return false; + }; + if target.tomb_tag.is_tomb() + || !target + .memory + .as_ref() + .is_some_and(|memory| reclaim_backing_matches(memory, &item.backing)) + { + return false; + } + + replicas.iter().all(|(node_id, node_replicas)| { + if node_replicas.tomb_tag.is_tomb() { + return true; + } + if node_id == owner { + // The exact memory above is the source being removed. An existing + // same-owner SSD backing already preserves this route. + node_replicas.ssd.is_none() + } else { + !node_replicas.has_live_backing() + } + }) +} + +fn exact_memory_reclaim_needs_ssd( + view: &MasterKvRouterView, + owner: &NodeID, + item: &OwnerReclaimItem, +) -> bool { + exact_memory_reclaim_needs_ssd_with(owner, item, &|key| { + view.master_kv_router() + .inner() + .kv_routes + .get(key) + .map(|route| route.clone()) + }) +} + +fn partition_reclaim_coordination( items: Vec, -) -> (Vec, Vec) { - items - .into_iter() - .partition(|item| item.backing == OwnerReclaimBacking::UnindexedAllocation) + should_coordinate_unindexed: F, +) -> (Vec, Vec) +where + F: Fn(&OwnerReclaimItem) -> bool, +{ + items.into_iter().partition(|item| { + matches!( + &item.backing, + OwnerReclaimBacking::UnindexedAllocation { .. } + ) && !should_coordinate_unindexed(item) + }) +} + +fn owner_has_ssd_storage(view: &MasterKvRouterView, owner: &NodeID) -> bool { + view.cluster_manager() + .get_member_info_cached(owner.as_ref()) + .and_then(|member| { + member + .metadata + .get(crate::cluster_manager::META_KEY_KV_SSD_STORAGE) + .cloned() + }) + .is_some_and(|value| value == "true") } async fn finish_committed( @@ -1465,7 +2053,6 @@ fn spawn_finalize_retry(view: MasterKvRouterView, owner: NodeID, items: Vec prepared.push(item), + OwnerReclaimItemState::Prepared => { + match publish_prepared_ssd_backing(view, owner, &item, response.ssd_backing_len) { + Ok(newly_published) => { + if newly_published { + newly_published_ssd.insert((item.key.clone(), item.epoch)); + } + prepared.push(item); + } + Err(detail) => { + counters.route_changed.fetch_add(1, Ordering::Relaxed); + tracing::warn!( + owner = %owner, + key = %item.key, + epoch = item.epoch, + detail = %detail, + "aborting owner reclaim after SSD backing publication validation failed" + ); + ssd_publish_failed.push(item); + } + } + } OwnerReclaimItemState::Committed => committed.push(item), OwnerReclaimItemState::Busy => { if response.detail == "owner local memory still has active holders" { @@ -1571,6 +2183,7 @@ async fn reclaim_items( } } } + committed.extend(abort_prepared(view, owner, ssd_publish_failed, HashSet::new()).await); let mut invalid_prepared = Vec::new(); prepared.retain(|item| { @@ -1581,7 +2194,14 @@ async fn reclaim_items( } valid }); - committed.extend(abort_prepared(view, owner, invalid_prepared).await); + let invalid_published = invalid_prepared + .iter() + .filter_map(|item| { + let identity = (item.key.clone(), item.epoch); + newly_published_ssd.contains(&identity).then_some(identity) + }) + .collect(); + committed.extend(abort_prepared(view, owner, invalid_prepared, invalid_published).await); if !prepared.is_empty() { match call_owner_phase(view, owner, OwnerReclaimPhase::Commit, prepared.clone()).await { @@ -1594,7 +2214,15 @@ async fn reclaim_items( unresolved.push(item); } } - committed.extend(abort_prepared(view, owner, unresolved).await); + let unresolved_published = unresolved + .iter() + .filter_map(|item| { + let identity = (item.key.clone(), item.epoch); + newly_published_ssd.contains(&identity).then_some(identity) + }) + .collect(); + committed + .extend(abort_prepared(view, owner, unresolved, unresolved_published).await); } Err(err) => { tracing::warn!( @@ -1603,7 +2231,14 @@ async fn reclaim_items( prepared.len(), err ); - committed.extend(abort_prepared(view, owner, prepared).await); + let prepared_published = prepared + .iter() + .filter_map(|item| { + let identity = (item.key.clone(), item.epoch); + newly_published_ssd.contains(&identity).then_some(identity) + }) + .collect(); + committed.extend(abort_prepared(view, owner, prepared, prepared_published).await); } } } @@ -1682,7 +2317,10 @@ async fn reclaim_single_victim( return 0; } - let (master_only, owner_coordinated) = partition_reclaim_coordination(fenced.clone()); + let owner_has_ssd = owner_has_ssd_storage(view, owner); + let (master_only, owner_coordinated) = partition_reclaim_coordination(fenced.clone(), |item| { + owner_has_ssd && exact_memory_reclaim_needs_ssd(view, owner, item) + }); if owner_coordinated.is_empty() { // All master-owned allocations are fenced and revalidated before the // first route mutation, so no member can be admitted independently. @@ -1765,7 +2403,23 @@ async fn reclaim_single_victim( let mut blocked = false; for (item, response) in pending.iter().cloned().zip(prepare_responses) { match response.state { - OwnerReclaimItemState::Prepared => prepared.push(item), + OwnerReclaimItemState::Prepared => { + match publish_prepared_ssd_backing(view, owner, &item, response.ssd_backing_len) + { + Ok(_) => prepared.push(item), + Err(detail) => { + counters.route_changed.fetch_add(1, Ordering::Relaxed); + tracing::warn!( + owner = %owner, + key = %item.key, + epoch = item.epoch, + detail = %detail, + "single-key reclaim SSD publication validation failed" + ); + blocked = true; + } + } + } OwnerReclaimItemState::Committed => { committed_keys.insert(item.key); } @@ -1851,22 +2505,35 @@ mod reclaim_partition_tests { indexed_allocation.backing = OwnerReclaimBacking::Allocation; indexed_allocation.reason = OwnerReclaimReason::OwnerCapacityEviction; let mut unindexed_allocation = candidate(2); - unindexed_allocation.backing = OwnerReclaimBacking::UnindexedAllocation; + unindexed_allocation.backing = OwnerReclaimBacking::UnindexedAllocation { + addr: 0x2000, + base_addr: 0x1000, + len: 4096, + capacity_bytes: 4096, + }; unindexed_allocation.reason = OwnerReclaimReason::MasterAllocationCapacity; let committed_slot = candidate(3); - let (master_only, owner_coordinated) = partition_reclaim_coordination(vec![ - indexed_allocation, + let candidates = vec![ + indexed_allocation.clone(), unindexed_allocation.clone(), - committed_slot, - ]); + committed_slot.clone(), + ]; + let (master_only, owner_coordinated) = + partition_reclaim_coordination(candidates.clone(), |_| false); - assert_eq!(master_only, vec![unindexed_allocation]); + assert_eq!(master_only, vec![unindexed_allocation.clone()]); assert_eq!(owner_coordinated.len(), 2); - assert!( - owner_coordinated - .iter() - .all(|item| item.backing != OwnerReclaimBacking::UnindexedAllocation) + assert!(owner_coordinated.iter().all(|item| !matches!( + &item.backing, + OwnerReclaimBacking::UnindexedAllocation { .. } + ))); + + let (master_only, owner_coordinated) = partition_reclaim_coordination(candidates, |_| true); + assert!(master_only.is_empty()); + assert_eq!( + owner_coordinated, + vec![indexed_allocation, unindexed_allocation, committed_slot] ); } } @@ -1875,10 +2542,17 @@ mod reclaim_partition_tests { mod owner_get_holding_reclaim_tests { use super::{OwnerReclaimBacking, OwnerReclaimReason, reclaim_items, route_item}; use crate::client_kv_api::PutOptionalArgs; + use crate::config::KvSsdStorageConfig; + use crate::kv_ssd_storage::MIN_CAPACITY_BYTES; use crate::kvcore_test_lib::{ - integration_test_lock, start_master_and_client, stop_master_and_client, + integration_test_lock, start_master_and_client, start_master_and_client_with_client_config, + stop_master_and_client, }; + use crate::master_kv_router::msg_pack::{PutDoneReq, PutStartReq}; + use crate::master_kv_router::put::{handle_put_done, handle_put_start}; use crate::memholder::{MemholderManagerTrait, NodeHolderKey}; + use crate::p2p::msg_pack::MsgPack; + use crate::rpcresp_kvresult_convert::msg_and_error::OK; use std::time::{Duration, Instant}; #[limit_thirdparty::tokio::test(flavor = "multi_thread", worker_threads = 8)] @@ -1927,7 +2601,7 @@ mod owner_get_holding_reclaim_tests { .is_quiescent(key), "completed get must release its master key-activity lease" ); - let owner_node = owner_id.clone().into(); + let owner_node: crate::cluster_manager::NodeID = owner_id.clone().into(); let busy_item = route_item( &master_view, &owner_node, @@ -2001,6 +2675,183 @@ mod owner_get_holding_reclaim_tests { stop_master_and_client(master, client).await; } + + #[limit_thirdparty::tokio::test(flavor = "multi_thread", worker_threads = 8)] + async fn master_unindexed_allocation_reclaim_publishes_ssd_and_reloads_exact_bytes() { + let _test_guard = integration_test_lock().await; + let (master, client) = start_master_and_client_with_client_config( + "master_capacity_ssd_reclaim_master", + "master_capacity_ssd_reclaim_owner", + |config| { + config.ssd_storage = Some(KvSsdStorageConfig { + limit_bytes: MIN_CAPACITY_BYTES, + write_rate_limit_bytes_per_sec: None, + write_burst_bytes: None, + }); + let target = std::env::var("CARGO_TARGET_DIR") + .expect("SSD integration test requires the NVMe Cargo target"); + let root = format!( + "{target}/kv_ssd_integration/master_capacity_reclaim-{}", + std::process::id() + ); + config.share_mem_path = format!("{root}/sharemem"); + config.large_file_paths.paths = vec![format!("{root}/large")]; + }, + ) + .await; + let key = "master_capacity_ssd_reclaim_key"; + let payload = vec![0x5au8; 4096]; + let owner_view = client.client_kv_api_view(); + let owner_api = owner_view.client_kv_api(); + let owner_info = client + .cluster_manager_view() + .cluster_manager() + .get_self_info(); + let owner_id = owner_info.id; + let owner_node: crate::cluster_manager::NodeID = owner_id.clone().into(); + let master_view = master.master_kv_router_view().clone(); + assert!( + master_view + .cluster_manager() + .get_member_info_cached(&owner_id) + .and_then(|member| { + member + .metadata + .get(crate::cluster_manager::META_KEY_KV_SSD_STORAGE) + .cloned() + }) + .is_some_and(|value| value == "true"), + "master must observe the owner's SSD capability before selecting coordination" + ); + + let (_put_id, start) = handle_put_start( + master_view.clone(), + MsgPack { + serialize_part: PutStartReq { + key: key.to_string(), + len: payload.len() as u64, + reject_if_inflight_same_key: false, + reject_if_exist_same_key: false, + make_replica_task: true, + preferred_sub_cluster: None, + source_node_id: None, + }, + raw_bytes: Vec::new(), + }, + owner_node.clone(), + ) + .await; + assert_eq!( + start.serialize_part.error_code, OK, + "PutStart failed: {}", + start.serialize_part.error_json + ); + assert_eq!(start.serialize_part.node_id, owner_id); + owner_view + .client_seg_pool() + .copy_into_segment(start.serialize_part.target_addr, &payload) + .await + .expect("copy payload into the master-owned owner segment Allocation"); + let done = handle_put_done( + master_view.clone(), + MsgPack { + serialize_part: PutDoneReq { + key: key.to_string(), + put_id: start.serialize_part.put_id, + lease_id: None, + committed_slot: None, + publish_local_cache: false, + atomic_group: None, + }, + raw_bytes: Vec::new(), + }, + owner_node.clone(), + ) + .await; + assert_eq!(done.serialize_part.error_code, OK); + assert_eq!(done.serialize_part.local_cache_holder_id, None); + let route = master_view + .master_kv_router() + .inner() + .kv_routes + .get(key) + .map(|route| route.clone()) + .expect("PutDone must publish the production unindexed Allocation route"); + assert!( + route + .node_replicas + .read() + .get(&owner_node) + .and_then(|replicas| replicas.memory.as_ref()) + .is_some_and(|memory| !memory.owner_local_indexed), + "production remote backing must have no owner-local key index" + ); + drop(route); + + let item = route_item( + &master_view, + &owner_node, + key, + None, + None, + OwnerReclaimReason::MasterAllocationCapacity, + master_view.master_kv_router().next_owner_reclaim_epoch(), + ) + .expect("master-capacity victim must resolve to the current owner Allocation"); + assert!(matches!( + item.backing, + OwnerReclaimBacking::UnindexedAllocation { .. } + )); + assert_eq!( + reclaim_items(&master_view, &owner_node, vec![item]).await, + 1 + ); + + let route = master_view + .master_kv_router() + .inner() + .kv_routes + .get(key) + .map(|route| route.clone()) + .expect("SSD backing must keep the route alive after DRAM reclaim"); + { + let replicas = route.node_replicas.read(); + let owner_backings = replicas + .get(&owner_node) + .expect("the SSD-only owner route must remain"); + assert!(owner_backings.memory.is_none()); + assert_eq!( + owner_backings.ssd.as_ref().map(|ssd| ssd.len), + Some(payload.len() as u64) + ); + } + let persisted = owner_api + .inner() + .kv_ssd_storage_usage_snapshot() + .expect("test owner SSD must be configured"); + assert_eq!(persisted.persist_successes, 1); + assert_eq!(persisted.persist_failures, 0); + assert_eq!(persisted.used_bytes, payload.len() as u64); + + let (holder, _get_info) = owner_api + .inner() + .get(key) + .await + .expect("SSD-backed get") + .expect("SSD-only route must be readable"); + assert_eq!(holder.bytes(), payload); + drop(holder); + let loaded = owner_api + .inner() + .kv_ssd_storage_usage_snapshot() + .expect("test owner SSD must remain configured"); + assert_eq!(loaded.load_successes, 1); + assert_eq!(loaded.load_failures, 0); + assert_eq!(loaded.load_bytes, payload.len() as u64); + assert_eq!(loaded.memory_hits + loaded.disk_hits + loaded.outer_hits, 1); + + stop_master_and_client(master, client).await; + } } fn request_is_current(view: &MasterKvRouterView, request: &EvictionReclaimRequest) -> bool { @@ -2040,13 +2891,15 @@ fn request_is_current(view: &MasterKvRouterView, request: &EvictionReclaimReques return false; } route - .nodes_replicas + .node_replicas .read() .get(&owner) - .is_some_and(|replica| { - !replica.tomb_tag.is_tomb() - && replica.owner_local_indexed - && reclaim_backing_matches(replica, expected_backing) + .is_some_and(|node_replicas| { + !node_replicas.tomb_tag.is_tomb() + && node_replicas.memory.as_ref().is_some_and(|replica| { + replica.owner_local_indexed + && reclaim_backing_matches(replica, expected_backing) + }) }) }) } @@ -2196,96 +3049,105 @@ pub(crate) fn spawn_eviction_reclaim_actor( .eviction_reclaim_counters(&owner_node_id); let mut pending = std::collections::VecDeque::from(requests); let mut retry_requests = Vec::new(); - while let Some(request) = pending.pop_front() { - let (members, mut accounting_requests, reason) = match request.origin { - EvictionReclaimOrigin::OwnerCapacityEviction => ( - request.members.clone(), - vec![request], - OwnerReclaimReason::OwnerCapacityEviction, - ), - EvictionReclaimOrigin::MasterAllocationCapacity => { - let member = match plan_master_allocation_capacity_victim( - &view_task, - &request, - ) { - Ok(member) => member, - Err(MasterCapacityPlanError::CommittedSlot) => { - counters - .capacity_eviction_non_ring_b_entry_total - .fetch_add(1, Ordering::Relaxed); - counters - .capacity_eviction_hit_committed_slot - .fetch_add(1, Ordering::Relaxed); - view_task - .master_kv_router() - .complete_eviction_reclaim(&request); - let restored = restore_request_entries(&view_task, &request); - tracing::error!( - "BUG: master Allocation capacity event resolved to CommittedSlot; restored metadata: owner={} members={} restored={}", - owner_node_id, - request.members.len(), - restored, - ); - continue; - } - Err(MasterCapacityPlanError::RouteChanged) => { - view_task - .master_kv_router() - .complete_eviction_reclaim(&request); - counters.route_changed.fetch_add(1, Ordering::Relaxed); - continue; - } - Err(MasterCapacityPlanError::WrongRole) => { - counters - .capacity_eviction_non_ring_b_entry_total - .fetch_add(1, Ordering::Relaxed); - view_task - .master_kv_router() - .complete_eviction_reclaim(&request); - let restored = restore_request_entries(&view_task, &request); - tracing::error!( - "BUG: master Allocation Size event resolved to a non-ring-B route; restored metadata: owner={} members={} restored={}", - owner_node_id, - request.members.len(), - restored, - ); - continue; + while !pending.is_empty() { + let mut accounting_requests = Vec::with_capacity(OWNER_RECLAIM_RPC_BATCH); + let mut items = Vec::with_capacity(OWNER_RECLAIM_RPC_BATCH); + for _ in 0..OWNER_RECLAIM_RPC_BATCH { + let Some(request) = pending.pop_front() else { + break; + }; + let (members, reason) = match request.origin { + EvictionReclaimOrigin::OwnerCapacityEviction => ( + request.members.clone(), + OwnerReclaimReason::OwnerCapacityEviction, + ), + EvictionReclaimOrigin::MasterAllocationCapacity => { + let member = match plan_master_allocation_capacity_victim( + &view_task, + &request, + ) { + Ok(member) => member, + Err(MasterCapacityPlanError::CommittedSlot) => { + counters + .capacity_eviction_non_ring_b_entry_total + .fetch_add(1, Ordering::Relaxed); + counters + .capacity_eviction_hit_committed_slot + .fetch_add(1, Ordering::Relaxed); + view_task + .master_kv_router() + .complete_eviction_reclaim(&request); + let restored = + restore_request_entries(&view_task, &request); + tracing::error!( + "BUG: master Allocation capacity event resolved to CommittedSlot; restored metadata: owner={} members={} restored={}", + owner_node_id, + request.members.len(), + restored, + ); + continue; + } + Err(MasterCapacityPlanError::RouteChanged) => { + view_task + .master_kv_router() + .complete_eviction_reclaim(&request); + counters.route_changed.fetch_add(1, Ordering::Relaxed); + continue; + } + Err(MasterCapacityPlanError::WrongRole) => { + counters + .capacity_eviction_non_ring_b_entry_total + .fetch_add(1, Ordering::Relaxed); + view_task + .master_kv_router() + .complete_eviction_reclaim(&request); + let restored = + restore_request_entries(&view_task, &request); + tracing::error!( + "BUG: master Allocation Size event resolved to a non-ring-B route; restored metadata: owner={} members={} restored={}", + owner_node_id, + request.members.len(), + restored, + ); + continue; + } + }; + (vec![member], OwnerReclaimReason::MasterAllocationCapacity) + } + }; + + let planned = members + .iter() + .map(|member| { + let item = route_item( + &view_task, + &owner, + &member.key, + Some(member.desc.put_id), + None, + reason, + view_task.master_kv_router().next_owner_reclaim_epoch(), + )?; + if member + .expected_backing + .as_ref() + .is_some_and(|expected| expected != &item.backing) + { + return None; } - }; - ( - vec![member], - vec![request], - OwnerReclaimReason::MasterAllocationCapacity, - ) + Some(item) + }) + .collect::>>(); + if let Some(mut planned) = planned { + items.append(&mut planned); } - }; + accounting_requests.push(request); + } - let items = members - .iter() - .map(|member| { - let item = route_item( - &view_task, - &owner, - &member.key, - Some(member.desc.put_id), - None, - reason, - view_task.master_kv_router().next_owner_reclaim_epoch(), - )?; - if member - .expected_backing - .as_ref() - .is_some_and(|expected| expected != &item.backing) - { - return None; - } - Some(item) - }) - .collect::>>(); - if let Some(items) = items { - let _ = reclaim_single_victim(&view_task, &owner, items).await; + if !items.is_empty() { + let _ = reclaim_items(&view_task, &owner, items).await; } - for accounting_request in accounting_requests.drain(..) { + for accounting_request in accounting_requests { if request_is_current(&view_task, &accounting_request) { retry_requests.push(accounting_request); } else { @@ -2302,7 +3164,7 @@ pub(crate) fn spawn_eviction_reclaim_actor( let retry_count = retry_requests.len(); spawn_eviction_reclaim_retry(view_task.clone(), retry_requests); tracing::trace!( - "single-key eviction reclaim batch completed: owner={} retry_deferred={}", + "batched single-key eviction reclaim completed: owner={} retry_deferred={}", owner_node_id, retry_count, ); diff --git a/fluxon_rs/fluxon_kv/src/master_kv_router/route_maintenance.rs b/fluxon_rs/fluxon_kv/src/master_kv_router/route_maintenance.rs index 25edd27..04df8d5 100644 --- a/fluxon_rs/fluxon_kv/src/master_kv_router/route_maintenance.rs +++ b/fluxon_rs/fluxon_kv/src/master_kv_router/route_maintenance.rs @@ -105,7 +105,7 @@ pub(super) async fn apply_post_route_maintenance_batch( let event_is_current = inner.kv_routes.get(&event.key).is_some_and(|route| { route.put_id == event.put_id && route - .nodes_replicas + .node_replicas .read() .values() .any(|replica| !replica.tomb_tag.is_tomb()) diff --git a/fluxon_rs/fluxon_kv/src/master_seg_manager/mod.rs b/fluxon_rs/fluxon_kv/src/master_seg_manager/mod.rs index 627d361..45d7059 100644 --- a/fluxon_rs/fluxon_kv/src/master_seg_manager/mod.rs +++ b/fluxon_rs/fluxon_kv/src/master_seg_manager/mod.rs @@ -2,7 +2,9 @@ pub mod msg_pack; pub mod one_seg_allocator; use self::msg_pack::RequestSegmentRegistrationReq; use self::msg_pack::SegmentDeviceDescription; -use self::one_seg_allocator::{Allocation, OneSegAllocator}; +use self::one_seg_allocator::{ + Allocation, NodePoolCapacityBudget, NodePoolCapacitySnapshot, OneSegAllocator, +}; use crate::cluster_manager::NodeID; use crate::p2p::p2p_module::P2pModuleAccessTrait; use crate::rpcresp_kvresult_convert::msg_and_error::OK; @@ -22,6 +24,46 @@ use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::Duration; +fn build_node_segments_manager( + node_start_time: i64, + seg_map: std::collections::HashMap< + SegmentDeviceID, + (SegmentDeviceDescription, msg_pack::SegmentDeviceMemInfo), + >, +) -> KvResult { + let total_size = seg_map.values().try_fold(0u64, |total, (_, info)| { + total.checked_add(info.len).ok_or_else(|| { + KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::InvalidArgument { + detail: "registered node segment capacity overflows u64".to_string(), + }, + ) + }) + })?; + let capacity_budget = Arc::new(NodePoolCapacityBudget::new(total_size)?); + let mut device_id_2_allocator: HashMap> = HashMap::new(); + for (device_id, (seg_device_desc, seg_mem_info)) in seg_map { + let allocator = OneSegAllocator::new_with_capacity_budget( + device_id.clone(), + seg_device_desc, + seg_mem_info.addr, + seg_mem_info.len, + capacity_budget.clone(), + ) + .map_err(|e| { + tracing::error!("Failed to create OneSegAllocator: {}", e); + e + })?; + device_id_2_allocator.insert(device_id, Arc::new(allocator)); + } + Ok(NodeSegmentsManager::new( + node_start_time, + total_size, + device_id_2_allocator, + capacity_budget, + )) +} + // --- Handler Functions --- /// https://qcnoe3hd7k5c.feishu.cn/wiki/KkeXwBbP4iCRN8kWSDccP5GBnrd#share-AuMbdrSaXoadUbxRmUncooKnnQd fn register_node_segments( @@ -53,31 +95,7 @@ fn register_node_segments( match alloc_map.entry(node_id.clone()) { dashmap::mapref::entry::Entry::Vacant(v) => { - let mut total_size: u64 = 0; - let mut device_id_2_allocator: HashMap> = - HashMap::new(); - - for (device_id, (seg_device_desc, seg_mem_info)) in seg_map { - let allocator = OneSegAllocator::new( - device_id.clone(), - seg_device_desc, - seg_mem_info.addr, - seg_mem_info.len, - ) - .map_err(|e| { - tracing::error!("Failed to create OneSegAllocator: {}", e); - e - })?; - - total_size = total_size.saturating_add(seg_mem_info.len); - device_id_2_allocator.insert(device_id, Arc::new(allocator)); - } - - v.insert(NodeSegmentsManager::new( - node_start_time, - total_size, - device_id_2_allocator, - )); + v.insert(build_node_segments_manager(node_start_time, seg_map)?); } dashmap::mapref::entry::Entry::Occupied(mut occ) => { let node_segments_manager = occ.get_mut(); @@ -96,28 +114,7 @@ fn register_node_segments( }, )); } - let mut total_size: u64 = 0; - let mut device_id_2_allocator: HashMap> = - HashMap::new(); - - for (device_id, (seg_device_desc, seg_mem_info)) in seg_map { - let allocator = OneSegAllocator::new( - device_id.clone(), - seg_device_desc, - seg_mem_info.addr, - seg_mem_info.len, - ) - .map_err(|e| { - tracing::error!("Failed to create OneSegAllocator: {}", e); - e - })?; - - total_size = total_size.saturating_add(seg_mem_info.len); - device_id_2_allocator.insert(device_id, Arc::new(allocator)); - } - - *node_segments_manager = - NodeSegmentsManager::new(node_start_time, total_size, device_id_2_allocator); + *node_segments_manager = build_node_segments_manager(node_start_time, seg_map)?; tracing::info!("RegisterSegment replaced tombed node: {}", node_id); return Ok(()); } @@ -154,23 +151,38 @@ fn register_node_segments( )); } - let allocator = OneSegAllocator::new( + let new_total_size = node_segments_manager + .total_size + .checked_add(seg_mem_info.len) + .ok_or_else(|| { + KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::InvalidArgument { + detail: format!( + "registered node segment capacity overflows u64: node={}", + node_id + ), + }, + ) + })?; + let allocator = OneSegAllocator::new_with_capacity_budget( device_id.clone(), seg_device_desc, seg_mem_info.addr, seg_mem_info.len, + node_segments_manager.capacity_budget.clone(), ) .map_err(|e| { tracing::error!("Failed to create OneSegAllocator: {}", e); e })?; + node_segments_manager + .capacity_budget + .extend_physical_capacity(seg_mem_info.len)?; node_segments_manager .device_id_2_allocator .insert(device_id, Arc::new(allocator)); - node_segments_manager.total_size = node_segments_manager - .total_size - .saturating_add(seg_mem_info.len); + node_segments_manager.total_size = new_total_size; } } } @@ -221,19 +233,22 @@ pub struct NodeSegmentsManager { node_start_time: i64, total_size: u64, device_id_2_allocator: HashMap>, + capacity_budget: Arc, tomb_tag: NodeTombTag, } impl NodeSegmentsManager { - pub fn new( + fn new( node_start_time: i64, total_size: u64, device_id_2_allocator: HashMap>, + capacity_budget: Arc, ) -> Self { Self { node_start_time, total_size, device_id_2_allocator, + capacity_budget, tomb_tag: NodeTombTag::new(), } } @@ -513,7 +528,7 @@ impl MasterSegManager { Ok(()) } - pub fn get_node_space_size(&self, node_id: &str) -> u64 { + pub fn get_node_physical_space_size(&self, node_id: &str) -> u64 { self.inner() .node_allocators_and_tomb_tag .get(node_id) @@ -521,4 +536,109 @@ impl MasterSegManager { .map(|node_segments_manager| node_segments_manager.total_size) .unwrap_or(0) } + + pub fn get_node_active_space_size(&self, node_id: &str) -> u64 { + self.get_node_pool_capacity(node_id) + .map(|(_, snapshot)| snapshot.active_capacity_bytes) + .unwrap_or(0) + } + + /// Return the exact live node generation and its shared active/parked capacity state. + pub fn get_node_pool_capacity(&self, node_id: &str) -> Option<(i64, NodePoolCapacitySnapshot)> { + let node = self.inner().node_allocators_and_tomb_tag.get(node_id)?; + if node.tomb_tag.is_tomb() { + return None; + } + Some((node.node_start_time, node.capacity_budget.snapshot())) + } + + /// Update one live node generation with optimistic epoch fencing. + pub fn set_node_active_capacity( + &self, + node_id: &NodeID, + expected_node_start_time: i64, + expected_capacity_epoch: u64, + active_capacity_bytes: u64, + ) -> KvResult { + let node = self + .inner() + .node_allocators_and_tomb_tag + .get(node_id) + .ok_or_else(|| { + KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::NodeNotFound { + desc: node_id.to_string(), + }, + ) + })?; + if node.tomb_tag.is_tomb() { + return Err(KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::NodeNotFound { + desc: format!("{} (departed generation)", node_id), + }, + )); + } + if node.node_start_time != expected_node_start_time { + return Err(KvError::Api( + crate::rpcresp_kvresult_convert::msg_and_error::ApiError::OwnerStartTimeMismatch { + expected: expected_node_start_time, + got: node.node_start_time, + }, + )); + } + node.capacity_budget + .set_active_capacity(expected_capacity_epoch, active_capacity_bytes) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::master_seg_manager::msg_pack::SegmentDeviceMemInfo; + + #[test] + fn one_node_generation_shares_one_budget_across_registered_segments() { + let manager = build_node_segments_manager( + 17, + HashMap::from([ + ( + "cpu0".to_string(), + ( + SegmentDeviceDescription::Cpu, + SegmentDeviceMemInfo { + addr: 0, + len: 8 * 1024, + }, + ), + ), + ( + "cpu1".to_string(), + ( + SegmentDeviceDescription::Cpu, + SegmentDeviceMemInfo { + addr: 8 * 1024, + len: 8 * 1024, + }, + ), + ), + ]), + ) + .unwrap(); + let initial = manager.capacity_budget.snapshot(); + assert_eq!(initial.physical_capacity_bytes, 16 * 1024); + assert_eq!(initial.active_capacity_bytes, 16 * 1024); + + let allocators = manager + .device_id_2_allocator + .values() + .cloned() + .collect::>(); + let _first = allocators[0].allocate(8 * 1024).unwrap(); + let _second = allocators[1].allocate(8 * 1024).unwrap(); + assert_eq!( + manager.capacity_budget.snapshot().used_capacity_bytes, + 16 * 1024 + ); + assert!(allocators[0].allocate(1).is_err()); + } } diff --git a/fluxon_rs/fluxon_kv/src/master_seg_manager/one_seg_allocator.rs b/fluxon_rs/fluxon_kv/src/master_seg_manager/one_seg_allocator.rs index 18eaf66..817e278 100755 --- a/fluxon_rs/fluxon_kv/src/master_seg_manager/one_seg_allocator.rs +++ b/fluxon_rs/fluxon_kv/src/master_seg_manager/one_seg_allocator.rs @@ -1,10 +1,209 @@ use fluxon_util::vallocator::VirtualAllocator; +use parking_lot::Mutex; -use crate::rpcresp_kvresult_convert::msg_and_error::KvResult; +use crate::rpcresp_kvresult_convert::msg_and_error::{ApiError, KvError, KvResult}; use std::sync::Arc; use super::msg_pack::{SegmentDeviceDescription, SegmentDeviceID}; +/// Runtime capacity state shared by every segment registered by one node generation. +/// +/// Physical capacity describes the already allocated and registered memory. Active capacity is +/// the allocation budget currently exposed to Fluxon; the remainder is parked without changing +/// the underlying mapping or registration. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct NodePoolCapacitySnapshot { + pub physical_capacity_bytes: u64, + pub active_capacity_bytes: u64, + pub used_capacity_bytes: u64, + pub parked_capacity_bytes: u64, + pub draining_capacity_bytes: u64, + pub available_capacity_bytes: u64, + pub capacity_epoch: u64, +} + +#[derive(Debug)] +struct NodePoolCapacityState { + physical_capacity_bytes: u64, + active_capacity_bytes: u64, + used_capacity_bytes: u64, + capacity_epoch: u64, +} + +/// One generation-scoped allocation budget shared by all of a node's segment allocators. +#[derive(Debug)] +pub(crate) struct NodePoolCapacityBudget { + state: Mutex, +} + +impl NodePoolCapacityBudget { + pub(crate) fn new(physical_capacity_bytes: u64) -> KvResult { + if physical_capacity_bytes == 0 { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: "node pool physical capacity must be greater than zero".to_string(), + })); + } + Ok(Self { + state: Mutex::new(NodePoolCapacityState { + physical_capacity_bytes, + active_capacity_bytes: physical_capacity_bytes, + used_capacity_bytes: 0, + capacity_epoch: 1, + }), + }) + } + + fn snapshot_locked(state: &NodePoolCapacityState) -> NodePoolCapacitySnapshot { + NodePoolCapacitySnapshot { + physical_capacity_bytes: state.physical_capacity_bytes, + active_capacity_bytes: state.active_capacity_bytes, + used_capacity_bytes: state.used_capacity_bytes, + parked_capacity_bytes: state + .physical_capacity_bytes + .saturating_sub(state.active_capacity_bytes), + draining_capacity_bytes: state + .used_capacity_bytes + .saturating_sub(state.active_capacity_bytes), + available_capacity_bytes: state + .active_capacity_bytes + .saturating_sub(state.used_capacity_bytes), + capacity_epoch: state.capacity_epoch, + } + } + + pub(crate) fn snapshot(&self) -> NodePoolCapacitySnapshot { + Self::snapshot_locked(&self.state.lock()) + } + + /// Change only the active allocation budget. Existing allocations above a lower target are + /// accounted as draining bytes and remain valid until the normal single-KV reclaim path drops + /// them. + pub(crate) fn set_active_capacity( + &self, + expected_capacity_epoch: u64, + active_capacity_bytes: u64, + ) -> KvResult { + let mut state = self.state.lock(); + if state.capacity_epoch != expected_capacity_epoch { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "stale node pool capacity epoch: expected={} current={}", + expected_capacity_epoch, state.capacity_epoch + ), + })); + } + if active_capacity_bytes == 0 || active_capacity_bytes > state.physical_capacity_bytes { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: format!( + "active capacity must be in 1..={}: got {}", + state.physical_capacity_bytes, active_capacity_bytes + ), + })); + } + if state.active_capacity_bytes != active_capacity_bytes { + state.active_capacity_bytes = active_capacity_bytes; + state.capacity_epoch = state + .capacity_epoch + .checked_add(1) + .expect("node pool capacity epoch overflow"); + } + Ok(Self::snapshot_locked(&state)) + } + + /// Extend a live generation when it registers an additional segment. A fully active pool + /// grows with its physical mapping; an already parked pool preserves its active byte target. + pub(crate) fn extend_physical_capacity(&self, additional_bytes: u64) -> KvResult<()> { + if additional_bytes == 0 { + return Err(KvError::Api(ApiError::InvalidArgument { + detail: "additional physical capacity must be greater than zero".to_string(), + })); + } + let mut state = self.state.lock(); + let was_fully_active = state.active_capacity_bytes == state.physical_capacity_bytes; + state.physical_capacity_bytes = state + .physical_capacity_bytes + .checked_add(additional_bytes) + .ok_or_else(|| { + KvError::Api(ApiError::InvalidArgument { + detail: "node pool physical capacity overflow".to_string(), + }) + })?; + if was_fully_active { + state.active_capacity_bytes = state.physical_capacity_bytes; + } + state.capacity_epoch = state + .capacity_epoch + .checked_add(1) + .expect("node pool capacity epoch overflow"); + Ok(()) + } + + fn allocate(&self, allocator: &VirtualAllocator, size: u64) -> KvResult<(u64, u64)> { + // The budget lock spans the physical allocator mutation. Capacity changes and allocations + // therefore have one total order; a resize cannot be bypassed by a stale pre-check. + let mut state = self.state.lock(); + if size + > state + .active_capacity_bytes + .saturating_sub(state.used_capacity_bytes) + { + return Err(KvError::Api(ApiError::Allocator { + detail: format!( + "node pool active capacity exhausted: requested={} active={} used={} epoch={}", + size, + state.active_capacity_bytes, + state.used_capacity_bytes, + state.capacity_epoch + ), + })); + } + let region = allocator.alloc(size)?; + let Some(next_used) = state.used_capacity_bytes.checked_add(region.size) else { + let _ = allocator.free(region.start_addr, region.size); + return Err(KvError::Api(ApiError::Allocator { + detail: "node pool used capacity overflow".to_string(), + })); + }; + if next_used > state.active_capacity_bytes { + // VirtualAllocator rounds allocations to its alignment. Roll the physical mutation + // back when the aligned size crosses the active byte boundary. + let _ = allocator.free(region.start_addr, region.size); + return Err(KvError::Api(ApiError::Allocator { + detail: format!( + "node pool active capacity exhausted after alignment: requested={} aligned={} active={} used={} epoch={}", + size, + region.size, + state.active_capacity_bytes, + state.used_capacity_bytes, + state.capacity_epoch + ), + })); + } + state.used_capacity_bytes = next_used; + Ok((region.start_addr, region.size)) + } + + fn free(&self, allocator: &VirtualAllocator, addr: u64, capacity: u64) { + let mut state = self.state.lock(); + match allocator.free(addr, capacity) { + Ok(freed) => { + state.used_capacity_bytes = state + .used_capacity_bytes + .checked_sub(freed) + .expect("node pool used capacity underflow"); + } + Err(err) => { + tracing::error!( + addr, + capacity, + error = %err, + "failed to free segment allocation; preserving node pool used accounting" + ); + } + } + } +} + /// An RAII guard for a memory allocation from a `OneSegAllocator`. /// /// When this guard is dropped, it attempts to free the memory block @@ -108,6 +307,7 @@ pub struct OneSegAllocator { pub seg_device_desc: SegmentDeviceDescription, pub base_addr: u64, inner: VirtualAllocator, + capacity_budget: Arc, } impl OneSegAllocator { @@ -117,6 +317,23 @@ impl OneSegAllocator { seg_device_desc: SegmentDeviceDescription, base_addr: u64, size: u64, + ) -> KvResult { + let capacity_budget = Arc::new(NodePoolCapacityBudget::new(size)?); + Self::new_with_capacity_budget( + seg_device_id, + seg_device_desc, + base_addr, + size, + capacity_budget, + ) + } + + pub(crate) fn new_with_capacity_budget( + seg_device_id: SegmentDeviceID, + seg_device_desc: SegmentDeviceDescription, + base_addr: u64, + size: u64, + capacity_budget: Arc, ) -> KvResult { let inner = VirtualAllocator::new(size as u64)?; Ok(Self { @@ -124,18 +341,19 @@ impl OneSegAllocator { seg_device_desc, base_addr, inner, + capacity_budget, }) } /// Allocates a block of memory of `size` bytes. /// Returns an RAII guard for the allocation. pub fn allocate(self: &Arc, size: u64) -> KvResult { - let region = self.inner.alloc(size as u64)?; + let (start_addr, capacity) = self.capacity_budget.allocate(&self.inner, size)?; // return base0 offset in addr (pure offset); base address is carried separately Ok(Allocation::new( - region.start_addr, + start_addr, size, - region.size, + capacity, Arc::clone(self), )) } @@ -143,7 +361,7 @@ impl OneSegAllocator { /// Frees a block of memory. fn free(&self, addr: u64, capcity: u64) { // addr is offset (base0); free directly - let _ = self.inner.free(addr, capcity as u64); + self.capacity_budget.free(&self.inner, addr, capcity); } /// Returns total capacity (bytes) of this segment. @@ -155,4 +373,82 @@ impl OneSegAllocator { pub fn used_size_bytes(&self) -> u64 { self.inner.get_allocated_size() as u64 } + + /// Returns the active/parked capacity state shared by this node generation. + pub fn node_pool_capacity_snapshot(&self) -> NodePoolCapacitySnapshot { + self.capacity_budget.snapshot() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn allocator_with_budget( + id: &str, + size: u64, + budget: Arc, + ) -> Arc { + Arc::new( + OneSegAllocator::new_with_capacity_budget( + id.to_string(), + SegmentDeviceDescription::Cpu, + 0, + size, + budget, + ) + .unwrap(), + ) + } + + #[test] + fn shrinking_below_used_blocks_new_allocations_until_normal_drop_drains() { + let budget = Arc::new(NodePoolCapacityBudget::new(16 * 1024).unwrap()); + let allocator = allocator_with_budget("cpu", 16 * 1024, budget.clone()); + let first = allocator.allocate(8 * 1024).unwrap(); + + let shrinking = budget.set_active_capacity(1, 4 * 1024).unwrap(); + assert_eq!(shrinking.capacity_epoch, 2); + assert_eq!(shrinking.draining_capacity_bytes, 4 * 1024); + assert!(allocator.allocate(1).is_err()); + + drop(first); + let drained = budget.snapshot(); + assert_eq!(drained.used_capacity_bytes, 0); + assert_eq!(drained.draining_capacity_bytes, 0); + assert!(allocator.allocate(4 * 1024).is_ok()); + } + + #[test] + fn shared_node_budget_limits_allocations_across_segments_and_expands_immediately() { + let budget = Arc::new(NodePoolCapacityBudget::new(16 * 1024).unwrap()); + let first_allocator = allocator_with_budget("cpu0", 8 * 1024, budget.clone()); + let second_allocator = allocator_with_budget("cpu1", 8 * 1024, budget.clone()); + let first = first_allocator.allocate(8 * 1024).unwrap(); + let _second = second_allocator.allocate(8 * 1024).unwrap(); + assert!(first_allocator.allocate(1).is_err()); + + drop(first); + budget.set_active_capacity(1, 12 * 1024).unwrap(); + assert!(first_allocator.allocate(4 * 1024).is_ok()); + assert!(second_allocator.allocate(1).is_err()); + + let expanded = budget.set_active_capacity(2, 16 * 1024).unwrap(); + assert_eq!(expanded.capacity_epoch, 3); + assert!(first_allocator.allocate(4 * 1024).is_ok()); + } + + #[test] + fn stale_epoch_and_out_of_physical_range_updates_are_rejected() { + let budget = NodePoolCapacityBudget::new(16 * 1024).unwrap(); + assert!(budget.set_active_capacity(0, 8 * 1024).is_err()); + assert!(budget.set_active_capacity(1, 0).is_err()); + assert!(budget.set_active_capacity(1, 32 * 1024).is_err()); + assert_eq!(budget.snapshot().capacity_epoch, 1); + + let updated = budget.set_active_capacity(1, 8 * 1024).unwrap(); + assert_eq!(updated.capacity_epoch, 2); + assert!(budget.set_active_capacity(1, 4 * 1024).is_err()); + assert_eq!(budget.snapshot().active_capacity_bytes, 8 * 1024); + } } diff --git a/fluxon_rs/fluxon_kv/src/memholder/lifetime.rs b/fluxon_rs/fluxon_kv/src/memholder/lifetime.rs index 92a559b..1ea89ec 100755 --- a/fluxon_rs/fluxon_kv/src/memholder/lifetime.rs +++ b/fluxon_rs/fluxon_kv/src/memholder/lifetime.rs @@ -433,8 +433,8 @@ impl MemholderManagerTrait for MasterOwnerMemMgr { }; let mut targets = Vec::new(); - let nodes_replicas = nodes_kv_route_info.nodes_replicas.read(); - for (node_id, kv_route_info) in nodes_replicas.iter() { + let node_replicas = nodes_kv_route_info.node_replicas.read(); + for (node_id, kv_route_info) in node_replicas.iter() { if kv_route_info.tomb_tag.is_tomb() { continue; } @@ -476,8 +476,8 @@ impl MemholderManagerTrait for MasterOwnerMemMgr { continue; }; - let nodes_replicas = nodes_kv_route_info.nodes_replicas.read(); - let Some(kv_route_info) = nodes_replicas.get(target.node_id.as_str()) else { + let node_replicas = nodes_kv_route_info.node_replicas.read(); + let Some(kv_route_info) = node_replicas.get(target.node_id.as_str()) else { continue; }; if kv_route_info.tomb_tag.is_tomb() { diff --git a/fluxon_rs/fluxon_kv/src/memholder/memholder_test.rs b/fluxon_rs/fluxon_kv/src/memholder/memholder_test.rs index eee9dc0..07fdf7b 100644 --- a/fluxon_rs/fluxon_kv/src/memholder/memholder_test.rs +++ b/fluxon_rs/fluxon_kv/src/memholder/memholder_test.rs @@ -105,6 +105,7 @@ fn new_client_config_with_size( large_file_paths: crate::config::LargeFilePaths { paths: vec![format!("/tmp/kvcache_large/{}", instance_key)], }, + ssd_storage: None, test_spec_config: TestSpecConfig::default(), } } @@ -139,6 +140,7 @@ fn new_zero_contribution_client_config( }, share_mem_path: format!("/tmp/kvcache_shared_memory/{}", owner_instance_key), large_file_paths: crate::config::LargeFilePaths { paths: Vec::new() }, + ssd_storage: None, test_spec_config: TestSpecConfig::default(), } } @@ -197,7 +199,7 @@ fn evict_all_replicas_for_key(master_view: &MasterKvRouterView, key: &str) -> us .get(key) .map(|route| { let node_ids = route - .nodes_replicas + .node_replicas .read() .keys() .cloned() diff --git a/fluxon_rs/fluxon_kv/src/memholder/mod.rs b/fluxon_rs/fluxon_kv/src/memholder/mod.rs index f23c88a..55cb437 100755 --- a/fluxon_rs/fluxon_kv/src/memholder/mod.rs +++ b/fluxon_rs/fluxon_kv/src/memholder/mod.rs @@ -305,30 +305,39 @@ impl Drop for MemoryInfo { grant_id, slot_index, } => { - let spawn_view = self.view.clone(); - let release_view = self.view.clone(); - let key = self.key.clone(); - let slot_size = *slot_size; - let grant_id = *grant_id; - let slot_index = *slot_index; - let _ = spawn_view.spawn("resident_local_reserve_slot_release", async move { - if let Err(err) = release_view - .client_kv_api() - .inner() - .owner_release_local_reserve_resident_slot_holder( - slot_size, grant_id, slot_index, - ) - { - tracing::warn!( - "failed to release resident local reserve slot holder on MemoryInfo drop: key={} slot_size={} grant_id={} slot_index={} err={}", - key, - slot_size, - grant_id, - slot_index, - err - ); - } - }); + let Some(_view_guard) = self.view.try_upgrade() else { + tracing::debug!( + key = self.key, + "skipping resident local reserve slot release after view drop" + ); + return; + }; + if !self.view.register_shutdown_poller().is_running() { + tracing::debug!( + key = self.key, + "skipping resident local reserve slot release during shutdown" + ); + return; + } + if let Err(err) = self + .view + .client_kv_api() + .inner() + .owner_release_local_reserve_resident_slot_holder( + *slot_size, + *grant_id, + *slot_index, + ) + { + tracing::warn!( + "failed to release resident local reserve slot holder on MemoryInfo drop: key={} slot_size={} grant_id={} slot_index={} err={}", + self.key, + slot_size, + grant_id, + slot_index, + err + ); + } } } } diff --git a/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/msg_and_error.rs b/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/msg_and_error.rs index 91558b6..d9d24a8 100644 --- a/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/msg_and_error.rs +++ b/fluxon_rs/fluxon_kv/src/rpcresp_kvresult_convert/msg_and_error.rs @@ -87,6 +87,12 @@ pub enum MsgId { BatchGetPlanResp = 3072, BatchGetBindReq = 3073, BatchGetBindResp = 3074, + BatchPublishOwnerSsdReq = 3075, + BatchPublishOwnerSsdResp = 3076, + SsdStageBeginReq = 3077, + SsdStageBeginResp = 3078, + SsdStageDoneReq = 3079, + SsdStageDoneResp = 3080, ExternalGetReq = 4001, ExternalGetResp = 4002, ExternalPutStartReq = 4003, diff --git a/fluxon_rs/fluxon_pyo3/src/lib.rs b/fluxon_rs/fluxon_pyo3/src/lib.rs index a6453dc..0165f9f 100644 --- a/fluxon_rs/fluxon_pyo3/src/lib.rs +++ b/fluxon_rs/fluxon_pyo3/src/lib.rs @@ -60,7 +60,9 @@ use fluxon_util::{ FluxonCliProxyDescriptorV2, FluxonCliProxyTransportV2, fluxon_cli_proxy_desc_etcd_key_v2, }; use futures::Future; -use pyo3::exceptions::{PyOSError, PyPermissionError, PyRuntimeError, PyValueError}; +use pyo3::exceptions::{ + PyKeyboardInterrupt, PyOSError, PyPermissionError, PyRuntimeError, PyValueError, +}; use pyo3::prelude::*; use pyo3::pybacked::PyBackedBytes; use pyo3::types::{PyAny, PyBytes, PyDict, PyList, PyModule, PyString, PyTuple}; @@ -4216,6 +4218,10 @@ impl KvClient { len: owner_data.value_len, }, make_replica_task: *make_replica_task, + // This owner-local path has no earlier remote + // reservation. Selected items are admitted to + // run append Start, where allocation occurs. + remote_replica_admitted: *make_replica_task, preferred_sub_cluster: None, atomic_group: atomic_groups[idx].clone(), }); @@ -7756,7 +7762,7 @@ impl Drop for KvMaster { /// This function creates a master, runs it until Ctrl+C, then shuts down #[pyfunction] #[pyo3(signature = (config=None))] -fn run_master_blocking(config: Option<&Bound<'_, PyAny>>, py: Python) -> PyObject { +fn run_master_blocking(config: Option<&Bound<'_, PyAny>>, py: Python) -> PyResult { fn run_master_inner(config: Option<&Bound<'_, PyAny>>, py: Python) -> ApiResult { // Debug config println!("🛠️ Master init configuration: {:?}", config); @@ -7878,7 +7884,20 @@ fn run_master_blocking(config: Option<&Bound<'_, PyAny>>, py: Python) -> PyObjec out } - run_master_inner(config, py).into_py_object(py) + let result = run_master_inner(config, py); + // The same SIGINT wakes Tokio's ctrl_c future and becomes a pending Python + // KeyboardInterrupt while the GIL is released. Once the framework has + // completed its graceful shutdown, consume only that expected interrupt + // before constructing the Python Result object. Other Python exceptions + // remain visible to the caller. + if let Err(err) = py.check_signals() { + if err.is_instance_of::(py) { + tracing::debug!("consumed KeyboardInterrupt after graceful KV master shutdown"); + } else { + return Err(err); + } + } + Ok(result.into_py_object(py)) } /// Python module definition diff --git a/setup_and_pack/rather_no_git_submodule.yaml b/setup_and_pack/rather_no_git_submodule.yaml index 9f00b04..453a0e3 100644 --- a/setup_and_pack/rather_no_git_submodule.yaml +++ b/setup_and_pack/rather_no_git_submodule.yaml @@ -1,4 +1,4 @@ modules: - path: fluxon_rs/moka repo: https://github.com/ActivePeter/moka - checkout: main + checkout: 91c97076e7b1bbac306d7ace7b74f9e994440b2d

OP9+0Quu7<4!E27jqn`i6X1oyo7Z2Q@DCvnX47Xd2cE!uvFeEVD!8+Y z-p|J>zuBpN1p@WW0qgqv32y7EcXSe-$GpvYTDcnLVerY_^nM1c7yEyC2P|TNk!VoG zd>lM9Oz+4EPhvg`p2d8jaO+mBt-lz`8Z?ONp%>T)PhegFPiMXl?qPl$UIK5be-42f z)}ZSLv_i(k`hYGM9_-2HM&#RA{+;k>-NnEEfk2`jFrI>EFnd z7w`W!us{_Wgoo=hJ_3(n{x>|C`Gv)_a@EZ3@LK6j>o1P|RS1Oi)C=DXPi1}=Je_$4 zJd3#rFKXdd{Z|mEY!Q&x-`ns2^HO;DCHg>jz#YsFz^j>`D#rf5kp)6Nq@@e(r5Csu z9?AR)cs%p}!JW*L;TgTy{{KD%GFgKs;JM6SfR{1Phet-}6Zin0q+A{UFH`{)kn1lV z-@_}I*TEZ@|Dy_Asu%9OfmU=5bF(i3YgmAOT0uN3G9QinkluQMN$?ov55v=$yUE4- z|19t-8k94C2j0N^Q+RYAeL$7)6y`s}^DI~EFP8c=0u`*m`5)2J1(?%sI*4yh*!99! zBEO3HD0p<=7WuONcmz^f285@0GhYYKCvU#~Higm+)XKdII@Qk>9-j;%q;MfSYyH{`nrM|F~R?f}x`@q+jEHDg# z3g$P#YnZ3PqXz2}m;p~^{;cqp18q9~`Dl>M8mxz}VeW-{nSTebVSX6ipu1_D6@iu` zvhKU$e=h!%mM(0FKC^*v2lH#;$;`*WGnn6Fx!C__v%q6$;Aj3E+~Lp%lm~Y+e-EC| zd^5aMdei!g8Sh4*iZ!T(hYr;X|0O)w%60#YRxXa^4}hn(aI5|`2+U~_kcVL`Je&Cx z_!{Oecop*n@J_?@2`u{z`~PSbSc?XenU}$9neT!Jm>+^CT%{L215dfi)B~ZP)6&gh z4SK-~m=A_mFuxw|XPyENi9ua;{2xTXrUG*P#p7vsH1n6>iOlI6(Cv*B<{u&7$=v)3 zfeaS-5uVNbIJ|`UIe0Deu4S~M0p^#Jn?~Aj{Sd^WK{oTT@Lc9o;jvfi{mc{|?CMyI z{8TGnt-o06w-A`aIx2yCn12l~V7?Dt%=`qrs-;`?H_;L`vxDJK(9Bi~9Q!$j}0Y@jKkZysej(&d0nvyqW=0pm10<7TaaasD=1p(5tt@Tgn#{43$f z%tu)+_WxxpFdhx!$LJlU!K26O{v_NOr~4v!9`lv(YUxeuFOGUK0*+htj<&&*nD2$V zm>-4bFmHsHws5QdMdh@l)hz<@`s)X8U_Kn~zD*x!B0Pur-S9l-kCbEoU%~?O(7?-_ ze)U59Dqyl+_+8}Nn12S3Wxf-hl5FZ7`4Mok27kb_n78{9CnNKo@CxS9aKCbO{I5eG zWV}A0+u=6m_roKYXTqbHzbHJ|4bA)j4U$-ct?@QF0LisjNXhJUvD4XgxfKxffo@ zd=I?3rOW!iB2aOsUZ4RUK0)`6U(*W3Fz*ddWj++1#XLc{sNddL!vYi0pq%-1c+y0D zKy%@#%;}d<+8cSyS0lf0BHRCOM8L-yd;_m%UIULv)d%!DJdSzW3R=08CdcvbjzDHp zKpYqGh=OM^zZULceyi|cm)T>;&u95rCIY1_unb|97%L0vfoPPlT^wJ{|65J{Mlc z+yf7p%=Z7Q5r`InmXD3X|Nqh%#y;dHvHTNo7jyc7BJuaeW~bxdZ3it~VROK$-ydGa z{2F)#^CaQH2I@k-pXJZrA@=|B4%o;7xo8kRMPG?`;8Dy=;YG~1!)ut=!0SyG_#FYq zRK0N9N*ZVq^X|ff&G;JRPiFaJ;cj@-^*0rPI@Vw&+wX|6jxc*P%f<^V{Km=J&%xrs)&N6dr5> z`N)rw`AzFDPQ&#G#IcUN@EqoQ;C|+{@Q{1;0sRSgwQ#F``)_IK+${p~`ip?)Fdrg3 z*v#%g{u-8lKfIKA=C|1Y`&r;cG^l6(2Hdz$pV^1-PRz^U(ae8Y!u%vWjd>d%t&od(7`bT_vcLc|@G&0=54~TX!8mvrb0<8O`7F58a<%?q zsTU%U!5X{<_b@Ml=QG~|uVB6hUfa@T{a+CXe?XsE13Za&$KAA~smy!B)0hv1XERR_ zF6xW@ISWiggHq_N8w|5OBmoxS_fAd+P%( zNMU|6+{yedcn0$f_#EaYJWqJ@`irCZ3Iau}!Q1dM=B2`eU9L6A_p|(y@cL#){qJds zLNfHF>k5xzemUI3JQm)-d@MZjVZHyU-(&xu!U8kVz|A}hUc`Jk+{=6&yo&iIc%8`t zJ_H(={{oMAM4!Q*@F?c(_tJ_cGpAov6feQxO~-!-8sxJEH^7US-w7{eo(?Z({tUcM zchh(ofliO=GkXi}U|s@GV*WKegZV!A8s;Y~7yJJT7BGIGrK@G$4Ibgr2ijkFu&dxE z-*f~DS%bN7A9D}fHd7zaYIrR3jqsEfZq@$=0cVSV7>`i{&t(2P zJezsjYFfE`=H20y%%iHY{|~UhwP+CYm_D;x;i=50!PA+~hI^Sm5099|_WvtXfmwRt z_u+2lUU)w9@8G4(kH9OGtKu@*o_3&KgTgk=#p9QMWpq%*;cs29C;Q{8I_tDCQJg%=qKjFGfz3&KleSk751*Jem1Z@C@cT@a&c@>%WP>nwA0K8{l5%U&3pcSHq7p{|(;A z{6FEMzSz4xp)XOFpJ?eKm`B1>nU8?aWIt_0cOlTg8Z3Z^J*f|L89bKx zT6hZcGPtM7ar}27P|_3->n|RM;8o1e!0VZZ*5IVe)CbxN9?yKRi9j|BTra%&ETzH7 z|8*k2kmWxHFK3@L3TDnZu z;1alp`5<^9^LThE^E=>`nv41mAW*9X4C5(y19STITk&tZJgu+Lo5;5_-vEze{-t!e z|97)MH5%kG{|#Qu{6BaF^DYNyMg7bp;bG6P{r?CAszspXV+_2W`4o8S96jF!cQIc8 z&uex%{>u<3Y7SWS*TKEaH^Up4?}6Lq>H|6qk7NG#0k!{UfzChE(z%)UgXc288eYVF z4BX3nDm>nNRv+nO2&6J!C_LEx;BDk*viwir#mv8f*TS2wzn>5YV>_Y~@D%3f;OWe} z`f256Grt_3ue)i)BG9M@jIr==x4uGC;Ze+I!jqY2!DlmHZn@b1ht1OqtV06_^G)zl z=012W^Iza$^Y#A!geOXGT7PlAw?9Zrm%$oD2oHAbuSI?_%O3}?W_}Mm(88_yk0B7g zKp*LI@EGQK@Ob9$!IPM8hRS;IYr^ z13d#zWNwE35`5_f2$xHjo2_?r4cyCoEIj-LJ%0*3Z;|egl8fK}e^C$2LxUvdufi*t zzXOlS(fj#SCk`7;9XRsicS{&O1cWPW}vtxy4T`d#q$hL`!3$oIE& zS$`A)jV%Mh$HOCD)@POmk7oWPJdXJycq;Ri!bN@YQ7aZGMuXYRx53@a_rj~0AB6{) zH^Rdgv;F@?ztWP%FV<(=5AI_=93JJ-^W`t32fJfFsQPcp$MJs}0e4e?j{i&WLgoeV z66PPleaydt*D(LlM4*lZj>AKi=rcP9w=?g0m{u;1`Q`9r=CN=y>H&z3It{|PMcJQ}1jUja{J{ysd1xmS3w75W+ZYeatY z`im3(6av+(qx0%$=|Yz4Gwu$b%zOYmAy3c0242|gRDUc2$*<`Rrof%dUGQ?|3*gnv zm%(e9udOp_X0{c2;W9LcV7?0;#rzOFmiZaDhk58xs#|KZKraN!nGc5hnO_e-&O8O) z!2CgY*y}XmrsMxK0uBV|{%063!IPO6z+KEgg3n?86+BmW)A$jAGCg1%hu1Pc2T#q{ z4_Vh^w4_}=nI{1le|D?EpJ z1Ki8J;|Xi!OrwegdQ-rtWj+*M&pZL{Sgp@&B0P@ybaA>&qct^8hGF(%vZyG z%s0a8nSTS1U(;fsvVIK$lUoLa{|z3SRy3$% zJ`Eo6c8eK^fzE~}Fn=DN$$W)yoLeo{Uv%^-8dR_bJK)vK_rvR$2jIp#`asY7omMWa z$x*)t0+CGtF&gn0C_LCzkcj+PmVY-qf%zlwWajfs1SYdUEcKIZKLxYIH336FbMU+QS#!B%c8@+VV%^YNdGKql*GCcJ=o7QBl2a^b-W zZ$N%%VatJv`sJ-OID`gqS_8v4(@K7~Q^5-lZN+aDZtee*Sb=FWATG-^=CfPrXh|!+ zz7^kr{xe1Y&Fe2p?nfYp75*K*hIyOQG|)2U-Gm1_1P&gW$KTBY*7}S8S=owz){6hoiq{8s)96yKk4P0B z+=`DCF0YPKHnS;k+k5(oJ_^reKHqY&|1V~Nr6SOBiPV5LprcBbFaJrUVEMaR@tT(2 zwEm*XiIxFXRs8o%EB;R_9&#r5fVu>6tG+!*K-Q0L#YeQ_H?-onw&GLHi2Z-CrF*KC z1}lWOH7+t7Tj}?~uf!_#{gcj#^e{Yvxf>qE{8e}i z^LOC!%GL4zR0QPA+%+__c9@y*7r6(%4W0;h?x*}hxCd@KKz<**8t#Ta05`?I!DJP- z`KiHWDgcj%?}YD!I}cL+eE86_bO@5v%-}Z(mlLxg|0ehf$~TS4tigKK;1Ct4L4(l0 zsiOc~&Fnt7^B2m05BZznwp#KF+ECz&MWqb=o6 z-*PGCW1y8C$)}c++d3?_Ae-1o8`#gvFW9q;&j0QR^p2*0a}O0zK4UO>V6X0lL&*Is z|7QoeoB716$c^t*Ke+xpF%+=)3%!t^}^>?2X;)X z2%gCNgo!{p3k;q^9c43r6kf=@7+%5r6ugf4u({N~8M;Ux=_~}In13u>{u2yN+!MNqZUY7KL&xW6Wq_-5)Q1|eSR-l_v!3sCPGvVRrXrxI4O8$Zl z*>U*e@c3=I7sDOpW=zoDc4ZYp5=O7CbI-1u7ee0Tt^R_F(~zoKPf z@vrF26aAZFNqyhwfpH=rm+s*WJ*}bizjUaEpS*a7?xW!a zmCI=VPfKAK^AYguqy}mwHo@KBlB=0Dz+Joa0#_}d!cL!_{|G#JcT+xHf3*nMab13f z8_p+L)RDi68eD`MPR?`W4qUFM;OPr#tJ@B~Y)KMMFH{nsa)Q=tcU%(UL0l0a79(5GElo}KukSJX44U7M!>$M~9 zTub2IbL5wtM-95XPWk?}wAUMev$1VH^`E(n`d8<~O~S>U(KHIMIUIt*@hfG64#u#U zODvfTpAUcO7dkZZ?3Isl_zLFj-k^Tog^OQ}vL1=>V#~$)cST?k0@dseSPB0E9rZwd z=QpW9HS=WnNq9HpzXETA=Ll;+^7vOF&;bF}php1}xD+0Nj#A;*z%PZbfZIxXS)xwT z8u$d{cR_ydw+0!eTP<|ZlfvXi7yqXGlkJ60on1Bo33D2&5;2Yq6zsjfjMm+*oq5)nx z8CS2N0wdw-evk=Igwv@ienAm_FDu*#p9fcma+LWt6hjwS?@KP;|HDYb)=>dxseblOgbzbU>YR8_ys8cM-Vyy%tKuhJ*sI+GB46In3Odpa zYKv7@9RJvJ@@R{1!Mv|77#h(S;j%%X6E#T2rgQ`HqgZ}9Jdycccro)j>GJbG#(KT* z-)JzIc_%~WwKvL{_l8G*p!ef|XEVPMUMn2uKh1ao0;d$1J-PW93KSqva0>2ISAT^YlTP`bd&yI9eg6m#%p$*sZY-ve{tz`tUPysscw+wx?kpfbjKT}2 zBmaH!F1SN=pF!^0LT-ISOB{wZ@Z??O6L1f|DnsU*Vu!Pz0>2|LQXKnWH>O%9zVW-rm*;;ewot>{(pg%^8jKb$3wuvffjdz+3;9u{ z`boMB`SvsVK)*x&(ivJ^5m($?$X+RCEKs-G3Q+*|F7cTpcKS%w{lA{-o zPmmw=DSQ8aI|2!;qy6Z}7LsRmpbo)(?Px$*EdL33Df1WL$Ca!5Z$1L{&-5950FU@w z_b=c^neN}i8<^L@D>v!+=06A|Y}NyvFOdJg_;p<7ec`q(dVUPNocU<@Y_FdGg?0If z{l6E-W*pw?xcOmR$L(mTQ*pLe!hNB--~I^YJ35lD47ZMuaRBbSjQn@hpZ+N2dt;=F z_1}ye$e#$fM^l3b;qzV8AaED?_1JxOo=G16F!^9?8dtzwbI1?l^6vi_P!6+Jc0R}!maoJ?H^EqLRvZF zhzQ8b#$HT541P-}xf8DTjBml+@E4K49q#y$`WXlx-X8sYm`CTo3amoFg9hqG(WQf& zk@%OA*bE}!8O%q(-OR_pbDJF3-xLH2n*uac7rc!50(cGcW$;GkYvB=J=!d4vL?Dg@ zcEKkzKLnq{{0uyYd1yykxgzGZuU}#vV$=RH9h*;ZY&uuc-)x*Ex_A8+f6Mtq_kA<% zR!4sHb2)a&^B*VoAzyjSi+!zp+Xky2Q=De>D0!IzejIz{6LQG|%>Pa9Z*^2a9T^Xy zpQRJY4Y=y(s=LVTAJGJcTLTrxf8V9_k51dsK)ru=Rc~?|8YuU`9mszWg?EUz*W`P> zuJ@_Hc&tS3JLEoGWj7=LWQB0~{(t;?)Sy4^bV=XPE1`S-p_fkT#o~{`WdR#jLS262 zwp0GZKJ;o3-587Eb6=&uBMe93-S7hOMu&C&W21S$VX+c){rx5b@=W-Y0u5*|eJA`g-H$5&T=$2*MShv? z6MQJl4nePu;`u+=tuzjoO(nZ*Zi6>4zgM`m(fFDQt7E(l?yMj$!o-R@(PbHKZqsiF z+YpFlz89Xt{3v`j^G0|U^NTK|f%2`iF3N>&<5!wd+h?#k?oH zp84BP(fz~WqyDd@tHU&o;g83z-4wVJPnY+8i5t-mo3xDL0bg}>URa4+NW<2RvYT&CPe;(J<&hzPxW?%;Djflor zavNM-1-IQt9*@HBqW`rE=wviDiT>sJ{}ckFix4iDC5WHI`kdDF~cGHZ{QzM@@jtIm zfj|E*t=W~xf75dDmyi|uIbj||pa2EJ(crT0sQ~{Y^!=81GfG+hyTYwQ^9?PvdMS7P zUUD1mfND!O`UlHR!+{3swb{sOYEXc)bQ}gWA0A-79Ufm!g;jpnAE_S?^GR^O6OXmJ^f5|FWMjW7c2>Jiz=TxCc)*Y6Abj z{cyacBz`l7`VYX>yXQ-Ui}(M<-{siJb>jhQV8fva$01k?FRrASsXJZwpRp3~&bTa( z!u>lbU+t8fe#%e&7W@B|D6mxo2gwM`-)oX zCmC142=rfLxtKq$f^h6VjNZRegI~_0TZel7o(AtWm9FnQ(a{>q#Vr;CQY&->`TUPp z0}oUGWmnTclhDsUCIVeAq5_i;7xnSd#*d}WWvhTX+~kLEJ47)5-AVB{qWJ~D7hzf{YM|^ z2Rq4KaP_gB`2EI*3a)b^lIAmFXfw0V+LnEc=`Pw1!lvIrR2_Y zpNxCBdW&Uj9W@BRmtjM3!BKRCTdcab-zHq{8>U`B6G*@WmcUoR z$HTvaADV~#zY~G($LJWBvST(;xSW9(C+W|~e^WVb;rGFhz@0dhH^UQuqkiIXXgt>X zi=YPq54*Ql!ySLnlEz~t?8m7i8%|PHI9<40iM2Qx)$53L@V~$BX$@s024o&bVCPW^ zs9WRU6V%b4?P*C9(O@RLejROCCc;ZB?`9OgrJwB;C&fVJvnac9-4(DVU>X4gYSB@t z2*?@uaWdWl{|Ej)_Ij!CQK#sT`B~w4mUl3gvwq6q`Q>r~V*OP|7o4V!Dp*Hjgv( zq*^XM-QIErqRs2b--ijPeh$F*V)v~2>H8-QD1O!Fa{kSCz-RuV!e`o0Vf7@m3BF_^ zxzlQ880X;WDDVh;?OEz)i1@;Sd^`m|4j=j&o$OE3{>Lze{7nsdV8*JW$KYPfjLI9v z$HIf1)dT*aL%=Uf58TV{6K72XeC&?)RG;Ac`4z%tVRy)D)|}LJ-_K4SV7?CSJYUZr z)|c{49}9ejKzuvB!43VWK{4~~aQg*%{_U4hzK8ifxDjgQH}C)Njid%H3N-EikHMV- zsDK~Ga^&Td@9wYrB6z{&y6=N~BU`#S|E}my9mPkr42XYv9qvJc%TV}7xP2hyt2^e+ z1E`;5<|S}9{6_TCFG}Rg{lAYj*ggx_F;-$7o^}_^#>v%JALtIarz5$_&w8Bl<2&pA zzbD88w%6$VR}KC|z}HVNFzQKaP|!{9=r4G358aD1QGgA!0dDkc%BSo9!>6c0@nw49 zv&wrlHLwFoV4& zd<34yd>*`%c`n??{9SmR$pW7tV0@|W(sZ`$gxi_>;jzsBfG0C=cLhz%1*i2FHF_eD z%^F0*3z%OAFJ*o^yqfv_@PO{7k%>U)SNe=!gxi_F0gq+=Av~FRIXs>D50;DX|GHTq zW(l2K@zHcnj6IJIf%5}$FU}S9eZTy2a(gW0t8dF)@g+{uE6J;<8zc2Aa?fz#a{X6f zPj?uB_z~1Vy`Mk(YieLzK|U4v|3}xE2h3FcfBXvNu{D;mGa{+TSh6o8l0?Q*Ny;dR zQcaswbVpPwX^JFECgdwoLx_k;lu8;>RF(-9B~6m0RKL%;@AvUM_w#$2Kl1&)KHE8; zv)*%;Cu(jW%Elzz3cNh|&8M)KMb56}g{;lMbA=oI1V=$-;a>Zf`kMhlaAeQ*Mv@1~ z?YZ6&@(?p&&-HHq2Z7HBAg~Ewev3R_!O6akolgkZ$^GL!|6kInN&|a-*YscGNY48f z6xb?>(Fl*1blzvp?77}b>er`!kO5AS2b7-<&Lv(ZGEH36xDQjek%CY&KmW4GCEkum zpWjtJ1N^FZ6))sq2L4GpS78%Tsf#fY#aqMw5HJ5?)Q5tc70}Ui@@N|vEFs@Vo^1{mQ1BK5v}p)O3zeg*$@eQhh`jno{$ZS*h69Sk zWeEH_{r~l@$6Y7d5rUQ!jQ9iwN%At}*Y5^Tk?$a{=-tPY6V49sGm=gD&VJ~JJArTH zDtabw@5S32F8Q}LZgDT~<8^^S)nbV70(qz#_$v(j`*+Y!g~4sjhBn6mMU+ixN7H`$ zV1gIeaUL{&O#5H*Ifh@5ZMoP8dKw9i1ePMZoKj_Y0v9wN!oL4&kPt$;iv-|F$>o zpddp>mUn3k1E&`PbYg&|P}O+3N}356WosbL2|Wgc!0yz-jMiP7A?_wf`QA#nP`7^Son`#X21NN8dX|g8f8PUx`#d*} zvp@_?ige8?lmOQ$y-9{&VN`;Z%x z)F$YE$^hNIW9R)4ybZTpckui_&cL=)FFeNc|L8iuqiQA58KbP3y)1u@JoEwd6AWCr z6gsJ%aQX}PW=85yqW(Ve=z8w|tzdX*7&sdcpc#kRxn(ec)MqAa59sIdl8$+l()?`G zOe1eJ5c5h82Hr_OLv2QF``0Rqz%lkx>*zM&X82V(rNdOQ2bu>pl{-zGZKOj15ZY#oieqtBZ|?W3VDV+Om25j8%kq7$k5Ls z>hFFVm*q#;hwNRp;8H&S6K8J>(qNDX%&>`nfs)$MF^xR275sbZe?gw&gk$#;WtSoF zaR#=RauM=rcT`3G?OyK%5tzWqEeK#8y}k+O0nQTtL{v5d{m56)AI{;rVLNz~O}3T= zy}`R&ms_}}{jmL$MLAJyhoj~+Xu_ROf~mF#hb6i5$&wFa;6vW9tl%V>(GdMKJR8GU zKdyI|OF^-7Yk8{n1SIA03QmY64bssO@{FB8$eRTaKtHZG!s8X314@5|aFb~_w*xh{ z&+GLr2SJeB4$FS!IYE)%$G~3+FKn+@sRH7-;aDKxa(X%!OJ2rC2|t5leK>87^y61rJj~1LUrTy2+gizStEz5~wznVafke^U|W*ZFS zjG7Osa2uW^x7+X`QXp^tpQGSsW+KOu?qr{^Pro)k7d1$e+xG(QC7-SI-zNW4^{t~G zuiymUUWNUKJ*T_05}F{p8-2naK)x^BY@ai#GoDcy1*#OS;uZaRR-kx`!ZTV=xS7I( zpPgP)F#cLm&>&ynx#~{dQt^T0ofW^AJfisH@;9#nikd06q|TGU$1zG{HWrc$g6+uFX*-8VRFuYjx&sch%y*O zK2GuH$diiCCSR)fa`GL1?mC}PaKJBcW~F(4S7Mr%VteX+b`B311S+X0=p}1_67~eKcb`Ee7ZfEhXO^(A4p+w>MFy@ z{DR(p9p`u9WH7*=e1WLaA2uF)q{nbRL6hu2cAjp6sWNY{1tifJMRB&s>|{4D7N1p zxVvz(sHD_Bf1=0bi3pVmXEh3xItoASi<+>G^96b22zWm^fAxOz-b2mCD@O-}o0{d0 z!{8n2uUZ2h{S|yK`NXx%#6ECav5(2aKl-_w=3!HWz1^Pami_>a!ix7J4=6sDJXQvy z!;YGIygL>x2EL4$cz>7YU;1B32yUm~Y(7L5E&^Vjycci5ocJ8;cQGW+nM6LYQZ0|z z-EAjtagy%|GNU2tKfy%{TQP}mACcNf!Du?NTd`7Au=+(+r@NZ`1OwPr^m&i}|Ihbr zqkf2fJbg3%Dplpq=O4693AW`kFL2<6lP0 zwZbypQt`Uv{SF5vMugg{k zuS9;vbJz!jtAW4F0Ap+MK0-P03iRJ8$QuvjxN4UEw{r$&x?Fh}*ptt*XM(3H_#I7K z0G_M}Zm*oawaavE@J0-L?-HyXJqBUovcqzz;jS#B2iU8FG&m*#GyDQ9>2&f&avkpt z%K!rWLOzr{To(Kg`5f}l*?ykpRdZY_?2SL0qK+pJAi_-89nn+dF~zr#M-{)8SJO#y zdo}$NxkD~j(-{AMc;m8yQ(_s`bvswLI1l4nUp7BPUaT^bX{YK{9OQ2b)@jpWF`q^TVRJCs3${FLIikO#KNDm?@7k?uKrN8tWd`sR{@x$aJ6))1(*vr+l;uVD#mWftv<@-OzV23ieijGbweiM1+ zulxnQhrGMu9!@>(I z=q&0-l>TD!gyJ87%lW?&d`W}AH~zps+5n25v;h<^)gGB!s(20Z9Ud<*{u)tmN*Qz{ z4}R+}P+#GNW#S>~cUJln$j2AtCjKl6HWm~JUqW7gr$6up^0?wVgcnwzzlEEV(!dqy zbQ{^F(h6h~)%%@M>`T-p`;g^b-;A`3$g$Jl75Ua`M_8 z(KPFKdgGr|{%I-#ucUPJC`GT3$9lriB=WN^gMNqsdXvu!%mE-5>Pm%nZ@LeMa;xR|F)^+AE&C%HS}L4Px8wusixfjUtScF z#vjt)LKrmT8B3Xuz>{KNem13%FTfKW!Pis&oNeGa7IY&!Y2`iO&Lz-)p*Y9ih5Hzw z9RxqIKv!RhtyQcIxVcd-m6@+jdL9gY!mz` z241Hl{~QT&CUyr84Tk>LtQgE2Y9>gxd=@_eiI#iask>n%1l%suUH>EIS792ZMH+? z&duQVqIQngSLFOZpd5YI0FEMb)P(`=Zwnrxem(MYJAmh+2w?d<;f389{gL{P(Kqwo zt#s5V3`a3KvYqik@+`R>_YFHjKgfdGzz>jTR3_dd4=@uyNnCIKEq)msIk)&z*MmGn zZVUP%d6GQA3T&4?QP>9L6#Gh!eZ^L6Y;Rfry~SoI0$V|;KImK-#V3(Fqo8kxS^2)u zj}Hg8!)zXTs@IM-q|8?P3X3gq(@uSdR7@m9i3#lj=uzYa4rl|1$c z_=R@;D}Egel2$;2`^Ynj7r6vY79Ivi_VjClaMS7b)vo1vXiGnzlj|p>-13cZ(lI`b zqZfNLa*c3v1(UtqA0X@Lmvm~KhX9=zpiT&WV#?1D;l@wuF8GEP;&pX z8*&4Y{EZu`dYX?>|1f#O0pNF&H(CiIOKwleQxc%C%zeqgD^%bg$(_Ak#Z3Rl?<58FA+Xpfbv>G(tKv1uhb!Kg ze5c}_$-D0>m{Ey;9R&k?0>`=C22gx7`FO<>X70q$s>y2#wLp?K1T{vSkr7|K{Ha&{QOJ8zoEd{Uob_EbBMg9;{TFQRlIzEG+Bx7 z{eI3TkLGj4Z%M(@e1X^gR|)sF;c=wSZc0DwiYFbDN8G0%SW*;{ z?IJMe0U4EvgXH@aKSf93Y4Bq^SC<$;AfkBjQ*@-onM;@Dn8ZRKPIvDzKW^^`r-~(J`rzSz) z{MQ?QdngF9&HB?|3jcm*=vf&2%;EGuo(H5J2Y-p3_qcqT)zmEb9Qb@*ez*A?JjT&v zp9Q_|s~XtamH|3$=Xn4PLgf8=@m(+$$X@$ZSOFd#2R}Wi-)AND$AUK|KROK8 zmYK)6|8K_{zdH_s2p!q3*Nn?$$__JIGkdK#83F7koG;{5o#Q-VC!Cvj?UyAlVdvit zGD8)1u^8=&nJdOVVRyqDu7rMz^J{rUx4Y-w-N5xXpC^;+7Zu#EDA3=0?tc{nb2x2g zhJGT~HJc`#uCT>st#I!IRgHoz;I6Yt3HGt~MiwBYcEY*%RyfKk{r2QX74Jn};z!$v zsKH?J>K?cG7ukapgp|S4>C2xp3L@B2ShFG45c$&2$f4L0|x>Z#fb zlIlI+s224hb)1F5&2>bUO=df3&8xwK3sIoQIs6t0XJ<$LIhvdt1#S}i|MOVVrafWM ze;{g5mwbe96F4&$0qiPzkUTLTd^H14iNH^_i&69o?EdF#3RF9dLyYFo1e zd63-R@i?b90`y9vph5Z>KBVx`@w_Vn(`KnfD5*Uhu6i4IXbrdxe7|rroRX?fJVE`) zn|?oM4~2e8>DMNA(@M~cf&+?QK^{2h@74XuLyF%?-dXWD`6%%G@i$2XCKHj>sDYi^ z*OSM{?Eyu(VbD*I+b1Xnlc&h-M=REor{9DB+q|Zc_~+e@6eUn1wwU8wD%=z(_5lnU zQBopZ1qEf(+(CX1d7AunjVVPV8Zr>-YENh1;(18z8AZbdp|7;N$gNO?JSYHIzZ@IlK zO;gxnvx7~R*p0w;QyRPjO_}}>{2a~)uiYX0e>0r2s_oyQL3F3z(ZA%OAHd^u6d#TN z*^j`Bk(a&`Jhu`2dh%)Hj{7MD%h~oPtbjGJt6%soI128C{tIlf*U6*bf!n4jayM&C zeLF$jCEQf_C@YNo3mRh$_Q4VN=g#lssr}$KrLheBbZQ6dXohx)_F)8q``d_kTex8IEEa-YeBJpU8;$^4J} z-}NFe<37NYT7%7=L7vk<>3>K42=&X*RsZ|pCr*wVj`BAm$uowV{CB27)dye@V-s{D zf0{g}_&?-fHq9;6zi$LH#HO)+ek0Eo;9mRxd!(jUp1oKG1|x$kO|x%-2DO^ zMLq$4g8_O@;!ze70}L3F<2Z7)|}T zvg2=}2u!C-{0v9CxEEU^+>F<*s?%l2?^k>;c|!4{ z^dCP6|HWBQx5Y>VNGgLX$#*I~fc%i+caxt`{4wFCV!0y-Y$vFl(085EKl_K@uXI#b z@iQJmLE9=m@jQxfHwb&^BgHqVT(``7PPM_XlL?RL2larS_&o<6bK(mK11<`$rma?8`B zV+Hn7Kcn=I3YYkK&H*Jj^I@dA^dW!KymkgM6#Wwc9^npWA9?m4@HjhHoubq)GTkf6 zVGhe%$RkCkoBB%=6!rdb=2DP469(<+sEQP*uv9l^L7S<9b|vqucz^P~r#a#~cTx~L zEkJ?dUlHu8NlvtKPGn=0J~eq>39paTvIo#@;rp-XROCdIj^g#PP!U8sa@~i6>jF0m$yX>ooqUt41aDH1Q~Z7M%D?$*yp24h_>bhB75|fbIQi-JFY_o;I!+k`$rmc# zlzgM&UC0k9em!~VBfbi_&TtCq`vuN}e_%7|T!7AHm*eya@ML{(`>aRNBAAjBb-_RN zdXVFkJp(*?zTZ!u;)culf2bY=_JlLZMdFnjj#(7^Z27e8KL8=A}ijYsa4Ln&Md~pdxzGx_Tl*6w-3p8LDc#wV` zBmc&58LrV<@Y7mWSFdto@4zAv_-vJ@8l*vk;S5|G2BldbSDLJ_iD(9!vY%?oH^~Pp zo_>_i|BqCHtuz>?`1j-q#ZQpWP~7}^KQj@nP`oC2#oxXE!RpFCjVY-6yRVlz#kcYf z#)ZhlIGRM*mcfg_?V(j)Zzh$`cQB(N>OaSfI@GUdJJ;6~gekDg?(sX>#^iRrkKF|x zyBLA(djF&0W)G+e+F2@ASd+PfL|_cEbY$o7KgeSZ5Wx28*W%C*Gz7Pu^k3m7)lrqX za$}$$yaf98Q;c_kOZ^)`kYL2yDeTIC3;`_)e|KZm^M&3;Eys@Z2q#!r#|NL#3aI%9@QhU(& z5hs?wt>C{hL!)G#FvoFIn%DA(J+{B?ZuE&XGkS_O-V-D54L>!?!%=l9kXu-%XvLDo z3YJuCx|5Gne4ucX>cDLXFn|SJN&U%6e-nA~5B2>29tu**;0SrKWBybZABU7yRJ<~I zNb!rwJD=tz|MF{3!O+tJ@LuE-6#w~=YF>>~!%*Y%pzgf*J5NCF0v9FkH|tz9aXJQW z=ZPoXN)R|hAh5%uNK-5-i4ouzaq3;eH6lw#Eyy>>6mAY2g7-q-ehFzT=Z_eh=1mrK z5BrLnWes+5lX=xWaFnZOJ?uCAq6$mjv^ZQsJ>NC;KllNn-*@2nS zJ^j~jKA|ATDbvn?WgZYm(z!DCBk(E~=zig56nxVHqk!0XhkSbHYF<(9WP$#){C3=1 z8su>))?jJl!bZUu;U;kUK?Jrn>-{)7T}t(d!Q^ShN09GSe7xai|9?mcrqQ6paT6&2 zw~)N9;%mw0E522@sX*viRNyu?amy#blh04b`oEikSt2lVc!LxEz)NTlp8`j_O0!Vo zp+8RPSGo>upJV21Us)pDG})k*XtLVee>i`50{N23=2f0&+x9K{!IAS20@vf|(KXkD zN9TagZzkcp)# z6Me}uiVq<_&$?Hn#D;ROh6?`l=%JP~^xd?PdT`v^2mvo^lr>N+=# zWE(GqK_v!$OG;W;n{8qZI;)!PChx0wj(o7yz(Pybbv& z#jhrB_NTuI29b9*{B-`MEca6oRR&LzPf&as`9j4Pk?&MIOlY=>N*vI(7O=WPpE`m2G5ee&t>jY;pSHANLA3X)4=B|-pk`9 zo%}DKc=dMNM1vhIMdSw*UrS!%Z-0|*A+N0XesI@msRYMq&{y%2&!Te; zR=fuJ{fdXkCoA5Ge1*pgjK6Cs*r5!DksnZe6nTk%{55`#JgE3=@^C?J;xD5hT2LT- zBY9l$Z^@@BewaL^c#(<7+(yMK3YYkK&Q2w`fCi@&Z%tnDUw@5@@TeyC5jyYf=vz+1 zUO4rRe+bU&5$CKySPNRV<=?-qM}sRpK?Ntx-Wwu+ng%ntc-ULApHjcX7ppwYAoa`0 zX}B33IW-C<$tW^p{PPPq&y2%f~2aLk8~3Wj(zS++KLR zK<-9Agrr~D)zgh_zi@*!;EdtnErq9sPCZ+!h z^|N0>|4XhBUsK<4$}wm7=MZ^y;RWVD`2sQp&6Gj;=TU?1il0xuQSp}Krxf3@5?9SR z_PNPL8NXK^CW_P+)Sy21fQ#&j#&+;tTrIns$PC$Qyoz!SY5Gu-O<*rPu95;3 zHp=$8E)SV^BEXqU-Fb2F6a#c(0zZ`7W+rfI7xeAbah@49!UN>9sDIag1b$w)(a*WN z;iww}Z>7LF240H1>I*Q4osEOIADN+R$irFa+efaalIQk z0z@l9;4tuQ8ug%8XzHfR}Prp0L@!u8_CnX z!Dq3cuabxRfk)VT50Yme0&hxvxA|0#%h3>=WJ(7xMTr=AC-$P}M8B|_EfH>pSwA(* znz56nC&JGlHs>UB*>Ar89~=+CwG=da2%Rgg_*djv#UFYY`r)Vierh}do+R%_|L>DK zPaA#d|2FWDQFQbK99e^+qrsz3`UAX5o}~T_4AA~j=*OS&>u)Dd7xZJs-vcfT(q4%i z$2uw#XMra89nB|q3OW)$mydydPzByio>lz8$ISb`GVY@cY%@`IEF49~Ah4Y{Un7qx z-fkT96N-ODo>DyaIP?SKW_a_@>1{&ECm;xoQ-R5&WBt74lhDs8zKJ{&_v;TF4}Isf zKH@uvDF~^OKK2w0(vSHa1)c^EpLT@Cf0aB=ZhL#PXP_Tp#n!T~eBe?LcpL%FytQERelIx+wwuAX9Di ze<2UhkJTUjJpDu8J>B-DUw|OLZIGjv$U~~27fgb_Zkom9x@p=^hJKC(MMkClKcgV4 zQr+)G7zEjtwh8u;>!w-A3zCSM>Ao=g23dqM&!UOh<(y0A3OC>XNpgJKE0}wYKnwyj zSk2C|{y(PPuCmcE!#MpM0@xkYgXAIdXX$5e0YA1dp6INXx!5G&Xgv+CB#%B1ZZ9IA zCyy)sEqRjM9=n}C4gO;h2`h<`T)aSEdYkYWps4E<*$L;zYTki z6tu9_@>1cZ$-?gcU|>_)^N9;RL6qFS+3fy@qxp0cSp`4#y?}BvxU9bmZaeQV^7Mz` z?j+WDw>4M`!D4Qey3a(aN2*lcB;3>>y8-&Pb8R6HzXyIXGt~MO)|dsl1#w+xDg`;# zz`=hfSA@fuqLKA(Q>=i~X|Mc^Z4tLKfsC$8ZH!cJ$ecs?f2lHbTD4bHxn z`ftI}eqLPmol|&kA1&NuBK9rxhp<40=E(WK5u~<3U^`v^xiCn44sNetW|Qa0?O#s* zi9G%V^y@J|lh>G0#UCb@=l@~Qg$C;=h_gVp?Q6}0qbzG+o8Y}`k?Qm(@Uy5W9DO}c zG9*)Ylz!~+uJb?e44dqr-T!|=L2fe~S%dQPVGw4GuVg{{lPAe-1!j{6$n7QAPvjvM zr~&=BO*NeJiZ^lP1%`BOaIjZw)Sb1A?eBSo0r&_pndI zsBbfO(f`=nvnWt?K5nzGGyKQ*fd60$YQ|r=%OObaf?zkN%%pjVL`oWGfOE-jk^qHe z;za*vgK!Ic6iL>!(o5#12$NvEDK>fAk&hOw0n4!BD6rQ1}!c9g)e?k8o z?my(sWeCy~Jjwv|-vCdXf zNd5_f9`ttZA{Yd94ag&k&m&Ke+X?3|c@F+v#|qw)Ocd6ukN<)@8-c%3peIa%9OX_DXhQ6KX zs=vjGNrBA#7s= zyBG#eQv|S%Mv%uZ1-BEhfJ~2Cm6A ztFsI|R38Q}7lo&Rpp)+An zmW#(^^Y?$H?bCE*=YwMA1w`S2+R&fKf_7^Uo~#T0B>BoWF^rRp>kei~tGxw5yb%m0 zF?F{HH)p!~oshZY!=J!}Q;quH(@%`U%)Tkv^=Hju$b63HUZi2Pas|%YM53sk# zZeWI3(9qi$1;Li!b`&fpkCB@uHu0VIOJNXb1%sj-9#hG~oxz`G6Z~%V2Y@FSxXm*7 z33UK3Mn99u12=)&i_yc&`20_OHQ^Ll&T)JN4E|-{+byRfTeAb?Nfu}%3v|Ofn9#Z^ z|91&DeJ(W6MF8vQFa^OI!GEEnTUNl)c;#pWc}DT4$PXz#L%0{16*&F<&k`#kh*|*y zk04K|8aF!^Cmq2SDClL>pU@94AjZh;^SILh4myv7T*hoCqGJ+Fm9 zsu%cbZgG~9XS;!a$W^7xYINST>Wn`~1q$oDXTR%JSkC{Sg(KT3hKax|LKTbo7okVU z>nr{&d06pT2;c;thyVAOq4KMc>14ui>Hl`Tj-w#K0@)exur+uAj^@+REvw-uG6~#1 z`?Z5SJpuei>bH0g6&qZzpl1ACDFV|r5gH7k!3i3aDDKZh$u-cAO-6u5)E`ftRW<%g zxXI`!<)_SAKL3+bf?6W*_5o-512-0K3L0jH?5J73hO6aJ6zB@xoIXjOjDsKNt=dQ5 zr~bs5-u&a(_=wa zqJB>4x88`rAO8aX%{*_?{-Y`Q>>vbolbI%O_b9kmUNI{AF#<=}_V$S7D)J<`J$znC z?!1Cbe8ACh;U`icS5oo(b$DXpcGh8ux!{neY9(w2pF#t+%X&RPE9x`RBR_)p|5 zg-iYOf2SxIpbW~sk6t}e@!I556>mm9U-2u*Gx;3x`-{L#EUCFjQ5TkJHo5Z}xV={V ziH=U>JMt`k|B~Mgq#t|5Q}jFRo-?!I=W{M{sW*83A7X%}4Ez?GK<|40mcWHILA`aH zF-!QHpe1=T#k-LYaFt*H1u4bvA}^Nb4-hA>uJ|PKmWt04Ua$hE+y8SBm?lVngB00C zrN;;0xs~9nIUl@Ap4kd+XTZP6Q;WbiGu79u=h~45zXyI?XBh<%2ELh1&}ah;5?f$k z`Cr1#;?!5wtjvdOf|C9W)glio-dH%k|M?aI%;VzmyeE){%QE17S)i}U!`r~^zM=C+ zC}@iMwxCCZdj(a2i*1B{)MU=&-x>@TfiXxcgGb2&rTjHZ&{2*}VDFrqq<%}KU+QBP zbTumQl&r2^``<=Enl*dk3{-iWa8sbDa`Yqlc*XyupZE?0usfx@KSAI)GgJreolT$c z{6D$fpVIc9!XWfDxZPU4O&(;Qusfx}n^4dhsz474_jXqFZ#OJIQa@4J^{4bt3Ko|3 z^D>_yz(&RKm(25={falGzEj5Urwe(=ay$MymBc5Qf=pd+rYOLp((FQH;sf%V$pb6E zcXF70(Nz{FGmO`P_u+}dg;#>dIMEF{3y$0eDF`it!5+5#S)XB*bJ)3VWZ>(i1_dV& zV&^f|th=ol1(V5#Dn1Wfp8r#V6*NdF{t5X}#dnfdEbCA8ufk0x!uwD$yQXy5jHayb z>D&BEY0E7^ik$s0uxr5txn4ILjm&p`N1NUS5AFpwkJFjoAKXC&cY*gJ|3@@*P=NBU#2yU6voVuM?t-;#k5-f?arzmD8K12T{N#R^rC|Jp3+eP0+y@+TO6 z#$GQ-zMQoW@d;M!fcyVS1WCEi(Mxx#z;($hp6&1LEy%ko-i>^?;y04JaV3a} zz|uj2*$y}f1zoiup%D_%&Oi4nrh zhNZI7A5Z;=1O3a`sW)X@7(|u99vdJ4gElniyaoCbl>T+(a}~dxe1+np$#=R+kf5M+ zIe(4kkT+0#xp0%}WLXr{ZmlY8MM1+#zaIGja?XE_vtRxsx^WaO2S=sYmdA1!eu2Nx zC(b9o;ALD=1xi96m#~iW)I79(Sm{?a_Z7u|mQBXh)paT@Mkk8V!2Zp)cX)=AE`tEK zFmPuM*Dz~rhwC^l$02figwtg${3pomd~l^1#%GxC|F8yjT%MHPZWf{BFa86Ea^J#H z>JMaMI(JI1kw;E|uOfeBXW_&6J>g~;C;k?FlmE3e=&=ieWD(Rj?@UyA33;?MxSd$e z+ztJ(8U+s?Y~+C-ju0QTJJj;=>5Ska=kxTNUrw> zzmi|dzzFX+P4@En|GpI18R~((2yA93^RpAw3gM=pQP%iAPwF_8_Cf#LiMW?yC#e3y zjlS+ftz;BnBJ%1_FY?dLA~30oaTKhe=z9*E;c7S?xBBNJ)w8MJ;R_7E@k+lJ`3%c# z{98m|0!J=^Bl{%O7V=PKavmNv*~Wri3jPTLzeb*^4~{M@dqDEYMc{UxaJzpAM`;S| z3r9uhEiDEAWX-|-USG>axILawLlRT(W zdWt+wZvC6TfNTnsAon`8Y5z9gpa%U^4Xze$3^Es^#&$~HMxJf}K9)6W^eyxw4Z&@y zpC*r!cc%VN!oBBzG8EX`?%j66QIMU{o`}9f9$=@l{K8$(4=X<1^5!VeMGPF+4gFa2 zSJ3}2px{Xnm`)d0nHcys7N=ZwIC_~g;~O1uw>-%JwztRaGhyYSKdC4JlpTs^#WL)? zySV>wCNF>>SP2I9koh2an0!AAx|3f(&YT1NPTU_{mBNIRWM8R3{pH-0rq~%RukNmd zK~4>iqvS#McH5S1?L{X?jpYM)o*%4>0@+n=tQ^mq88FK}WO+r|l$uMt|M&gR>$qFh z2CiIE8Al0K(6jBPl!2dRjjMfc0?4ubuV@t0u;zD@$4ffj&#z_vuj|w_|H$uE5qNVo z9od>4B+rp|fx6T92k3`6_1d%H`ago_SmTYnE;e@3`zvN!|RVdf5yM_ks-PK{UZg+Y$oj)GOf zP0g070Gr7-DgGUKv5NkRrBj$mlWmYW*Y@5Dd_*cufqjvnC9exoEn#3kKvJJmY_u(S zTh?sxg?QjF-WuE<-G0RRBf?Bv2z~kfr}WYyXH<9QFIwZFuH3C|JcQw=uY&V_!6*oK zM1VgT_+#Nk+rK_qcigw>=zfVc@)95g^bV+`dHquy9k* z+*=4>8pQmztBt1=v;d*=tP6SxI}b_{Un zHT3py1l&I9_z#ccQrCmqHR5l%+BNI?igz%~@L$L2u*Yz@#!ap9JoCcIS?ci$PRl>c z^6ff~9k0hc!T*2Ku>~)i+ntGF)|drd&x_7O3|y1^%>5>C1*fYQz&ZVa!`|dm3v!9? z)HfRe*#`vK#FNR`B~j zHg&rwxNiko5$+uMtUdy#3Z_n+4f1$N=W^=XQ8S17ai!n?1S*zhCK}lN|7;PMPPCnE zX?y8@@^63g*R0-2=+|Um+hjw@f9Qw4aw}_W{^Dt2^U71M2+X=ZPE8=wg_|}`-HtZC zg^u=7f4$QGgWNgSKgE{#0e+J7!|BH9N$$q(K!8aM@Dc@)JHd;SxBU?X4XFS<$s>y2 zEZkHeaWDMXOT3NbX>j-SU%za300!avVPHGmLQXh=q2M7F=!iV$V|sgFIJiA}d5G5q zQC46wJ9SMnYDC|;8~W8eF5|C{*-(fe$CBD>x%#rM8y;rh0o)(lMIMa7(J=B|9A*(t zXlc$k3)m<0M&^*==J_A};8CML5je=Ev8&nh|iLmn^b>=Au4|D4{LtfoO+8T?Cw)eLYh16+0rf&csxqoXzXHU1vK5r7QVou7l*&75|I8ui|BXLVyX12g#F)@9_GNE5qZ2ztb&}RGVQFQ9Q>c z2#!F_>;s1nz#?;5f|CcN=Knt~k#1g1<0@gG}u%Vo5m!$9Zt^#(c2>`z)NY40%pQ~ zAMji9Faz66)O{cNQI`TtFS0gR0Ug=EEsCNo?2+;+#s27O)4@pu)X>{lL^zt1xqRgeds?jF-Le2r@B*& zms%X&&QamUPm&d|!|&=}FcHnDT+a4?vFCFY7k1mBHd&Lv}6#){8&mvEg+spMMv( zfZUFbC&?qrq2H1E-;*cFJCUz?1v{lEGhv(NUN&)bf#=6P{rdfOwsGop1bCf}26W|< zk;>7lf1>SUim&?%Jf(PzQ{V|7m-c^vg0xQ{=X&Hx#V=;3iz_~sJf!&FMQ~ygR{T_V z;pX|Dh!Wh*4-q6%$b?PZi{|E%=qH#Vd&2o8c?>B%eM58XV(7<}{$}#5`1kt14RGHQ z7-Ur7f6b#95;(1R$7SG22DW~#Sq&b0(_ew9{}c9?$azSP#f(8n@pa@e)mJ8%(=ySID*nA3LK&Xp%s7t|+K>`h zoU&$0HvKZ~S#S0zvLQ z2<~QqULg;XcPD@ScLZ*r0<0Ep0>r34iuy0k!wi^P3IFG_^Ax1_!5s-lRx3&_p@KP$y}t0dj5YQ?}A0wprprHgJWV)SV8Ol z0Y}4CCYqDS74J%(upINBJgZ4T(h3-OIC)C(N6FKQzr!abQfpBGyU}=K3Z9gRlH1d8 z_Z9hEhS|GSR;jC*!}EPH8iZM(=Ou7qnOG^@w0$Uzz~A6ek>nBp7FTk-pWil|7B=nDNGWE&;JzGmOU6Cy9ti$CbPL16sCWZaBnzO^-n}G;igXnK8GLM z8CR3XHuL$PSuE+X94?UppTVFJ2mS?RS>w&%^{8L`&%z7TRJbY7U{#>Y$w!^$9DmnQ zFyXWS5r&a(RQwV0LyAunZfcx;7FDt*q9y+V&piVkXT{?Y)`p6a+_spTUxvKf7TJB60A3Y=V>Ip%=h$ ztnN4u{{#K-!{Fc0&sqPX0tpnzr5neoO2K+n(uU;w6%UgiRlE;*#p?dd4Iyvf;}ZWN z3c@~t<4hp$uJ|nSsN!#v#})sGJfZlvhMVvItWbhqMPO1Ld=#m($LFKvTd5vr6I{&P zm6Ig)7$?i*aR;#@M2FOyV$2-U_ZN8TV6agffJL# zf1v)av#_;_97JR7Xb8b$Nq)*{ANX^;l{%*e-hfKA6F;u#+GDYsf)Jz+z@R4s4}0%@6wK-fgG?1T%5v+|^fK@yxov`v$U~K&e>a!! zL7kwV-HN81&MTfHrP81!K#=5_;*-H!mJ=_qm)c$nN4=oEQ|eZ>}N zc}47?65NWdpnvz~b0LU-g}}o~qeMr^b9=$*2CVJ5z;%fK83{PUj9zxBWa z9ijgi{j9y%3+zO_xNiRU|LZq^Ajp|+1Pk=ufABsH8JGpKopg@O6NT-Pw|Flu%U|0n zI6+B#XFml83JQcDCqJQhN$;Idx$dv!U$knFS5`bk-c0dM!X#YG zvaf?zWW{cDDR34-V87uol{~Tt+4Zef?3E?Ia z?haMsjTEF6FIfQr0?Xj28f$z7d1xhgf;AgQo?ZpsnEZWmXN|{Qrv(N7h``(y?-Rw% z*lW-NPT0&`(kFC=9{CTxOgdL#!*3ru-BMp?bme`03fB7s@?MblGO9dGu6Q-_or*tu z4hkAxhZ@_zqSNpa@-+BwY=TR~Pchf|?O#^(^gja_;D8EnH+hMmf80MtURm)M$zzJo zC!Zl)>Yx8xWdqdq2iQ#BK=JR$M=6fic=Md3;%9j;yUIiC`5f`9Qjp0Pc%^Dcen{~! zdByYm1>IF1TdvG{q`Ecx))0A*(Cjm^AAog$<`G*xQ}& zP|&JOby>4-FvIm*@Jq;_F#85GweJD{8Wnb(YD{VHGYBrFL5w`P4gAJ4k<*1HrN+@d z@UyA^-9_Nh&%v8>yS-m3X7oe5z`tXr$9NTU|NroNi=C^k>Rju{!-{`NK0xsUys?WuB8#2DQmIDc+3yfZ|t>7pvnR9sS9J1-KXgP72x<5SRkR$@?ij ziTr-W=aDBAUrD}D@lEBt^*_(qs04dxuwU^bP`^dqC;+4r;Dt<9}=en-n zQF{s^%Ahy-0L6!p4^{kO^7|E^NFKM`w*PDjCRl;VzxppHTdEaJm0;zP||`r9nXP7s#tCK99Vm;_s68 zReUpf%;PrylIpz_Oi%{L$mc6w(tFEAKGUsuP4cYbO~_9b3M$w0XQDrOGsW*B zk0|~a`EbRjkdIeeqk9`d9oF!_E1BgXVsN#Wa|&_XKYbMlp0!W zQ{?v6%;V%)@=4S;x9!dTKkohjNA@1>%W^}}2*N*tx1+%r?=F|TYOM-7nS7(-|06%8 z_`BqxHmET2FF`(|U@!%Y>txBND!!pKE~%o&P|yWD87W_e`~Y}!@`2>ZU%}tOcHVV5 zHo^Wp&KmDwaDe$LhaCTF4Qq8X*&#-29Q2$TMOT*80@<*B>@ad+psXpscB|v$cN&msm zYhJj1F}cH8*r;jZ-T9Q)Z&Y7#JBz@iDAN)pwQanXJk=E3-nqO&4x^2J;8O56S!pdeLH zApAA*wBjqsbBcdT9%%2+=x*}PivK2D;>%+)N`QldJSV1jjd~bJn{>{cRBbK zs{jis1E__>p;`$m=V9BYAhlW5NqP z|9^!BLzMx}bn=`Dim#*oM#XV-ljr0V|AG2-JF5LZ&S>(St|BP-E9sqB$R7|kG1Ca2nh&!i)l>wSdW2I$xV{v-7B6!lk=hu!vYG>J3RJdXQR zYw#xIbEIa4jpHq>ak0z%O}3xBuHwhZJCmOteyUs9g&IgOkIQzlLW)yVe+DUHYD2t+&-|-g3kv;slSE#XS9~4 zG0*>NgXcYg++a`vMoB>nYk~!=z$R6J)#OJN-%K9pBu#cY|5BqvLD>sY;}wcW zAXCT_ zoe{u(Ty_z6KGELb_5r4OZQv)vVf-fjU)|Q@u5=<8*b9a&5IDIm;CIm=+76DQENE}? z+R`+I4a=TvvTdr#29X!L+%#!{@pm5u%{&3U%Ri5k4_5po^2v(7PQG68Rpdttaua_u z1tq%pJL7lcl@&iqUSILEEx z#e5VaO5W18|12p{VV!7;a5G-BG$_jeRWB~*y|S@`uWZ=i_b7Qz@o$8iOs`j&IONix z#K<+CYwM^-0~j1q1_Q|}Ut#3=zk7t6cSu?)KijC^QtAId?nad0Bn9IXFYVm{k%!e4 zuSLF1@h0Rs#V;o>-PNl={`l)B0+Z@kH0f1~&lfq{g%^>Rbh@5eztY~lnmngI+6++sTa&!A;vw>-ieE;)Kc6Fh zUkch@>F?D;$OkK4t|!-mK}oML^Y|=iU-H1M;P%n&8N$ueFsU5Yy%L_4i#WG<}=w1oP>81%2Ee#gGh-{IGHov{?;`~qhK zc?o`?!#2%X*PzB3`7o*ZMZNzz&Vv7_@lN)kxavcPJuc_}6O_R5ZZzgOQxz{yzESbI zHn8<+$Tg}QW{h>-b#buy<#B08s2~9rqgwB6ehon zem)j%`q26*=im z@-Ig7DX4grKXvbt_fvc_+cM4?+rOGI?s{Y{_$Vsy5BtR1!cCvhAE9%PdII?hmg;oP z`_oYzj_ivE3xyj;Uya7_yNxy8Bn2(3Y5o!JHO*M~X-WN7ayMMK>%=HnPC+Kng zgF!p;KfSx*atNg|F|7yt3ia(hp%PbvCm)BOKj`Nn%bze@^1p~FT5kl>DI()xaOat@ zC?mJk3#(ZN;YL5O0Q&aQ>}BEJ)v+q*8`MwCh5p0Fy=nimTe8M;Ah4Zr2zh1}xb4-Y zS|LEQ?*6_~L%3I<*Pw4Z?@a0s?cvvdOSr_BTd7L$J`D~j{snpHYQLlJ$-66loP4O_ zdEQNF`RL`x@*Rr5NnWw1t$@kD{NAS^a#{es zO}Gi1W7F92-O#(4ENh3-50j@9??b*x@gXh+2bAC;@?sHNQWR(cc~J3LDc3-ZuHaLFjzf24PlD9;(HI?L1Kn-rfxUb(lwbG<3t1dcO+ z?Gtx-w{YY&U!@=K;GO@;8&FE{f*2S_8P?2>`=9BkuhRdU`VMPsC#Zhjt(QD!q|(2g ze6p(qqbW!!o*>_(_#E=mef*hNPTpPdkI5&HpB{gu2BTNUm!NIzYSxK7s`w*T|1Ibj zckp|Q+*u56&jEiR5BT+6r{1jy9Q6yF;p9Pb^lis^lRU`+*}y-LCzPM6L*PG2ZVS}Q z<8uD*D1+x|5L0|Rd6?W5sLE{!kWvNODXA`OG?kT`Q>Jf4S4f6T{_U{2m4ft2q|OeT z?=4>nZYQFry&DU%e5*E|K_2Ss?-Os5k1D{u_D@qVwSYj% zsaCd3U0PYSv@}{8hG7^+!w@D@E2A63WO8L#jC0E{nOqu%;Z{@oFicif_T|#luoxzz zsVl=MSv49)-}gDM=h^mty6q2rK9AS?_5SfXKkm8b{vsb}-xF4^j9zIU|JGXNFB*Z! zY5IgF!Q;u#f@hLn4)>DF3lXY9jyuQST}TKz0ZeES+%;XF(DU$A@@ja1d_6oqOYg_r zj6fv?euled=n38MRPv$rU2XLYiTp^opZsKT(`ceVIubg`uYyO<)F(6-oo;~xmA;N zu3QHM=wbR!<<^tkjCFpyy?x8a+Wt)l_}`Ym$97nKFW6*B@YLz zC$4V(*?$+Mp`Um4_GQZL@Bj3_uP20^Ckg)b;xF0Vs8346GwOA(RBk;du_@e<5`RH0nNc>0=oVQ?I zjz>A~2jVNGx$&-AS*S<3-B@uqt$2X_dVu<Qy-t9jEfdmPld&Bq&0|!5qfjhBR zkI0pYHf<6gfTN%s9z-P)&{G@Sh4yk$ug1UmCMl`6zmRiT{i<@Sq`}W*fY&hauXg*v z#)hSG1>oFrov0QNsuEWzw{~9N7t)V&-LTzq>;Av{O9?o;*rDq7xcw-%S-irKzX$Bw z=IZS^RH3KgZu0-Z^U2?amnrY9zZzo`0u_|74ceSEJ+qHs7_uv zF~0KKFxk2O|M6CN(|85~7o*gtT_c;oiwa#J{TP|fwkN-9jhV9+HoHizz)JA9$V{Er{g%LkTg3Cx(JA)*JoSlZT5&qOiF~GVtADrIDjh|k zqZ%Z1P{Iay;x&3nzeY!~-%3AW=tu4sMi^75{mts8l=YfW%K+^E1xV;Xz>R?8cc`08 zRzgOYBsl&Tyn(#!Re80`|Fujg7Ki0_yb4y0igw7jrg82pIsCE)>W5zto=W~E&RmID zaXkjOa<ql0O3Xk{^$qE`WVv zI0k6H+3IJou_az^!(R`dlqWvsW_2d8j=wt)FxBn0P&?xr_H8)zfdSf<>*1y3U&3q1 ze}cF4ar^lH6M?Qi0c%bN+qciu)8<+FPIm-6i~Iz5A$c0SihR1<|5IOyLV-C*2y^QL ze}?mc@sr=KSssq>2h_e|ZDZGu;@{a(L%o(P?%6JWCiaydob$wYrUYcyQ;!8|n^_$h zLGeg*^d`KzP2Bkj=DBKH+5@BgS7<-`7V!@FyYPF}!n957oPS?d0qca|X_o<<6V6`c z*6aG!wA0O0_Y1A|#$VF@F;rr`eIHRB_f)wr;cjyCCl#>2e3Ay3t?uVp162Ph1Dt~u z?6&XoshyEJ8lY~`Sp9TSKSl5$`9S+dhI;>h9d&fL1dL|#iOQ`3Qs=*8PbC@?s)EOp zAFrMjTkT!stL$gX>cgkAt$oX>zxto`NXVjubo*JWdf2rSFsk}zCfrSa3%rEf3$N?z z*7!>h=(t|r+gHHbZq$7(+{o3v5uQN44W2{3N4XkbT|QG_p#5}NeJ+?h8XmY!A9xZx za-QyI!86D&hx>1*`~Nuzq~z-z-38AjUj#28e;!^&UJbA5acuwf2n2cpvYj`>TgZQg zcanF*qwdfbFjPIQw~i*?-+sGe=V5xWsRGu+Yc(F_dLCZk>4W6dv4*G^HBND zXD?1@$v8nBw`9CjVyE3+{r>kLyCTMocgNWQ&!5tfbJu(NA@WNn!F}Q-=xEHL6Ychi zd&MhI(-wGek9e9Pe=F1iv{SFmYWsg-Kj%{?1lndB{*VFu*k%JT(FOa&tNSgryLbo# z{Bf*0=c{d;+FyJFCi+9jfeqs@>zR@D`QKC;_$d1+le!yDo(wM_zZhOjehs{i{5E)p za_s-Igd!FAZ;8}bzazo8Q{SuC!(+%dAE2KB_VWaFx4pN$j6VW_%-(=Kqlxfb@)UR> z`HXpZI1ZCd;JhlnOS$!|xe`0C^Vo6x?WP2L6!6?G9r?ngqieBO56l-&93(y!{;YEA zT93cH>M}LaP!%o20(>T|U@-!<UW`8;?!`2+A=@-lcS`75@o_y5#V z;2k8?lYa(pB5#9tkne-L?$%ap47RVb)w^UY@2S74_ZS2cC_$d{sdurEPe%J3@@epL z@|)mQecT?u5P{Y{0c-m|22Z(1U%@hXCHZQ2J$VDXiG0g7xc|SC0=tmVP2SIbo)BR~ z7wQv=f+vtqfG3lm4o@#M^^PtZkmuh zK~eAZApZpI%gKZAD)K$>`o3EBgqZ zNd7H6oxB5X=22k4byB(_@)7WI@`>;Oc?vv8ei^(=y!ZIK76Dh0zOp;u@#MwuRPyJP z_a5J}8Lj^|pnay+UXA|^0{L3NFm}RA$^V7dlDl%Ga*gCi!rRGDw%oe@k9|O2aXJzb z$ghG=A)gEPkS~Cjl9$43mG{FNS&vKk6G(R7ar>v$ruoMxOz!t~S9v z$sQQ#sZ_{pz^H;{YaZRGdE z4WB-tr{L+fJM~xP_#XmpN~nW-$UlV_k$;R*XQ0%>Q0ncf{eLQIjX!jblr-*feWph$ z|4)Kye;L{*Q~TL)5Bco}=*O>Ijjta4C}9;kY9g{3n_3G0%hcv!z;+Ihu4$Ohc}Zy3hxx}J^q#= z5M8R5Xf-^A{6qK@@^9f;I=Kc za_jm(i30Z`A)EYhcp>>q@Cx#^@M`i+@J8jm^;bLmcL=mo!td~~r}Py>%$3T;l8=F> zke>k0>UA0aJOuK41NQMZ1MVZg1zttI0A5G_r1DT_()Z`$`hO=SG@~Qe)B1{kgeQ@A z!E49|-zpVKD%1OkfoGW%I39rl@^j&3&*&Xp39lp1g?EwP1CM=H`svyJixEgcK+b>a zGvV+&@*230d?UP^{2O?s?xyi80u6dVy?H}Q*GWDM9{rqNiKF3h(v@@eoI@|)oGK6E1${!R;fdr8 z@D%bb@F_3Q_5Use@+hI-JSklg!yd=I>aeBkX;xd3^zxM?&}U=k8K$j?@;l@3S9EVOs| z^$Ohvk0URFXW8!5Uv>8M0S0&r2_@9ghwyUpE$}MxUGS#9ZjIkBUrN-~H=sNU9=TLs z*#vkz`RVX<@=M@Fe^)s+WuN-16>mdA z4khe{7m^RSLn`MZ9|12Xp9rt(ag3jWKwD2h%|`uQ2A{HAU)i4zzl)KOP40)6k-rJAAm0G5)m)ALH3H3AK;8d`hpo^{x*zT$ zKg@osg?e`j`BBP4ZG!Wx_SW@(HYH3)M?vzN;2q@mz{6JR6MYo!s?^=D+?h~s{Z*+0 zNbpj^=kOBpHn^Ys4|o-Mg#Dfnb-w9!89xSrhTed^{f~#Yke>^8{ZC)nmGCt3TzE10 zJq4!KfqJJS1r{TrjeIHG_p&~44Ltf4-8aHh$iGo;Zvw6UYASyrp^y^fZ8H%@Ir$Ox zn@-dhi;>H_Y1D5#lb`aTyqnI0n^QgC|1+&XZV(0$aPIX^Rs%RYi@i{Y!I7sI2;uZG82-go=oia;7AEQFW8rVsF>@=z;YjrMiaej_~o_1=E$@xMl( zxKF^^%sb$n?8X7cH9;|+b_Iq-P$ zd*PYnKDhS{`}nu!E`Q4r@KM4Vcs2Ql@H+BVcnkS&aAOq~;B5c?g;KhBCx8hJhbNK8 z!&Ax6fM=3l3U`y6vk}OnKt8;H{2_QT`Lpl}@>i9I+DSJ_d-eHWO4x>uj5qadyc?cC zKHy%dTo(Cocrp0|c!ljw{Z+Y7Lm)s2Q{b)Sv*1ZJ`b6i!OUWOA@9gW=_+Gpr z2-H(TAw29YeSpW{8RX00e)84u_8!Ofmv^(N-+rjo2iSsyJn~)eTJnClo(Nm3_Y9-vH>-s-Hfo(`=Bi{q>ARo9uDi>L&FCZEoPd*8rqP(~Ms`zIikVOfX!}G{< z;6>zj!E4AD!HxgxnW&8aJOU}b0W}@Ns8$}Tq)lj_L+!W2%gBF+SCNM=#9rD!fzb=4 zq%Gvf!8^&%fxF)6S(&|nOn40Wjqps90(T?eA%7HJLhgrGlfS7vROL3KeE{uywtqVU zoz&4^aPPbN$|CQV3RRIG0dFNg0Uiiw{g_6Ylb{ET>F}ucv;<=gJf8escnY}>o<+Xg zc6I%qPk}W^@R5HAFDGw>*OLDR-$~xTNGjK5c~AY-?lK&KxcBuH%R3*{nUVYqw9g^G z6kbI>8(!PT?eXQEj}b{x77!9wd~I z4}2i>gyNN3j~xMOe>%L4T;4&ce)>&&FShF98YCpt>npqM00YZgDcbFdq=Yzl z3;8MVZt`?^_(px;neeE-ZjGOZKy2TD^84Vad4qB_zB+6uutfzz zmGocbR{KtB?<7i(??U%#bdK}w- zH3A(y0ku%|w-Fxop}w+j;PK?Y!qdo&howRp2NRkOn87i4{m&< zFTfht+LUG_1)flWP!n2>gjj075uQf=H9U)a2Rui-_xSq<0WT#CT_iItAs+{?BtHq> zKz=^FO>;H=3>65q;`@ZI@Ist6AZsnm?aI{Y<5%q;$iDdW`@{8cv zy>hAW6!NLc%~0E3-Zrn^8A%C?(NP|`A6`ek3f@Lu4-el=*Z-Rlh}o>K;AeO| zdAIUV3pjF#R4$3yC&ANt9NYhV1TuR9vfZ-aIplNTUh;dDhnmoGwD(c_)g}Ud3T%W| zlYb3wA>RQvzS1lA4?LcHXsJ}l%%#9M1bpNt!Q08thljQ31J8g*ljp(X#e0uGQw2hm z?j*CO;V-{k2}9bjz*l z{{#wLg@jD05P@o(M_2jR?+sNNLz`#GDeHXR= z6CP=9(N}!%(^8^1@-gsq^5fxok0_%bLJ+v>Q_Fuq*U+oL{yPf>7a;ZcY`BBRM)4w(T#Yjl|PTw|H!}G{* zg_n~rfVYsB!rRDKDp%u27-8G>f!84+j(ih5ojeFHCEp9LBp>v=RA}dRy8a)j0{P=^xwwIV9v#!mDr}`MYpG`DgGN@;3NR@_i-(;cfZ~ z2EQOBiY6ZePa>C3KB=$qBA=|N-xGY6xO_RUVch+qEFhoyu|7{^wKvYS+pG8gV&K&XWSl7-ErgHsOF|I-0oJ1UJEB z$gAhegglqZgz7NS9rN-1pG|}1{qD{-KK5?;UeH?dTW$aE_k0$rfkPc;9SdaOz$_WK z7L`74p?IQsxdakX>Sqz~&lEolrTz`>zEb=Y_#O94N8aniclDE6zj%NNy^jhdph7tR z8AdY#1ys5pm0R1`@W=pD@h!Lo72@tY#j`Q+qL*Y-R!~3X@CMyY<23|Y^?-30b|T|e z8Q@RsM7!WkH;W&OlBV4&m2l;XJEfj~pSb6G@ltI2$JD0p-``Y+S%Cz8#Q=9bfRfG^ zcTPn2Jct4A7SBcdryddy+$G)s52%HO+9$rpf@6PDmFlU#O8Q*|tWu}mBOM)rjwY=T z&mf--cf(N#<8inL-Vgn}5BK(Qd;Gl!_z-Zud_Hca4D2Vr5?<{%Mpz9G6v_ge6W6dx z*(VaL75Di&x)Rs_sT4R337Oh!_SX>!s*9bgnbD8S7O`z4iBQAVrTp3JdB+P9l0@p zYmsl{A|W_Bs`FmTPj(e`2NT_XL=Mf(V^^xyG>_+rbg@#7wsKq3NCK*MM~zySLX;79&X4zuuf z{V;n&J!n~#YkENjei}RV@9IQn|Nd78X8JSE?U6X61)r6K?butA)BvGMJzcqV;_@t& z_RgmK5blFJC$#*%e6B3*g(QM_`^+6`BEFbPBe+ZsO{w%zt$Fcoi zMWDPVAT!FrHgm0zmCeRX+YjJ*c)WL2Nc-Jrf05eTtxeFeT->=RU2P)JM1dm~OF}g& z;T*4*IF9zt?|i)p_rb9xjl&<4e*AE!qF%V^r&7O;KoEW(HqCeN>SeM5=a){#;;?kX zFGc%+s%WTvrA@iDuXtD5{g}q_NVxeGJlL#~0h|-jHs#i~ucA$}8(v2~pi0^|k`ITs zYOc2b1O#?!0rhzxcsKdQ@W`L_!|ZB!4Ee3_1o8!zTlfD{C?KC~RKMXuz7ic}ldps4 zk#B-`?$9S1gh%b9`~Q0pNK%2me}i7N{(pqwB_9c|B~O6I{i^qKHaxx8<@lS5Ku&MK z9{+lH33&m$j{FgLGx-bfHu5)KHDzU;6sSi+_%3|~U%_L@e}Six{{zn;cfBU#W}6fk zk3cT@Deyw_3*p7&+3-^GTj72<&VPon5P@n+coN=5UJ36ae;Xe8n_jt3;IX=!#&-xL z=>ek?o<)Ap>r%QL@=JW^{r^e|T!DmU@*ChC!>Xln-ac-RAB{jopMZ7zCBPfVQ{mm@negb{dL?q< zDddIKxc<+kfDZ`;+N`c_X}$JP2>uZ6E*kxyJraCjxDh5dMag&e)@`ECwD+ zo(NANPlIPT?ri@o1ah1J=9C97CilY2$xGqYp^8{r?n@PdckNpOB}cqa5;VcmcTwUP4|3_uKB&UzNKIff`Dvg13+d z;N9fSa95{Zp>}veU$@5ZMj)eaK)LHpDO~}19K4)78D2*|1>QjJR<6d6Fq$clkAx0# z`6#veTK(Vkm6fA?0(mt&gS;M||2y6PZ$Y4(5_ZDt$&DJRP&;`Pypud0Zv5da0NXzW zfrOrb9Df<`DdaiuJn{l~DR~LJj@)k|&_;n8c;r53rZS-hcoKOlJd?Zw?ja9bEtNBU z6o^KknmhsCNS+GcNuCLh?9vyI3r`U5J^l(2NTCEDdM9AWMPN*+ zBxJy^gx>>qy(aA){~8`!DPDp0W1p0MnqCo~2d{HnwYTfP0)hTdNrLB9NpOCc)D7=| zABOg)JdO64&`I!8xc7h3&(MAn_y!*Py7(i`_0L^p(or=^bTT?R;u&$@%aZUkJO^Hl zfp37n?>GjK8#aa!`>gbnh)O(#_BT9>`+7}CxE_IeB&1f$z-!<~KPMfzG12qk3zb{< zh!!`GwIv?D!S-QB;1Ic~COWzT2^$fp#pdB(#ukf+uwA9R=ZD^1bjn@VdWS}8Ca3F!m$gnW1_`9tv7Funb=@Er12 zo&E<|?Vb9o|0!RQqCT5#2T*_Y&lgB&IY=MiM|d~+pYXT{y?x|5+}!?99#hV-hOoxB zzLCVbB^vutpMdhTx24p%)X{W!*kFBtIq>v@b-x$xA@?a)!rRDSg&Qt?LIG0+tZkpTMz;OPelqaCNQj|?L;p`Iltvy0 z&m%t-UP^uu+-#x1)d=Jss?XE|4?j%z`{7mOPr(z1>FxgqFBb3J{&ffhDdAIia+KcD zcI9^Ea5y>FhI8MM3YAj(1@I2d)%c|dp(A#fmz`eaL z<2N8s*Bh`81Njn}2&0v}1MS<%!vaz{SG2z3Xm|{HLco-SWD2ArA&)#0UQV71Zy+y( zw~_nchB;E7X$1nwj@AdRgeQ^L!PCi`Y**L+*%W9)f`{Dxz8-bB7L!N5 zFO~C?$HI4#C&9yG)B<|yul9HOejoLEpcUxzmyLuVxyR{fjNU%E=&O;(lqGmf z8SR&+X0AqY>zCB+@ynK4PcBCrp84|bO&12Azg!YB-jala@y3Bq;qJBK=i|+5M^;Gt z>i-iT1-}E{^q%-4yqeumalC0i8+Csmf%OPn_mXtv!4=VS{bWXuto-i^tjH;qp(k2$ z0N>u@cz=$wvLaQ|P*=m1%B=?**UvK1_fer)>t)*~(k8eK?jgS)UhKHD{hvgj#R*`5 zmGGV9YvJKX=-a*#o=UzAo<(l%L7m9N za*&WheiuBQd=Wg8{CRjDc{RMqcBlTT-0KmjqJ+)Lt!?l5LAJefp>gd8QlS8~zXRS* zUJQ?p>$6~M{O1tJ=^Ie~8r)0%9=x2qS-CaQ)SqOc&tV^$w?QUaOYI*}uEtki9!-HV z6|g!AqNAg6_@!@@j@qgHRdCl)eO9Ihp9_y6U!dIX|7X1aM?JB&|4wU=0TL)-3Ot#7 z7CeJ|9z2Kq0eDG|WBZq>fHfocZ&JETFrms1WkNMQ2@-f4-bDThyp{YrcsF^ci9q<# zdg%`ONCu7~9|cb*KNg-zo(lJnUja8uC~yM;<>d3>mE`iZJZc{ze-Z7Q$lp|MRXSs@ zU1`%;i=FE)Bm^m8$j4HNPVyt+;S==AodS;`zX+bFx!V5MAdsd73}YTVi~K=&9{IEI zGV<5pRpjqmZe9NeD6km`JIQ~68}a&z|Ai-zAJ!<9OCdiRo}nE3zwFhgBTz^Qm%_`) zuZ35U-wAIZUj%RKbs7H!1dNIL%2vU%$Tz@?$iIQtkne(fj?w$?zX{j>B@`I3NlI5i zehj>h{497g`BZoZ`3>+ebCN!zyAg;dUkrDXFN1r?*T8+`AHf6gp6$OCfeuR81CLG6 zCpzd8IgSn2GJEGq!x{4i<I89GJx}5&^c9-5W86t z-bOXtuZpK`6aTKC1m0I}z4_c2s=v$@_L{Ws*edOvU&GB&ZnbY8V(JO~UYCR*2Cl$N z_rZN%OGhumPpp>q2CkG+G0}F%cS-vhnCLHWU;(Y@$3#a*t&)I$rv$D-!qIQaOx?7y zTzCQb%kXG;A||xc_Q6IwHqA7+d0dSQkWL+Wlv^(p`uE6$Dv=PeTD;?XaWDLGxDPvB zE&O@7ci1vp-iJ?GWA|ek8Mv%=K00xS1Ps@YGC(^L%HEQJn?^`Scc5~Swc;63;?9TA zyzpvV(*1~vE?tWS*iYru{_n;B2fdAsevyGsM#6r$Z-@90`1AiK?ftvO4S3u;;;!Gt zU%<2A`{31oirddQt>f>ZcO@b4w*;#3*5|VKlv|hKLuF;LnCMCGOMA~j;?9RrPX0hV zHC){JDCR?OBSO3z{cKTgT8BZZOFs&Z*dY5vJo#+6i`=tO22PBW0hacc5#Cj9AC`ye z{r7K>_Q4^`to0klAJX2q1c3}ZsBA__*TNGIlL6A<4}2&cWsDR*5d&ZKk+^TP_zCb6 zKDH(_*zk;%&z2-P=ihkp4ed{;$B0ljF4o|&!${O0QySoAECs$nAeH=Acm}!AB#)ME z@?mf<`O$E{xNLu`N~a-^da6FtDewaFS@5W2z5P6R0{H`upWU~;8ovyIJS|`tufSdB z^i5Dd)9G|X{uw;xe7$`eyqtWW<<|9o4Fv{&CM9ho9|KRkP#+)>o_3M$li}4D>pl%0 zoI=6UZNf=aDai`^i_sTYFu$e**$ty#f2c*#eKcRG-i;cp`cK&qE&t zM=Q53N>izQ^5?kz&!E6XNN|&9!wbph!hPgkcoq2*@H&$MFCoxKUJGv}{}|p$z7-yG znO?cw@C10z@fY@mlqiJ~4u?-6KL+k5KNFr$o&opkZW`Ai5Yz+4o$$yEeFYE0W69-< z2P2F;^4HP6jQoAu)%AZB1-?W=3wb*{;c|UKf5TJBhcrt?r;v|>doAy&zuG^O5U8bu z3*a5(GvP^7^$Fbq&mosDDvU5ZecT>@2@*>B1gzt41-zboExet)5gvAhKA~-J7x|uM zy#FVG0t3I4(&dmx!@cB_;N|3J!E4Dchc{ng>NCwjAV>*!!NW53_KV>0@QX9$rm; zD!h^WVt9LBx5l4^K-hGB1-HXv$sdBJkUs~{B7Ys8PrhEc8b8ADQQ#{iG?DLsyR!6& z?uVz4pR{VMJb^h%F2i%IJzD)ueN#L(4%h!q;K$2j?F9b>N%%$D8x>Q&}QafOItP zGr4SU8YBJ8#uJz>6M;kw;Jjw@`sb36I#v?C>n|PEei3>?-IlAT>lsH&dwIg8Zf-YA zdtaQmQ|V=2ikrN$9}!?bW^?F)=N`aU!FkjCp|>{;XGW)gB?I(s8(HyvaGucna9-J< zmeBoN1lRjf+kaR~=!?cvm0L$gChgT1!VAc+f|rxeg(uF?kD3LR+t>dTC`Cf}Og&*G zynuWiyn}obyz(l&pCG(JIre`k^JK4>_s4awm#E?wn*us$VbED$&ZI8lTU`{lTWu@UH_L+;ASMWk;_-Ls+X#- z)hD_H?c>Q;!gI;rhUZ(}Q-8I;e~LggC43LxNxlyrew{v{gIlF?apYs+X?@%t|0D$5 zeFE0;cLBVR{3>`E`K|CK^84XoIr>DOZpHO~6a`*ELM-{a@MQ8Y;2GpU!L!N#hUezc z_5aXsrE~?9Fdp7YekwfXdVOUV!*j@I!7Chhw*T!2bU6Y0{HN{>!_#ii2Y3$dCx6}P zhkQLe{zknYbHIN2Q5n}nxj=C4+o$!HFOT!Zi#rp2=PC8@sxCBQj~D+O6J5MaJaCNo zdGM>%?RM)Pa5dcn{#tH&tNZ^6lCS}nME_Thj*b&|qoZZkm5eno+<6<$V(W2Tc@q}U zf%dztM<-DpjUj?j=T$5yAr=wkP0~2*twr`8v>n%B7?)5tF89Ad> ze86LJ&-hqO=qt4e{&S1gD(m0aHd(Z74%v#Gk$fz?jQj+6fP6B%o%~AWYJBxGc)9vc zk&6T$`91I|^2Kn^O?p2|;U(lX@XDL${r?*gFy`nTeFHBf{}o5D33TpU~i-lr)`u47`{;5#B&P86G~@?jQA6)t-hxv;=U_7{*QTDddH45BX#8 z0QoX_yXI>A)degd6ebW^?x}9CLp1i{B(F1`6ciu zkG=pmJdyl%c$V_s`m2IJh(IAFJOeKyuYy;QzYA|6{~R89ThByg{2vfV?hV-6zYCs2 ze(-iFsgL{!cnkRn@bGy(1Ka(lZ8xQ(3<^v~LK*oScmw&paM$hn06uss`Et0&q`(>k zYREr?*XHX3w8G2o(ET^Kai{M6zn2B)!h5#=a0HqtAs*g*m)_AC@RkDIFNLSh*Zo>} z+TEI)#+?Y1=mBF9ypH?@c-TE!N5(3668Q#r4*55>Tkrp&z%C@TlJ{?u(#00)1CM~` zk{<(aB0me>X?aim)&4jYfvkJ=0d9Z?$nS>7-KV!-3{NLt2CwMj_V{ZMXy_BLj*pMv zJIS}gW9aI64}1#wpdX}ih2*1t!1aF>1&%{P6ZyIDF7j#cFt1*T9qQ$H>ypk$luJ72 z+b~UBqP?)$9BZElxf)-6 z;+X=gk>Dq9fOnB^fhUyc6WRq&C-2uTmCGri>;EVOyp%8jUP694ypsG9cs;p%PpEpr z^QbdXZ2#Ml5Z4osx$vchSCr{Bsk500n-4H+vOBalG}Yv4uXAHoCV zt?+L0-{7&nz7ta8_y0vom#75{V>mpMJRV*^eg?df{8D&5`E1Lr>;Ena)@^Mp5yN>1X7;VSMUhjP5vUhi2O}>CHY2pqwc1$1%VDd zVEhJ;dP<+rfM2CT$>fK_v&kpHz2s-xuCD(pC~yT58pv;i8&B&Kx(A+4{uta(z8v0Y zc~AY-@%9!1J1OB~cyyUQ@HTid`CfPy`9Zs+a^5~}k3SlL%02<>_&*+APd*vmLOvbd zPJS~y{26@#>dSAf@gt0A3M@fF3i(R7oBVCKkNi`31NryL<+8nR{nb<(E?D(l z5af@bz45$0zzgs=@;BhgwmbD#+om3YY)beF?j`>P9w7e*9{z$pA=e(MXkuTt#vhMB zUf+Q7Q{aB`3*l|#+3=Vb^?`4Nr;;yJu0DUFKJ|K~?2Q+yL9M?bdu66MlrRqNB~Mar z^^-A8`f)E=?tDUGYNzyH`66BaU#|jIN51LO(RP`S5%Ieu)YHH*%B}WIIGpyP zeFNIJQTr`U`x(;z(fzRfANfND2=nWudqKH1fN_;1%*Fth@00ck)ILYK)!u{l@1y*2k;8=7Ufp|)wAsWO(P#2J^hb#6rhBc zm0JmkZkf=2d`E=mUvXcK_><@-Wxu%Rdhu-d6vNuI5k{NVzuNw@RKOkp9XSaT`bk30 zQhlE|9qu8&1nwhuE4TV@!i28CgdXj$`nB)>Q-bwXY4(I}kQF%Rs1w4(tKom4qpt_b zL~E&^U*SRWeuL1@jmzZvV>n)V9Ud+n#VpfTJQ1Euex`D3qNxQk(G$_nGidLo_OHTg zdR^A`9s*sx0efvk~Z>UQIp&-b#K;gee_`SLhurKtdAvlgjOF zd9O@pI&Ki|f*Xe}wrX@olJ3m2zum^q4e2011f?$pFWoqfrM-Ldr|} zM2}N$O(-Ku1{ja_kHBNk6wk*;I(ML-BJ|_zTgH9_65r4V7#1l57m-hZw~(Kq+?tSk zqzvqQv&t&8H&$u=o5ltN67_)b4ZMSV7d+}sts|rVAu`ci@)7WE@?&gQ*Z+AndPip= zp@w`a+*qx*zX2XYem6Xsd@(%J@}Byu-C-F59!gjP_mh7FZzA6cH`eGA-2+eT7-@Cx!dL+r=@2%~`l_aR{?`4e#0Tl&gYz>~=L z;}g;yxD3A;hu^8M$nE^#d8Qm@&hfekfk1}%S^cd#7{*$BAlZMZcoh5)d>}dTT=AE2 z_^rSPk3FY~zkv1`_#AQd6!G6o%%}nZ|5*}nz9OjupJMgjEdDV%>Z+3!RO8akc{j|b z_>gH+q8xq~;w6t+0coF_Fa7+DiJC14_~RuZ8xu-?PZEq{#Mk2lQi>0sCSE8Vnds;z zxN(K}EKKzK_0o@fk@yP_N=1*7k8YZV|6~a?V&K2=nND|#_-W|qGkm7gb-MV4@FMj# z9P1?;pGUj`6Drs$UVWnYhv@%PcvG(BYX3h?CS;twT@n(nmjuV-zZZ95Ct8U1FTwqj zr9xj}fS1}-dvyl93Y+XywEw>!<$XcVd^OgVIP1UG@weX&3^T%q$-B0lFNxmxlML*c zD-$}Rzny2C+Ai*$FYY|-F4!S%6pF9Mgm(Oaen!hgC*pUwKKm2D|K&YT0#{1^#yNjU zLJ&R=erC6<;EaRh9Z#pj%m2ZIsGrDxL-$kI>-PD_a0b}f8?d`}e4RSJL%qzl6~}!B z9rqo|txe!fmxay5MCT5*&Kv3_-?i4i)}M@TcoAsq2}t+}cn5g}JbInek+gpc?kE2U zUPu0|i9iDdI^b>O16;C#4)PK3Zt{unl(+SXrohcC3S5RjKKZq9ANd{dD)M4@6Zv!S zpg8KUs`nZKMx8#>_uw()&G2OMpWvC~f5D42SK}XYsFbu?3m8T$-1UF@gieCH$! z--l+14&F(g1b4l!uj~SNI{8d^4!mdk--19fC3xXA z$QoRMk4|#dcfEQPbc34&m|uiC6y~8kA^pqPqJNI|94X0EF`$= zwV4{1!@cA=@J8~x;9ca4;MpIj{(I`L4!`FSD6|57{@#FBlYap3ApaVkxIypdSGcE- z+vE2eZZ%Y2M9?Q-jXxaTPCgMHvr!-5On5f=t_^(|)}~kW zUx-pahJ>glJz*K#L%tfG`I+9n0bWDC1>Vxvt?j=HfyB@Cj`~Gg|6hIKFnJWboO}Yj zp8Rxp3;89=)%X!c)ED}|ZX~3W-wyYaKM3z4e+C}gtoL69Piv<8|L-E;ri9OxTidMZ zGC5qGUrLG|DHSTD_LG!b?fn-@`!leKTj4?YZ0G#@*eL0!nL1jg-0CRfBI)R6bTnhM zcyNmN3Gfjy(oc~3nW)_ACqVstXCh%IC3GSo@nRX^6`Y`|$H)L()P6lY>Psu$`?p!S zHE`@D(vNeu{mCPwA2XH`DiKH{e_Od-Qgr0pZhvU3bmXS?&%(Xrufi+Eo%5f1>m>qB zl<)<-ll(_`(q?_de=4^ontG|M*twk_F-|6$t+iL<$Ebk4G9=7G^^QGK5^}W!!$^ha zlV1V%k>3EXBA;)$b^YH!ff6LNk-rExzS38`O1ZTF14qXvSim3SWdSkNJ|a#$O?hwq zRZ%?j!#c-bwyF+|{Zk+EahEzwbjJ#tQWLJ9vVWE}48R zJeT|=cs}_BaBm;C$G-}Jiar5r{9EDGX8u)j8jdj*8HJ zE4&*0oDIMCNont;{>|jF&>am~5!y#tU&Co#P+Wr*V1OBpPZK{XOaiy7kKtOk=iO7q zV{j8Y-1~hxMAJSR};;^MB`Ao-~U#wCgicN0ag7cVFhdV zOM>@mnW-PX)kw4xytBle`}__4674UOT=VKkyQTA8j~Ah4eyq^3+_)hXxOBmI6U(^y`Ok^ z3HcfD`tRua|55~8+x3oS!?Vfr;g#eM!8^&Hg-3qx^l#N){k@7nN>4yM0MBo862!lN zSN)*-kMIWaKjCfUk>)X02kKn}Kk6Ngg~yPe2u~wF51vb&1ur7M8E#fl;64PJ$sdPz zlgl@xM;LKG=?kbu`yBE{c#$~juWArPz)uOC@CNemNm99X@)&qzyFQ^rc)aFn{4@m8 zw18n`!L!Ko;CbX;csY3~ypg=pa_joPn*w!6NcdS_K@&WKybbOl?}C?-Mq zuQq{v$GiGDJxWMILf9|*gwo-$oR^30wuix`#39uSCUu38^{Cjm>v2= zo8ejHjZc{JVBni0=XU2=?f-rgciklJ#e>J}4)NGL@r&_jwr;O@;?3f}+0!?SgZs;4 z#Kf=1+TuLcTne9QB4EAu&H8)X4h%EgQTl7a&C2bE(b+P9^H$CI1C*;rxoY@6yiEVE zUHq8woy|(Afi}qj0#>ejz-a z+J9jCV57O8^p7tfH;s0+Z9+XH$UzXo1L-e9}B z{;#FL79=!~?}E3G_d8A|x|2K#ZtT=|#tHBk%ljUGrz4O{375bN$=&ce^4sC9r(Jc0akcq;i1@J#Zq<8b}&r@+C-OGyLdN5F&RC&0VO)8Ns& z^o31_$L*r)|2YVxQo_A(H@Q!_wKIBelbvxpj+&%ISwJDRzd*UY^Ujm@G0yvcIuY>Q zr5~^RPmqqvsiVVA6t5>g3f@MZ3^#t$D`8%YKnw-0fya~I22Ua{Qf{p*_6}Kqvtyrs zl1wy%+RqSI@BgJho(fnU`O#4pN}8G^9hFl1E8w-{H^4i|=fhncR)5Yk)&DF(Ai)k` zRQ1n`@Lcj$@EY)Y(mlcf@w;*O2#5mI^hIkAQcOA7i<7{qOoiU)fnmNFtvKpF(~E zJcs;lcoF$xc!l!b`l}s&83F-HSOX7|e+2I$-wKc3r!Q;|JgL`Z{6VKl>8A7s?Bj0~ zJeT}9cnSHr@Cx#2@CNcZr`eDH>O&zExDN?Nm%f50;IZT@;3?$m;92CKz)MXEY)7D$ z{112w`QX!~axs7E6FmZ+N`4|d2i~*&&qu&V2{Yj}N?ut@{6t zCy~D)5W7$k-X0(sci_pTf4=x6+*+O2DIEnc(NYZX2Hw8gK?}QVkUS^sz%}MV)!yFz zn-ECEOr0l}w;v=40r#;4O|j$KRa@M0e{0JPgkwFNc?qzYeb>e_y%%#G^ziHy)KU$EDzM z8-Y_0$X0G$8}6izZiRP|FN8<`qc7k|<<`JK^uGrE&pp$2_5S}yWkzQrFzqZEIEgyC z37$$`2+t*d3|>UO4DPqxslOV0H3D^%&;V~C-vaL>-vv+lSFc3Bvt?nqecc*A3W0*Y z0p%0m#pI{MYsoKxx0Ac!(fjoY-L71XukQa-;6Ws0kv{{^Bd>xNlLz1xS!0* zCoYrrr=g#B(y(Hf9!$Gj_^xI+e>jVB&6t>1`I19!Y2el&KLEAUaw z>Y%vuaoZtV|2wdi(zZ?g{;&NoI!sFR2Ua}8dJl-TGMD&f_#@wmXN(ZP5EDJh`pBhf z?;9-cyhS7G2l2#KnNS2yP&x39O?c|m9xh9GLj|nsfN|f9wZXX>?zCNPs1f?ha;N?% z?TvQ1Zitm`jJs_gW@HW5+n=L8(rNWyiI@GxJI7y<9T;YKD51*vtY@vPU=UXD2RyM} z{4IPD!Q`K1#jZES&l?~!@+-G4WKyYr^Lr$uzAXt(B@%y;j@W;jT*Yb1# zykeKM&lq62s{bhn{DVO3ei>jP{0h7lTy024T^P6uuLY-mEA7W)C+&s@z7fwsKT~$g zz?xgzza4?57D;ec{0{C1c)u5S4yWVQ^L}ev`e|E!h5G^SHPYVM+sFNmfd|S0Dlnn@ zm7Dfqc8~;O5cmNJ+|lv)Ah9n@+9#m>1^Z+G&s#F^0C-fFxc@it!v;v{?t^!XXXWL}Ry$JNJCXIq&77GvFf!a8rGN+3Lr@iL1o9{y7YvVD=#}3)^@h z-uvbMT?T$LOaj-a_kP)xqk*4Sm-CkUUXu0;(a)$u#8a(vzWSR8UuYuW#^tkf^XQ5p z^1R?nGm2^3j~*)R=i|iX{HVn>@TG9)`NdM()%9O2I*P>rZ3y`2OgF(L zulHAye+6$LA9biq$b(L;4Wcc6U(`M>a#gL?+B`#JRT&=pF$TwVW% z+V;~`f>pX=>gXo8pZp$p4f&(+0J&eeJ+4-NHRQWUXr_eEoCJG4z5lU(6E@TWt{g5$ z!N%6Hc4Oxa$YtIrSdJNCbu`S#Aa^Ubo|*-ZlE;E*^z*vi zey}lppB!dx%yl>XqL1Z9$1HKv7&RHQ2RvUX}J4^iCPcS_W1W;1ug`fN2lG&t*g}=wvM%@IR=wGDO&c4TeTVSD~Xh2Ux+wSaAcb__+hLUx)TVYTpRo8ENXh0kA)YwhV`kxTJZ@86j8!tcsco% z%I%xUC*VOy^JxbJ5R(=6VVEPnN(9=xEE*RqD;KT>WgxlWPx&ii_w ze_7m}D1JZs`Si7Mc7;0NMey7|#7z%%bVBNQJ0T-pIywY*M%Ip$M>#)A{Si9aFiNfi zJf}+g8F&^vVYGPDY2r~>@mI>NQ~vMe_L5BF2y`?mMh0lYgr0?4KbsqB=eh!=4pOPF zhld}k@4R=x3p7{z-@__k?L@IDGSg$Qg3a)Zv&5Y*9E+PN+qg{Y$S_WYH(>AEY!ZT2P&VZC2gzr^yWu_CKMw&{l)kb@ zt>aj2nx^w)LQeE)b+}r`aq14)Ck9{>w7@ezlT%h0eB>BuKUr^Y8gHq9H9$2D&=1?V zgFGTu+PhFW=l+4I77%LNFT=u;X<;?CtNZ`y6xe`-9P*X}4DdJFw^RE=u9i&}Hr%P1 zlp+=$V|h>gRqP}Lk|^PP_!ROP@NDutcpkY4uju3U_)n-nsM4)gZtbP+i)GuZV%dM4 z=qS*qBP%fI8fovnNZNlP&5bnW*7>9TH`!NIr}p2xYt-xicHmb%;73QnOzCJXI{H+( zb-21l=q3FQ-b%g~9(K6ie&8(WC*g3q{y$s=tQEVmWZ;W1@GK-`Qb)JJbI6O}VbS`) zhrB9hz{DBSzw`bB!;Qyjca8)WVc^?wO3pxn<7-z*N8Xvz{sNRVvPRr@z4$vgE^FW& z=-+vCHOH)$gdhfR0-OI7Z_1XAR)xuoMoye)S11+j)y-7<@BFdyoUmi0{))#&c=#yY zZny7vMKjS6|$QCk;0qzhpRY^xHw+_Dw z8Xy^7M}85!nSAW`qvf#QJ=R*k`olK6)Cug7^MUg=9P3Bv|5G}ZW@3Og8sKqwC;9UK z^n>v?AR%(3e!RB8)4CzE%>-Q+`NOXZ5m$C)Y+YGr3Cx6X{-zoilZyv8~go~oV) zSbxr|U`ya#sGNbz_ByzMe!O;;y6J5_>Z+r|^kb)(j#sVss)SGzin&(KjK*!UuMENA zG*h{?Pn6Qi@|^Z%(!L1ox4_*`+in`=n9(WM$pF4*CE;xB6K}$so)dou?UQowVB-_- zgg*`UmFxXPUoY*Op6}a_+WyZYkh)X?&bQzWzd;gQPl->(0JGqUesSj|n__r%sdzQo zPrOkoR6`Xy!*c8TzhJb!(_Nwh*0%9JE*-U^qiT2n1K$S!74H9ky6!%(%K85v_(hAA z#c0@9!@)3&rWT9Is;OZ(F_|o#G#V`yOH;7@w)p z)G!=$*AD&hD^*uTi-%1u~9ng^aTV?ccKf(HeRF zuvhB3Syozs%WSm^`^~``Eu0boKrJUIg~UX?I8m#|C{tZz#8p znU4;cAKps76W&d}7v5*Ny8nbeh7`*L(Z}nTO#(cJd?dV*d;+|U{A%UaRbaHr#!gc+ z2j}02AO%5Fl&mRwzI2HFLOR&ryL}7X4{yL0TH&5ArTvTWQFqEX&UW3a?o`kJ){0`k z(u03g2dmUww1dMJh#L;QLIjWSj>v@fGmc8r>g*duvQR*nuErjqax=$plU0 zx51sb%gm$Ki<8lQRon#c+$aOt9({(i zclg9l!}Grj?%X0i7|#dhXLj(i1Vho`jAZP%LHs`4S)PWwUKLNm<@Xod^P29tXX0@i z&;Rz9>7NMtP}BJ3WJmC5*}o>g105VA&o-;Qs=s|tehWdsF9S`%&KxPy!TG6pG5j95|1)v>D)*2=tHFEyj!9gX`A?16$ z!z{Rqyb11sUnv_ihTbLP1mO1NSE1axuOx)-AGrQjBghB^GSW*JsA!igXf>{mvlq$) zu|JCcjfo$y{U>qj7HfTc56>XaFc--{MF`x3rNfhOBXvy>&c`wS2j00yCa9I>Mqa7x zET1-Tn{w+A1On1NfN@&kX3-d#z+UOucgsMfG*G5;YoH8jzaH%?seL27j{IYIi#Y19 zcJUp8F6uBcQBFqVJK2GKi(LTsz_*|hZ^2zV_4Ws!EaL>=Uj^H%`L96W`JZ&yi7)FPLcv8t&0{s+Txu5@U{4sNmn<<9fO z?WLfNy-Q6ubRGuz)2n6ftQfC!z;;ug8Rt- zQEqLl=_*<1Z}#)gscr;064)oB8yS>w0>QxZ^_Izl6Io#Q(sj*(0u&_O6NI!*Ju80ry=iZeEO&qw z!IR9Odm@jMtUP$q-7f9t4wiu)47z&$Pgx{EIVRYJ4k;z#XP`pIFOh*frucZY_rjYn zj_p}XTa(h1ZJ5mWmI;$#u*$anCK{C*lwcD~o&x&QWgNh!Sa`S!H}1%s)MxyC)~a|CfqBYvP9b3z7rn1RNTI5W-h}xWxDT#2cE&Pv_Dh1=ssC# z2CeiOcrN+P%B_W_JR=j><7`9wB5MB)yxjI+{Z(;(MbK^sIQ|Eg%Yu>;^<#Xba%%@lbAJsB%Juh-_K)Sell}zx)U|CTH+;gw^eeh@DJi!s; zWSl0CKF$!DATcA9Ub>TGY-W-6wv-j-8uj9Q*RSeYsS~{fh3#+%FX^30Bmu zzuH`~3apa4H%SNkMo|F|)Qj8qiSIE`GaZ^g;CQg3eYM=p|v}Yj^+? z*gLC!NCqHS-lz)bbcls?9X7%c|>-WK?}MVo=ctwFC@PW zZn`OmzgTwQ!NjMaq%OD%ZvU`ZEj)$V2jC94dJGMIG+rX(H;J2uUD$&zMd?139nV9D z-SF5i#G~*GxGh`SJHFQamCM9kZQ}FQtDN;wdbxNk#+MDKkwG)|5wr>cmv0#f&6252l=<~KJwVHYC-BUGj_^C z^Q92RUfl9MyVuC;zx`G2(=U)6q->WC<50To8RFh9ar+C1W5>$`MKr3;M(l$AYHAoBkA+cNYxf z6Xn*iZ?`HPs=uP02m*8ne#byA43vur-hWgEiaJd{hdSV~oqmH{tvL zKS?_#*wlp%zp5QXIt1~nq|_PxvQWGuW846D!|e$+!M$+%J>bJ0lW}~1<8j!24|uK$ zg4ZRL&JE8ZKlNPsa-HKJS&;qRGcV&I)_uU*;Fb=Rv)#Dcx?@_OX<`!`-5-ImJRr@0sEXdpuqB>#-h8d3s{~1Q!qjF)4l{u3xWvaR>s#WFY&QZZ1wb;}Ct~dU(-LaeMrU>JV6m%yZ~k zx&Q6Lv5dVL$1+wr*stHKlv~Ga@_CNn+U4sQ>J3X(iAX2o$I7i+b;c1g&Nl4$=qJQu zhl}Ug_um-^JaH1(&vfhHP4M*?=vTY_QPSS7#Mmcg0x#TtyV^7C+R_}v7rA8&O7k)zw=dKbts??9*SKkCgH4_J_>H^S^=X)eaWjDl2Wmj^&F*hVhx@ z>dqA_XK(0xN5|eKo&vX@^%~*EF*5N!Y~XL(%@Gp(gkW5e3>1J%s_F#yCWy47{T8_U zSaJJr!5=VBZsA_s!tF=22|*uf{FCkoj$qnfc3+AP-RK~(`s^6)r`LkPx64ACaIV-l zmce(38xC2J{mAtdJQfwj6PIbEE|3n+lcmGkI9XP~y-DKs`}~P_N&6yPX7*Rh2QQR! zg}=&u{oSg)I_a#l-THVd_)o+5NL?LKMueaL{YeE@2QSXjgV15rv*Jx-WFY&F`LJ^9 z##K$1*|TULKzsW^=D_EqeS_6rUjJlH+} z&-0%swnkDFi_pzh-Y9rQE$II{*{$RMsS1KCS|}at8_US`;!g4kxSRY3 zxQ{&Rc{!BLREg`9o7Tjgi)7-mL9(^4RA70LDQ-W>jCw)b3%8$$D&a1-w6~v#_Q4(Z z=;O?+lLd98gg*b3iMPy`80sZ8Dsaz_EfKe$4_4hL?fvjp9GdO$PE^7kXKA^# zcVWZx?fb7!1=eRgB_s9Ecz#0%Cw6c--qN^jx!eJlc;r(NCno+IE}vWu+!>42j{m=7 zulj5-)#qSVshy3ovqcyv2hV8iGtZayj_0Ml6E~n&aDP`)7T?YDO7;3juC zIa50L>!d>m7PJKJ+o1b)>-|ABf#)Uh-8hG;tIurbKIo=lADb>c z2>Ds|IUyZFUa}vLxl@}U)P8D2SJ$66VxayI(tdp0{W5`Tv+V2_+&ORHhY0N-*^lqtkI#5$V4UFVkA2d;9~M}L z-S)JHWe2?DNA`18Z^ZQ-b+&#>Zh|`oJUGAcDT0)NAb8q!!86GB!gI)nY>*p^i#!2d zOg?ghDIF>(n1Bv7Yyx zy%O!WNc&arE8)gg@p$v}Rzw_oL!!c%^b_V%;k zuga}QvDi`iRd9e0ucFpMt@Hl@taP~wtPZKv;YoDJpq=eQ`%-E@>_r);n*6G{Qc*W5 zVJ$0o{q08JMKA;lnupKv{N%AEGLSE9AgjwXxUowrVITWR>Qgi8Z1056!uZE6!tek0 zAvguW#zj~u`La@RCnmPr|G8M)|Gi9X`(iiz7jgUD@Tcw(FY3mV%t%bUM+Me%fRQTq za0h(e66xUTk%4Z;J-l!!CcsHL>}cummv!>0ld*G$v~R>a7t2?Pd$G_H<^HE`wU5a? z-@9%^aD-S)>`=!t(%J69TP*J1WdaAF^$f>GJ$== ziGE4W-d5@`0^Ux37QCN)JUo81e);9VQ-f~TU+rQxf*k6w5MD(7AlyUlh1Zk64EKk- zHUGN^dcp(cU%^vS^&RxUbIJcz9z10KN=5CrUS_;3?!xa{x4+o+hH^E(dgp=$@~gn| zdh(s{R`R{@F7hGuGEP5v0z7sMJ^znHkT^!)@dS7p`3^jkX8a>Nw%;E-<#IVmQ&0(f z24>8jjguPf|7$=0KZQG>2PdQb_W9X(zt0D^?~KplPUk#OKI6B)DWwgcs5GIyy^V)( z2Mplyv+sa6nYh#W5!e%t!=28Bf$T3xd<6HQy}h$*?K>cjvHe{yzI$cIO@B#+ig7>q z({go7Haq{2V6!^n*2hHa4rM)`_lYMA5`R!zaaQm~XBzg73lMyQ-~Z{7d5x>pv5#~Iyj{6o(U;b!=x23cqcEhtxcuoAJ-z5x@wjP?O)|1LcB9QywMuP~4Y z6Wh;v=4P4LsXByztWa)E9H92j|492hYClW4)!vE9<>C3mNPAs66i|mt;lN-{>jU6F@{X=EF7m7Eb!;fgc8t<0* zj+ORuw=fJRK8<(cWV9b-_ToktI855ZP2&UHx!kypZ^8sI*0Y;hQ0H-&05_tnWpcv_ z3=#hWH~nRntM=Yw#BaekpWue(M*9olqk}gz_55#Or57W3*1Dsqfn4!2(1o~VuE!0k zd$J?g(!M441bw)XGDiQrf6fzFC^lw)_skQ@t!GT1^^9q~{@b_G4g@WD__Y1FCuN`} z+|lf}-Q2cgXDQe~hjQ!II}Z!RdsfDA)iQBs*!b4`hD!y(9i!CtIq^fV!%*Y(HTm>>aO5C3Jjw7&$t7tY`2bK)EOdH?@Hb@o~da*mWkV1EO0iS4Q4<1xXX zaCeIC&%7yDfsv+Pt}nyW)9C&GcMud&hcDqR!fJGN#wxJCaF)$E$=2zds@y3&xtb7|KTKE4)-OB+us}B0r#Uq_IFU54Xb6K z&QqmB(ZMoviCSr-m)%E|Td$Udw6k^aO7hKcFL|rDX*5u<10DS2d*EHi*h0=YFbgwUYvAi;LyaY8<%xxlFreu z`&jD@4eQ2*_V&adL~`r;JJkMUkvd$tAOF-VhpY)Zlj+sxtk1}0`C67ExJ0=K)%`_P zDAJ)EqdfTjf77|LW4jVXDzJ9ohub%ti{BRaq)B`GtK25sIA7e0lkpwpR()g6)31(p zv~QZcE_nYj?C(^XxJ4!iWXV9G7a{dqB7-FzC+><0ZqPUdZ$4*?6@Nk4cq~^ALB>S! z#b`esUz&-<#_H_n|3>xsy>%=z=ve-P&-?x7$w2lkHh|Cjy%&hvKXCMp{o;fLeT@Z8 zcuo$@xm)Ei)d}BdsvSo)|N=Z|xq%XlU$=`wJkhjCldy2vY;(k(31W5@%U6LfcEd8{rP2bXxy?f(^!K$pih12#QFrI=~9{CI&>Imy^N}p zG39b``kkv}MUZp8e!WJw$UuRcWCHu;c)W6Jpa8YM3Z9y-k8>lu zeZXb@1qezn&^s)L*N{I6Zz10R50Jm5+&cCdx5)C4YtEiyhr?Sj8hGFmx}w* z{_mix=l`brBq+xYrf!pot7+l_<<`W`#nRrs3Z6mxE^7ZW+B+(wy?yzmwql%e<<|Lc z2OTO1zFcPL$Nm?17P;}Ev@aze4sRkq1>P6t!Rv1tuGHY_xQ z7P<>wNZtppCO_mOsa(T&Q{VA%2%4$G+3+6nOnCGJeVl9H>EyS-D{Z&$zjq^OwS!=x z48sGDny63k9K3-1Rd_M^`|t{Kvjag31;4`k$OnBarHjwh7j!h-MScdnnEXO<(Gd&n4duFCq`X%gG1%rE=bI zx8^?zK|^?;{4}_qJRROmeg)i^r0@6!cs%)h7hWbziZ(+d3dj8_2iAd&z%;8(DfKqCS<%nK2X`jle;EIy{~H0(c&|6JAa} z3tlZgaQ)qhpn*CphX=^3;RzS(JKF?zl5c_MX|Cq~96^Z|s6WdGuO$Bq?j=9;GbyQ$ z`~-L-d8*~X-~V}uzJtl=P)R<`o`8HVyo1~gPrg(ie2tp|`w3dW;@mpljFL_QntCtnCRrsx}cP`O-9 z;q_Nbc^(}SsY4??oBShq9(gCckbDok#CCiBsCFq`l^v+XSRY5jYsgQB*OOlWZzXra zyUER2Du{Graic>obyxw9x>7G`4LpwgRd^zKi@5sv9}2!k2Pb(C+(rHmyomhpuW)B1 zPlS7dZr5Lx`dkEF>Tn6%M?M|iL|z2K>2!j>{WWH8{rP}kKrlg z-@$Xqe^;*NA7T_!5dF23u8e#HypsGZcn$e@coTUJ+|r<63>rB9FuPbNPXo=tuUydcbj^G`=m78Y37c@eyhd?~z@ zd=M}`ov=p^iqe( z@RS?$_S4|y5TkVL`Y z@1%5I@_6Nu4#60-uc!8t;mzdNikn6o1#{4$hx~4M)Q$QM9)>57KLbxCuZL#`-LAhX z_j?HPsl(UsQu3eS4dlj7sa!AlaCquXVH>dKKLtTSc%XbNyqY{)d89*dGuk&(`$g~$ z@&}cx`PDBVnH{zwHSub6$R~dhUQNDLd87q(qJ0~+-vjTOP0#;PT__!OI0_zBpf5BD zoEecTSOCBGNmKwbrJA%6khPX4BeAm(O$XP>~+$h+XJ z#}+r^QWNh_$s(eOI*)8WnJ7r;Bnoyz$f3eJBQ zI>Z<0m3RQ2LH-oHlH3Q6nx~Jm6`n%=#gBOYFQVWFbnue*!@J23`w1r_`H67jc6~u( z;IX&U^M4kC1nO`dJc;~POnAwBeFIbB(Rb=z0Iv&oYyO1@QWoeP zDwIds*(+%8ruOf_>&d@@$Cl{h|D;^aul@o$1%IPMA^BmyNa?)fC%`+&M=OuCfxH0^ ztG}wmy%;D!13d+nqS58=*`WB!{Dl)q~2eNes;@dR9EovK5m9rRnU|G$oc06Mgg5Bg0?+C_ep@<@kZ6xs)>6PJRbGhMqH)DGzRJ;QW_@zlaVA)L|<;mHcyf3Hfe#E%~4D z7IL;feF>!A+E!js*4NmJlX@`>;w@~O%r97@x;2OT`rVI|y4z6Rb#{u;cO{C#-* zJ^BXz8+7&jpGLti=#WW%K(ACNpF9p;M1Cr~iu^oyo#mnWtHXa8f(Gi~g8RwufOn8D zgLjiZ4mXwzR3bQk9fG*9z&ah@g1g8+g}ceWhgXyL!5hdA`5n*y9TXh*yOi2kITADZGSy z6}%$ct@+m@s0t61H^LjpKZduHe+Ta;{~aD(u5T>556}PU6pTx_ma263FKlFwIeZ+M{o z>U{B{Lo;=F8Qx9)E_69ppXm>;aeg|3y$d5Cl)(Bl@Lu9`cjnb>wOA7V=Bs z{p8p8tLJ~a6mr4HKbNCJ!bAGbo`hGBZ-n=ezYWiLSRbbi?lmdcjll5e9rnTF$%p+d z70MuYz+L2{;f3(f@t>rENR^m}4sIG~DZHNiQMls~eFN*@#k!luW&~||U~GeTk#C2` zuFxm=4W3CJ^^a7@Nq%(D)$@N51*fBfhx`I~HMtYsPCiR{q>4U-_Ptj7Q2njT4?+A& zeP=JhlgZzKXOp+Xi^+e2SB80T{(lg}SLzcV{;!lSk311xNq#QeM}7&spM3hic>Z@h zs!v>m4w>Xj;YH-D;Em+#;Q{hSc@dGvhqk3a-w|=wZ8#g{J6f*`EXCr?fR>uRgR#6Iy?#QAm6Aw(toCAleUxtuiIDBsgCC&P$HGh{1tPYNc?b>`plE_nb8IvMG2wdxxX)COX)p!?wy){A@Lr@%i~3q|F^>aW7z2Ld#eeJu!2=aN4JFC%{j-b`K(&#TtQf6qivLc!PY zO7frKnNR5h8H26=A7Ye0t^06zE%_;Mvw?!K2-?WA;a%i2lt;P>mZ5$0YJEXf@Obfo zGb&msQ^UO?UnFC*Uruh(47A9awFu0;#fk6yvM$WMo-dG(!L0M8+J!t=>z zS#CZ5`zW{*9XiRE!(*S(C$5GklW&4M$+y7El@HWkoj#u?xwL7L2Qj)qA%b{BwzlVbJR1oQoHWLFiQ2RUJ z{p9z;GuG%EdkkJ|d8q#Cd|!{Cj5@pyuO!^_AIJ47nlOnxG~({}s#k3rCH2Ut)RJpKi}64${C z$Zv(0k>3ONkeihVd=#ux9_cFh2<_Xb{kQNg@?LmcoxXvCV}cbjjY0~Jk-(@RKNIdH z&ww|OUj$>_m7j`51Tsd6sfDzxwfe3a&$k2J%~#N7~t=Xx~BY*TEAu=?mQq zPv1oE|8GN3N*%s|yL|dUzrq{I4?I*V)JlFNyf@@H{z(YhUeqTzAKpcNIox-j&fK3Iy-j;EtT5_!>nCU^|()2aP>crN+t@O zguqK3zJ({gqA#=;?jk?0KlFL|5e#FcjAQ=@hF48YI}Xn99u`z&(u%%9&_n(c zJn)*nv%lf-4Z0t8gdBnl@)O`y@X+y3MNm&2CM%D$gIm$Qo!YzMNt^Wrt$?TLu73Y7 zf=)d!8sO3Y(FfY5Jko;ppnW2>j~XtO=qEoa=<4}D>2-aABy=bxKObI2emT63d?vh& zyjXc?1EKn>)8a{V=%)@F;4zK*LYv^7-9$rBH9=weFYq;s5;AaHY1zt!#5ne_aWhn8xRyyhxzbE@^a;oPTmb@Z+xn6;4OG&mlL!Jze`AlEXxa08rpFx2W9dgNUfR~XM!+qq-;63Dz!=u~i z`M(Z9Vw=9wx8RxNpTeEw-@}W@`{1o#V0`=dA9B2uw8svD_b0VBHSkn&^A;6EI*A@ehg|CL47`-Q9^OU%9z6QL`hva|H;oDkeny9Oa>F4N>L(u# zZ|Kk`I0YUc9}Ca@#%gcZU;Sq`f~sJE`m2Ai5$@LfFCZw{ zp-=E8ytq^MPvCy?E_f&TAMm(u^>K!tfam`T3XWBQ^#IaKo&t~iP9JC@+(SMUUbIth ze>2>@lb-)e5wuf>hvD7i&%&d+^a);pXOg$T3qp?L|6c@Up+JuRFYsFO15T6*`N`wp zQQzweIu#yEex8ZILBVD4baEFwi~J6F4*4>;i~Mor)@2`d{>zTvM28aU;D=X|e+T!G z_rm?;2cM+fZwBU1)&p6M`sWno*2&mU1I>cR?9xj;AD%*94$swG&Hp5VVl6O?jqn!o zx8YsnZE$0^zM$Rk6!LwRThIS)3Wg=hj(y|~cpLd>cz}EoJhoe3(6w-f@`3uRA{Qb^ zrw%4Oi+lww_lOa4R9 z)$@NN1^p_BH1P?iO6mO6J{8_YJ{jIeK23RO{80VX`EH^^^iTRBSP|YKcwNXpUPb#j zYTp7+B>x(o5$3`9dl2M=1=bY*!pq2yNDA9Q*n-a4k5Ai=-<^c#|2mrBVb#I9=eLnR z1MeY!8E*9Gm3s#sL;j_5IRxSLS5xi_1!3D#|9R|bvY-qaXe2z3d_25_JO}Qv-JX9o zf(ARl{0rgDYs`~EdF0Laio&&Q*M2CySG**n1!89I72*ky}13? zbMJ>c;3uK|4{#@ZsO8r2&rHSybuy6scR<%Ew|-zC7e6pye|!G_&^`n0r(lA#Go{q| zRJqjh_}~VbF!8Bqf98f1_4j|(-|_RUlZih-aLh*eYIXn}GEur4;cisIUeMdhtv@)v z3O_Gk|H1J=o8+(RddKR2A^9TZ*1WFu`1`-tW8yc19flhFFwo)f1AH=2!Fl>XnL$^D z{89eau>|aQ98@vgABnB$n&o~u0Crap?cp7dt zQs6_-O}+)5^NW7Dw!uq&)qOX-jC>#5D{kNa3}e_?a`v`U2M4^1d^9{Zpievr?jXMw zo~gN-zYu{_3)H0vFC$+8Zy;X-?;~%3C;X-_berYY^M4Wr+tHzr{5Nd;XdU9^;aj-1qd3cgA?9GJ`0|@N8j0wli`iz)8HK@1#=Pfk-OoEz532p z!i&h)!mG(Q!yDnDXV=4m&WApZqs?(?9wIgGO8buYQ2xU)_&_=aZiX@Ax-({ab64 zk8}jx)Zq%a(}=U12LF8n+($ki-b!9>k8itu{GUV+b$~v>M!19gZFn+y8$64AH{4Bb z?n6*P!LU>*X#=?f-b+3j9)F;|fl2U0@@vIS!$mkI9MCl8JbtH0XuUkGxk!=dL$N%P51 zfLD{J!fVMV!~G%0{L>Khg#xu2^)VNoage?PH{40S5?)Ha7G6WX*+kGpK`Y!(z60J* zz6b6&SYPPibER_W?C*w`MK~y@=GnZp8qQ;n1K#H z@;l(hA^ODk!4t`!glCd(g1eLt)L)(LTM@Xa!8Y;?#YUkEQDe-K_x?uFNqzYK31Vd^V- z7eOa=_zE7IpttXVCy@UO&m=$M0;#CecKi6BjG)R6g7+uGNQ2jsUkYy_zaHLAJ`dhY zZk8d4Jyze@WAGI6=i!CqZ@@j|ez=c(r?_eODcFk+edI&NN$HY~(-)cm&mtcQZzi7r z&ph55$F9Hn&#Mu*f&uEU{#5`kAuokjlY8JT zd<#66ybWGJz6)L)avc9Y1U;cZj{hMUQo26!?3Wz!S+gz_ZAk;DzL$!9C==EVrKjeH8qO z4u0~O2~yGy^5fx-Q}qpuf;-7Cg6An8sJ|+BE`n0(Fb7^mz8GFZ{s`PpUIXtKaGC!# z1V)m+gAd>i@^9d|o~%u5tPQ$){*OIV5B`G=DdZo)v&p}M7n1LVd&q}g zB$cbPJXC*m`5lL#nL3PucaTql_mWS8r=O*7>{fVDm$z{|)N!>h?3f!CAQz+1^* zQ?BM$KLJI-2j~ztR^RbA@HFxOJez#b#ZtK<@}uCDW9j+-Gz7KOAsyaIeg(Xf{04Xr z`Fwa^$Z`D35k#G*@Ayf0Ecr%w2Kn3YBJwu4n|!y4pq7Gta6kF5OQfWI9> z;aTL9;HHa$X$XqRZ-tkWFM(H+uY&u?pNF@J4_tq5BIu(IpTZN;^_}ff9_fyG(4|tL z3~K*>@IuYi{K*LFw7@Vfgg20132!665gs5ffyZ2+Z{PvTt>^!E3Z6!XJn|ReCFITU zGV(9s9`YaIUgZPzS2vu$5%{S?Y&K3h@{{06H1ez9IpjCN^U3dmSHMHZzXCxmbyy8=Ab$yNjMq2t4!o4S9bTooY5au1uLs6I z@WKiD1czTPB`qgUgx8Rt3vVI6B4EK|N2k#{R9d2am3mtNWRL&9R!TFCxkP#MGm*3fN7x_i-I`V7bQ5WeG z&xNOu-*W|?|MMw$6dkI_*Td_{-+=qcKY<&Q^aXtnPn~4y!Ji0nsKYR)l+Htb0zC6# zeVj3H7x~5T3ft}DKOI4X9a!~OAM@bt%13aDFd>cV*w%*}$<&j=q ze@FXDY9BpCDpXHC0^US^mbhuOQZODJy2*3k(U<89oefVXUkEQHe-K_Cbi4kl)LsOY z)Zt}#J^8!vUh=Qtsh8^u?SU7EyEXs6_5|U9@*}R4l6I4y43D}(pCAn$M}8?hjr@A$ zYW^XHi-LLR;2|%Aw~#*uH=O!{o`h7a5IB~gL0&Fx#aQiBJ$JW<>VK@z2r`KgZRMpHw%HEI@}5GCSMLWa`c^5 z!{f;}!BaF>^KU_rsRin{;lqo_yW#cZf5E%R54~C{8X!Nxa_jj&;c9&cspybKJ{g`# zJ`L_9p9{|;cf(7R57b|scPkN8QipZ$TJqQ7jpQH0{p360-2*Q3|AD}ms#oHWsZzRl z^5fy@4zr@E&s0i6Co+zS3FnQt~_DKJw-8 zR`P0iH~A)U(};5E6K_EW2l?mlO!98Hll(7u9{HiyNkwadZr5Lx`UC_%>W~U=C!Y*Y znyGJK8oY>nF1#Y#t@+&us>1{2E8z{~YvFC=o8evLt?;ND^o8zFuI5)ifJng}bjTzh zoF}ErCy$4Bk)HuKX6X};gQv}+=l>}PGO0s8+)Z8ruOY91HiZ=~>DFCb5W7n>AJ zMBpKx3a=x-8SW=9h4+#_43C>D8wg#0&mu@gU|)W(z>COR;FaY6h5N{Vfp_R`8VAgj z(sk>B5eJXDRWJ3a@Feo{;F;u?!CmC8psVNqItuPUhgR}s@BsPa@VMLbh1S8-$=`zK zS{|yus`sY|@~Ol3@FMa)coq2}H%LWm$d7~9hk0=Rvk^3h1=jJ;g!hnN1CJ@vcYF&x znfz{e4!P$BJpUI^@EkgnlfMdYC4V0tAn$;u&eIqAE4*NysRswnlG0UEha=$)-$CFl);oL!50L*1 zH|Fc@56F-F8gYVh>lrhb+K(1DjSdPfLI?Mq`UKa&qZa6X3p}3uZg?uW2ks2IU4OO4 z=Ma=ohgad11z&(kCuPhYa%j;7;-<;FaVX;9l}3c zxLI7PuPA1=l&+540q-JDg(uvtkCO$@A?c@g*;N+s$jw9g(3&{)NrQ{~Oy`Q%&RwP7Bd|8oQ_VS#o1b;ASXf5DTN>k}VZ zC?{h9`3dkc^3*~+|2I)E86A4ar@>?I*C(C}PbPQ6v&dJ%^Y5oy=2`@9>aZE^C2xh- zk?(-Fkne%_*lr*H!E>c_eRg2gUwy>G;~vm=dp)-dA;_i< z+3*5#7rdCf7+y(U4zCY)YyN5k9pQm;AH0XW8J_fzzO#0C7I_amkKDKo&;O+q#Hqmg zyr7&s30^~<4sRfL!rRF6;k^&j^M46~1dqP63V7}#x_jZtD|N4jcapcjjY_*cj(-ON zS13>gP#*z!F?m!` zhI|aXQTagq)p?YKpp80Q2k#-j6&_us@9Z9UB6%e|eZXb@bqI0>g5YWWI^0G6F}##~ zC%l6E54ex~kUQ+>e+rJjLrR+PxW2Q|@O1LY$|F6t&qn(^YJV5J(4^o21ZCt;!M)_0 z;LYS);4#(u20n);!b8Wu8$m90_zRv-erT~&sG9r)crAG=%@4@ z%!Q|ryWtt+E8*GXYlE(y{|hPDj1EoYt?(}L9q<789=PLaeFKB%OXZR+57l3t@9_w- zslyrYT=H@7eDW#qa`Jq5O_&GgUx1(~EU>P>`{7;WPr(D^K6pR*R(Q;6y%Jx{$Mb(Y z1wWue8hJlFhdlO9DQOjXBD|G64Q_Z%eMQ*_vc0;y;3ee6@M`jMcs+SFyw!I5`1=ra z*+KCBXBf@!e)4vB+%x(@d*I3B#saC3liZ9$P)tD*+)bViuOWBB+sO0bz2qh0rjhil zzJm&M$R+o}OUdiu_2eyZKY0h-c+Q&FuD|-v0D{C|fcmR{MU_bDa>(Q11?0)_Qt}MA zH{7lHa}YF#2g(cJ-Q=apBfZ#EqkT+`UeS$k2YHinHUAJJn}Sc#p^Ur>-blU|-bo&P zmsGBwd;~mx4L$##g`jeczJu}b*tNRnz|+WQ!;8ol!jsq8OUZjo1XUFL3$G_XVxg3@iTq@E2YDL2kNi@&nY3Qt!Sx7I$>+g6 z@O<)}@M`kC@HX-xi==XWnydK}5Tw7L?_eZ6 zk9-2Wg#2o_m%IR8N505%>-oQdf``x{K>iHesM8l(4^Jk451vK-HN0H;K>gJT{4;`D z>R^;g=~~H$!@J2(fyZvp7djU19B`RG8$sSc5WJpdz)Q(*hu4uWgSV4E0gu|KFKA;a zp8r!R*n$o<$$x}*k^cja+oVr?#NATSJd=V`5cH6r2aopY16{5>(rdx(XkSh3 z%ivA$(D7eoPw=8X!FqTKc_TcB{A1;j7W6-~FVfqa#^A+LiV8h2j)vEfp9b$DKOdg? zlD>h<;V$x-L08ZJMHCdHLj(DJ@HX-%-~sXt@Tiyd1vSBwEDzORo$sF^$e<3plt(J* zP@KF@YM%fvAwLUV7UseE$EzUH1on5wdBQqa*X2A6)Jnb-URAH}_))l@e4UBs|1JtP zqeCBgD?H{EeS#hEB=S9QC;4EvoO6Y*(DQ#hf)eU*2E2@X9K4!*3fxDY4{x*GKK=_3 zblE}h{--_#gF9Z;cl;DQjob$>Am0ivAveE7P({H{@NV*d;l^wFf`;ECC5>;;{Zx1& z`T63ekww83=uk*L3tmpX0A5A@0KArbHM~CPcKubkUq%q14)4L!H|sn5FT9-mS9lfq zpe0hFx^TDVKN>+pc%b|Ycsu!p@BsN$aN|GvLTAI{$rmYC^A9mnDR>wi+~m)}a~kyt zUW1pCZ-Y0H?|`?zLC^pHLlFI@KEc6DrF0JR5%4tfk??HtiEwwwas01AP#X&5`kMo9 zCpY2!sazlV@o+PyNnhz`1j*!+ z;aTL@!CmCH!OO^(!t2EcuD{0+bW?{H;L&gE3w=v@q!+Dk(7u@3{|YbDT+M&Ly;7n| zEijDX@EY=y;q~O_!kfu2hIf)*XSwzKAE00^Iv88@9lPNPb&<@cJ7E?;@W9kJ+kMC?D=1UjR=f zzkeAX5V9$F8XfYiIwJU3~`=&>@X{Dm;(;7Py;yF}#+11>A3WsQ&7FUyGoZI{XLjcu!yGNAOJY z@8J35d*Nka9-M#Za$K)rfpz^I2X7%C1@9)G1dnae7dj1|LVoLVJpVf>Sb`4u^Wcfw^o`vHPYJqRe^u%w2%Oa6QFuOiE!;!?I=qhjBY0!DTl0U5 zz#kqc?}hi0A6y|PS4^wEvt!`t4(I4s)+yYM|Uu?JkNN>La z?jv6d@A`aRXV!Q03u z!2{&e;BlYm3%V7aNxsBHkVnBPcoF&Y@OJVy;r-;F!ec+x7qm;c_4FKe{>zS|9+DC{ zsKZh4bn+y4KKXg@3i51tt@yzF*CX&#hk5Wm@-lerXZp?_gC~(c4^P!x&Ho013@tDW zKfH{5C%m3~FT9z2$iq_6F7gD+t>^#fHhl*p(IJ6+0z8fUYIqiT0X(045xhwGK>gL> ze+WSpb$A9|LtYQ>C4Ubd|GB=gui+&FF7yA4pnV{av(Y1^>meTwPyIrl;1qZ%`B-@T zmwNkb51#+)DVTu{z2vvs6SwOF-3!kpuY#A7zW}c>DR>h>EBPmI$5;BqUGQS^Kj2m5 zLm!cf*1W~8OBA*EFBcBS-|5{(@&F~7{P2+9^wR&JY0uPX{fv5dfpI|e* ziu^-(1NpZ>SI_?e3Vuh2gbsazAuFVG>Ey>MkMu^w`DmXY7X;%DO>Uqvl6(Ekd8tdXd|cq3jR{xIGu z{sJEJwR@lc!>h$djGO-EHz0rG7W_^@m-tGz@E$L9uipUg6;H>DN8Ri9#;Zo<{C@;N zvlN_)w~JTd$o?eG!DP5&H%aVPM+Bk?Km)9~0acM=!l3F7s5vUp3tgTMb@ zf=&ub#ryCs@nJmv2X{dec&d2pZFX|yKg#((iJ;m9(O>C!t9Xv_>AuCD$o0c={kix= z#O?F1C5ZpYZF~owD*h;5E&dYTDLxRoe%!tP(%VAke+mAiU`l+I+wJHIes*t^jMs|K z!>fLAuiqCR_9ZxqAYqwXP==R@`*^eXP57wz{dm%Zy?^-q>m(>42tEI|@J8{^@z`J8 zh5n2uh{xPvCzs>8@2x{n;0E57c%}Gmc&m6mJ}5pPkNM4A=y^d8{QSQJS5uHI-h}6g zKZaL|zl=ADe}H!fJUo9h?@@v=DfkOd{N3Hbs!evJDdHRB>Eao9R+I<(??+G)6$GCD z(Rhvc>3E}fHQpk=5N{WMpo#N;mjusH&@0}D4~Q?phsA%v$HZ5-(@t*kci$c9dIUq0 zu5W`U{Neguc%k?ac$4^Pcwfjv&;JsF;ZVT)cM~4_r`z}eJYD=*yh!{Vyh_~v(gf3e z5BKg`Gx(Rpd5bcE|t6=*DDpU*Wm`x{u&DyjpzDJ@zxyE1rZ; zT95SKmY~90%dUhU_rhbAbNz6iZ|jV;t%7E5x4zcAQ+4U!KeR!_@wvY$ycZwf@4~d_OkBV2}@%|il2R9I;iQkK7ia&+ti1*_8;-BJ0c=-AMNKhvQ%eB}E zHHs(TE#j&8fOr-@>bmdc6HK^)SAxf`%7gtI2qvR~ z!27odPl$7O_8guf{w|&+{+03R&X~(R!1=#U3KAZ$BWe}j0`C*w1s@VW5RX~K-9Ry( zvWo8p=Mdyb!IgNq_-%NjcpKg${vtjW^3d~tk6Lb=O8jEHUcBDA?{!OX9|e=*Pvcpuxs!MUZxkQGN5p@^ zQ{n^n3C-X9yb!MyUx4?CUxH7Do&Glxq$RkGTks3F+%4n87Yi2Eh$xQ)vQk`i67#w)}d@K*6wd`P?tk6Sl*|H$+2Cn&c8FQ55a z@A1y{+yzbIgW_=y+sP%a?_Qsb=Q?isXAl%Qf%)5T@LusEd|bR7Pfce-s}Re+f_D(4E9U8|VKb36@e&CjKYhAil~YcBJj% z$#}2$JbcKPU|)hU@uTp}joclS8K3UiU&Hmea(xqCfQO&|qXflL(2ci>zlRTrkKl#L z?m~aVt6cZJ*hlT?hTXth50Bm0y-^yTA-)G*Bz`DfC4N%S&H2Apf=UV+#IMEM#qYug z#2?3p#d~mX6SJ}K{LSb6BZ9O*5cTyPo+d&JMg$HXtg^EP!icJpJL|H~w3rC?b6IXphaz0o^(n)nxZk@y5&o#MMUTCv@Z zu2~A!!~4XyHa^|!cL3Lq%k{_NX`9hE^!(2xC|@dmtEd=cI){wzKv?!Qft zy16@vVLV5C8D1#9!sB*w)#B^oP2y?R&CmZ!um=TYTeu54G}J)++#{B zhvsj_eJ?>ms@wQ!JXicp;J@K=SJN>&_C`8JG$5{qXOd_;R)i~Rhg#7D#z;Bni#3%vx-6u%L#G9H<~8FdRmn-na@yTsqbhr~a_y?O3}#_@!R+y1kk zwxdgl1i|OOHl8Cs7cUdf!fVA3##_Wse46urw*==>&?jDNe3rMGSKV%ZReTjbrZ3?2 z_-y?`^|j(Nc64>(>*M|6+u~#5d*gAL zk^2YxA4!lC6$JV(z>CFwyj(ov`;CKdM?b&3em$FbDe#NXvsUwp`LHMA3!gFP|NnkZ z_Pi%(P%RB!H9p<-BV6Au*Z+nOiN`)`CmOr6od4G&NZL6vqQGL)@J#VN@I3KD@nZ3l z@QRR!o`0nYrrX)A6f}hj7~O+2T;I#}U2^@W_^7!5BZ0SzyW{1avm;6rPr%c}x4^T- zcQHQQ#*VVr`(B|GlyRdPaUX9KzX@*_zaQ@w@5G0K9-6-y>sth4Qt&xGCH^xWx2rq3 zm@YfHWbt+I^k@(C-;y9ZIxxN)o-dw{7mLrw%f-*btHrN2Zu-yh>LqBRpjrGeyj}cd zyj%POykC42AKq2Y|9=sTOTnto+mU)%?x;7$v9Pvrf3nSvrI7{DvVm%2By&&&L{!i#o7b#i^8@&9hX^xuhsJ}KBA z9}+)y+8cRZ71w*ayOXfLq{<>D#E zLz9Ti-!$Kof@&!^3~v-a8E+TA0PhvA!-peo``=BFwTC;pCya+y8a<_VxxPoP{{kNr zUxrVJFaMHnN0guKHeTl?>&4=8@e1)>@k#Lm@v1%D`xoP_z69qG42WNedwaPzx(!bf zZ^P5XUo;*)(eU#hq99WWe#G;|mwVYxs6;#guM*z^uXWw`b}>QpibBu%ND3O<0`FA3 zUA$_B``k8zKOJ=czpvl>GZc)^;H$i1C($Ph+6W&N-wu!2+dRtf{LQxaHo41OK=8J7FpjgN~zZtvs&>kiudDi{S`j{9l<))xHd`jua^J5G}8 zH!wck26o~4?BMmG`I}Yb5#-B_j+@~|mvVirT)z-6*~i_${rF(C2l_82@b+~J-oR7D zhwyaqpYQ_lS+Cm(Rfw-;-1ML0HAs+3L9_U-#-|(Uaa=zv*O%i-`?(vtEabUz{=bJ{fV+c3@l^4Xj8FHOsO9=x=X%rsc7h@&F#k1Nyi&XyuN8kEZxjE<_;d@J z^QM_l;OGB)q+tC(U_2(z-SO6Vy!ak?n)so3rua#Cq4CK4P0LDx5-GSAZxFxB_;fpa ziR(w@`uFj;1H&7${l6wiiUh&;?{_>^e9l{TLOJ5=<0ax-%TpH z!S2QbujQ09$j4Li-5sBZXNgzfB>@l5-`x62f^sRi4X+Vz!yCn4#M{K*Gp>^e_WzZF zVJTSg9lPTR@pbXUL);y2g=dNHhUbeP{0_hWr$mAiD5w^%!0W`X!kfi!H?BJlynoMg z{m3D{yMuQLCgnz7;8};d*Du2h#g~8APOe6L9lST>q31uBp!G1f!LIn2_(8^}+u2!M zpI6}C=W@JI+`oB-8+Fd$pK_xLxzP`JgZRIAm-y=a!3p`^hy7QF-NBA{y7>R_ zJn*Zdj0ng;#S;3j-Tyk&;_yyVXiEa65Ia-*N| z_(Jzt&VJucB29cPyg+;l+%J}3XM$Ss1Mn8{WASeBa(r0)a(v2qUFae_Q~X)H$arM_W)N=^lu5xbUM0TF_b5C)zI8Z;Fpa z-1gsrAoe(S2m9eE;z!}x;tTL1@r&_N@%j%q|5r$G9|hIoPvh<4Z{P#sL-@G(Pk4fV zyu0IBAMzfHuZ8D`ry8H`5$wzLrE+~CUXO>L|7ip*Qc#6=ieHZpi#Ovj#qP$Qz~f!_ zy&i&GH}F2fi^adg%f$c2tHk3!ntnpt7&q_V9IsglvV*}KuS@(;d|12$pAtV0Pd&k% zL@k~X@bLW2T5cyOl7dI@8u4ztMf`odUHlt-Aj*UN{~#ES3e0-ExIz12j6c!c!A5wR z`1W|d_&#`*c;O)D|7HmmP|z!W2|g@-_}NLp-+0u`Z!kJ5uzK@#H-D{%`iIqHwi9g&d8q$d1pT3a7O8k_iQ8aTJVpE< zJX`z(yhz-yAgGeyD!fJfcDzsg5qv_t8~09fH}Jl3^9cU?^Z!3nkRSyypV-l*i?4&{ ziEoJ)itmP32R$@@GwytXIw_cscZi>d4~Sol4~sY9DJMrwBGCUag3{=~_{(^`_y@+P z`<}mS24DSCK6G-QO^uuWbG%*&cA#Kbd_O$ql&Bq;g&u{ciZ8%(#4pCnPm%Ng4FvU4 za4+5_{uJIV-i!B%e~OQVo#+1}K~kx^v*m{D=nBLW@DlMYj8FGy_L;%w``oBPZgei* zFMbssd#bz8+we;9hw%>a=W%~Tf_Dif#lOT0PIDXoidTxqem4CiHa8yl%r)8TBkx}( zL5JLEf4p0~2=5a=10NK>6rXV1^luxeD>Mj8FGy=7s*lp{-J|4>#%)KN24lKMnWJ za2I+po-AH(Jh&id{$|IIQjjABFX6@F19+|YQoKd{PrM%w_g`gr`VnnsJn+62oaydt z?-{N?&iHa(l2_UOLf{E{vB4ibuR7@Kd({^>?tAwW)VhK9rtv`IQfWLCynZF`;DeL7 zwf&#jU)VoVk^Q*+qZy$;YLSQMi{Bb_-~6t0g3zDY*nOqB!5x$6%O{_ICN*KbSv z5p$#IK3xAA4{V@PHn94a)<*&!p1-+tQ-Zj1cho!JDdM?!j`%Tnx%e4)ca#VFUrLaC zmfN@i&k|pR=ZQaSe7Z?|!1c{?{n9Tv|94C92L(goD}QB2HzvLTo^rOkfo<`8@jdZ| zvwgRqfS^?hPQm-dFT_X0ufx;Maqr)Z7lb_Y{GTMK4h4L;Uc(#3KgL_d$M8Y%e{rwE zU68-Vh#hIX1e@W>;+e*$d&Y-xeWqN05?&yFzP-Xim5_^|knc+$D&xW&H;kM9=D+_X!4L(F;y>YS;MVFn-J zJ}q*e-)6Wz>05LE>3;wJUM2{9COYLt1%ZNT{=C3NGx)tT_#06knZIc{9u?Rj+aFi| zZu-VM&frJQ;8p*1+yCzW2EooR&*0z9;A?z8{X%z{!B70&pT6Ll848}5!9SV7XN^sN z|1CrA%-`(!&`=OPfAh~5&fxdX;BU_0zlewXulK|BE8S%VKVk;I*m&T>+b1918}MP* zeeWKE*o&gyOV4`}PZodG_;hc<7hInu*Du3!#h3pvuu${!|K$>_6Ab2fBjQ^cpRVz~ zTpwHIZlG|6>npfEF>rl&{$?##66DE^8fUms2iI52^{?Sg;)8g1ln48NM=%-{nDuyn z;}hcXKiOxTaIw4NO^r`Cp*^@hQ?5VcC(i!`5|mI-D}FxSCVtHfjUSl7U*L9A zpD)+@iwNo^cn0qf@52Yhm*54}?&N;KE5(=pIXF4rYm*?+2427TR``VY?s)2@ZsSAn zJn<5|H0YuEn^B)nP%j17;GN=k;=|(YcqCL?6LxS|^!1%X#miQE2D8AY+ z_QO~zz6o9_zJqbo-~0w-334eI6+Z@#yWHK`8F-TTrFfor1738woc|XQluN<0c$N6u zc%%3*-XcDMcZZ$lAG^$sZYUg>`J1mKd`vtYpA^r*V`|(972;{)Wj;Zv1l4%Gcmv)k z-ii;4ci}NtxC`nx9{4^H_4&6uUPeKh6f8esCsZK54qhuh7jF{J!uza8`X5X%Aq6Mm z-j(hS&c)-!Yw;rSJMc2cP5(y;nw-G%Uc%eN2k@k;+yyPg)5ZV9%fwgt)l4+-^Z!*6 zBnN`P`Coh`2F~lcqg88wY#9V@XUzY z{+|;RM1tU_@n^hDJmxn$p<3~E@Fwvs@lNsGelzF)z^ErA$fqFj8g~ct@eJ|v@O<&B z@iOryyw;cCF@hHHm+^M-5AZ(mQG7`JFMJXYKmS#Kx08sy*4^>Oc#8NAc&7OO@KW(( z@mAM;?<|74I=Ar^c(eFzc)$1~__+8>cE$(4$4 zhF6R4jJF3oJb&{sJdmJQ3QoX>#m~hj#jnQWuXlHRC!QAN!TygE~G zLi`83PJFpP?1VbR*ZPC=|BwW8DTukj-N9~nn)o4juJ}oKiTDM0^$l{0y^f$s3hu!N z#h=0x>)nOEfftB>hBt&f^!$G&=nVyd`J1oh|Fol<5?>cjztL^HHC`gVCtfA)A8vx_ z{)M5Ef(9wL7H<{53-1tr9PbzJvF>}55`08K@=fl}zQfbSk2!G5;4jN1KWTs6@7WkT zxs$r=Upm#yFV|hdF9`l^?i1N?X#S=q`7b-_5^1nKUM`-4*NPv3H;b3zozWiXe-S}{ zbYT2?d{q1%+*{~Qr~^+Fe;rR3|HSyTzyJSl3UZ}jwJAHHLh+6967hL>jrcxz!$LX# zA4xDQ1*hWU;uqmwgFA`q@g(tk@U*b={5uHp!-4$}y^dFie}XrO|A6<1dw<)>jft=6 z6HH35Ii7s8yR)6~4Dmd?Sp0arR{U(-?~vdMf+6und{X>j7gUmNcfPsIntcg4pXH~kMH@NRWidIFvyUV)d1Uxhb`-;Pg; zKN9f3`9HJKZQM;kp7{HCvG_N5x%eM=wRqgWOw@Q}{^pr&M9?h-+v6FxxeMI~&lfMm zE5sMz4H38fFCl1)1i??zjd+)M3m$vByP(B*n)sV|k@#o-`gRm$5{y$&DL&f^{MYZy z-l)ma~&fZgMu}dm9j>xq+9CXNvEQ7lWLHsN` z>PGQR@U|!qKK~4Y-l!n({_Ts8h!^7CUG9!g!;{1>#xuq1X9fTJpXN80NpK$p<>F7{ zb>eT}t>Qy?kN8jc@Lh8LpEcW#Zb}N)!V~Xycbtl6iSLRRiXViRggo^Aoj_0#3Ig*t zUln+b_*Hnn`0eG>Y$!cZeU0cZ-+fL*kd?W5y%%H=p)f2qvZAK|JO`cM@HA zn)thTvG`ZU<#o0FSD0f*)F1_kc$@f^c$fHYc%OJa?mgsgVE!E6HqMaXJPJz1ug06i zoA7?|$MBek-NrBD*}eoH5LAedh8l?f6>8AtHdu8fyRl61jqx%({QNTrnx$Yrd_eqY zJoXW{@#%Ppcs1Vby6-I{m~sQ}0X+Rtx4|=^2I75qqxcfMPyCmloAZC_V{U`xSGJ?8 z5l_S$#J9pb#dpVt#1Fy80v?{fdHqTVCZ*tfJf_`U=rwqv_?>vFcsrgE<-z{1m_Xjk z!2kJq-%yYpRS@t=yhwbdI6Jv|@g#gge49AV|22=hJIf9gh#!i_KjB_~5}qtxiI<6A zi&s72yEnRvpiK%M$2-M)@B#6U@DcIvaPLX_hMxc51Sz2)FlX}>zlt4cuK1>SsrZg~ zt@!_pPxpxZG71`{;1ax7ydEDEzZahn@4&qdchav}_q`+uKBk~te9ZWCJ6LU1JD~}= zeq+4%DYx-FJm=|vhvskoaUX(`U=SF-{VK$3#24TV;+Nnp;y2>G(H`jELNFE`7+;J} ziNA@bEp~VI8J;UXj+cnfUXAmAlLTv1BquQ68t_!{oA7+``|%3#PP|t9E#uSv z{{J5-=#m0&4LhMe@ip+6=c9M#c`0~;_)d7L@yPtmr+t5dEGak^&lfMpOT;h7%f)ZO zYa(v@KSR!h9-k2J$75e|cIJJB zr-}cDX9qkyfAe{tvz8rQffOX+rQ+M-RpNW$_2P%)Em0oqUrNv(6$IYDi|`)t>+wPH zd+;&w4!rzjcS5hP6*~V*@CgNt;y)Ol?hJT+JiiCzIr}Rop+9s!XYJ{)-_m&CfYbPj z@2+Tff|gfYKNN2lKN;^5zYy;gzaAe5dFc7yOE4S?0`oUtPvhg_Z{o>4?m|Du^TmI` ztHu2l*0G~#mtZ}7SbQ5i{#Cc}UU;qe5qOjMY1VzOPl8J*m=eDU&w9;m`~co8{w&@j z{tiAG^w9jxsJ|qLd);mD8=fw{Qlgz)iTH+ix%l>YL$n9_?@Q1Y9T-0v?-D-)?-Rca z9~Zv`kLz_e_K@htH}@e=Wq@oMo4@mBHc10MMK{~ihM zr6A!QcR^3%8RBo^UE-hP@$b6#`32869+|)Sw6Bn4M^`Qd>*1Z^+u*(8d*Q?4N8n=- zxBX8eNbYx6dI_HXf3DwzH;6xgcZffWkBYyO6#Du9_uK|wQcx)V8(t~C(gt>NneV&z z*$^)h-yW~>CD@msN&IMhLi`N8Yrt)M8J_up>$l*&c=-80L@*`=FW_+>x;J_cFBbm> zZxH_z?{VGtR^8B!F6AS)!6tZ~_>Opy`2KjE_;Glf_}M`>=l>oFt~9}Phs;IXs9&ys z79SCR8;>1yH#UqX1w1@|^ZG3#NRxsUHnJ1S7GD>y7Ei;w#rMERqdeIEFoO7x-Ibn# zXNq5h7mMG3*NWeVH;OObi1UB91aDC=B)$Y66<>x=im#Y#Cs+E3yRr50s!!znzb!$X z6zq+6i64oNi7&uYKXn`Xq5FqC^!yhRG=+k|>BD?2!n?(v!$-v5#bbxu#$VxS;{NXh z`4X(Wu^nBN_(ph>_&mH{d_Ua#%w5ni*3EzaSAsJss1m;%uM@u&ZxeqQ?-zd&p9p$r z{$|wg6U2Y+u5>A$EdCdsDZbh!c5)Tso8pbp9_YUlL2Gni`~bX5{CK=i{2Y8p{3_gA z;%@8?3eOSW1NVz1IEfCqp7|A>2|g%nhaFT%^d zcCUX9?-YL*_r7tj{|YZQ9+|)SwErHukrb@FxgA}f_(pijQn$f8JX3r>yd~nc|1ku; zks$c`orzD0Uyc`zx{Yte>%||&`@~<|+_yVR_}0DA`xKOlFU4!c|H8+_SKGqgKju64 z{+r@Sz63iFWQZSt=ZPPWmx!N(SBYPRH{jvte+NOE6g-Cah`)jliGPGoh<}gAeeX=d z_x>eFaRYD7R6DvX@h$KI@m=vU@q_Ui@%ceF=l>=N&ZnS5{91fO{BAsE%-NauB%UPx zI-U{m@chl^{ZoQ`DfkI56Q4cTPN+tF9lS|=E4(wxgZ=j)=#L5l@84ngsQ4*({15Jq zFTyj$Z@`Pi@0-i{zgB|96ts)Kg%64^!Mz{d1uer<#aGmP-z`|5pi&C9#hb83-MC%MR>jVb9krtyZErU{}n;(xI2m8@pSQ( zx3Z%v6yFH17N3VViSK9K_c|pwhJpd{Gw~7e%W>~#cLTTL@!}8TX+aOo-;Dc3f?O$h zA1@JKidT#Og*S<>mS!i{7VUxln-cU!2gY~82gMJ-C&Z7(<9~4{aSom)ewA_4e~yJKhyf7C#uz3Omn# zK0#qPu4}u!;!|*QgQ}AK&i}0l1+{QQH#nvP5-+cr%Qm`2B7Jmz$5?_KR|L!(kh8H?+ z`meaH9bJa60GzVhLWPpkDlayj^@LJ|zAZ9yjGKXtnL^7Jns%XU;Ht=O8gbPRs17-z;)mIo*?EQcSQf< z8RBbhZ%0=wz6D+n`+KJXQQ|JX`!pyfEP5`I~va zPEaldpW?ORKjF>dv*+0fb&9Wp_eXiK|5gN}Q9Th%doM#g`ekzr+(gf3vrQ3_H5i<=h=_j^~MI;^pE8 z;4R|E;W4wgf2jXi1gW8bf!E-p;NOz}B8 z*vaLHZ-D2EZ)e^2iY3^Gf}@c3AFp)cXd;ve8ev1>=o-|YBXf=Vg)8*dO_eJ4A)cJa;dKJlIL(XiA1 zK!S;IU{+(kPQbl6?#|A|lfu6#o;CTg6>y+%9%J;%NyG z!3ulW(N&4BhqsAugAa-Cg(t4-Ha-H+4SHz)=Jh*`phgNV!Mnt7!pFoPz?0T<8$XNZ zM|+_EI|S9yf$=Z#4)Ndc5%HC>?c|cycN=er7l?0f-1Ikp0f_|rQqV1aG(IVQ2A-Pa zHogom7QY2=Op^2eLj?U&@B$vQf!p9cJWKo=yj=WGyfy4R|5f+2qZ<`#2>{w#9zio#XrRTq-3|jcLasv|KN4v zYwTqwHzK|{p0Kfd|6TAh>yh{GAc7VtI1wKbKQGi^6Su)Np$6i2h3@aT>HkEiffIP% zYoP|4x(z1A;{|oUv z%MmjL8}{h58=b& zFW~WMZiDymT=8%4O7TB~ZqEPx60Ewf9bM|yZi7wmBJmyZ4)Oi*xNY3~9EaxwJUo9h z>az)|rQk}uUHo>uOZ-v1SNvssB+7&RKO`8B3IfmnJA6v~A3SzjcV}ztXD62+zB!&O zzRP}`|I;Kmh=NS<6Y*T}^YB9PYw%j}yYS9!eRl^>5R6K}Yj|S1d;KSPuK165rTDB| zJE7W;ho1l11f8KEFn{y4B|a>^JD$0nyP!kyBJq>)a&iAcf;I`R$GgPu#RtWo#z(~8 z#K*-yx9)p!+q*mXg@RP^75+E<&vI>HJaCB3kn4BG3&jt>tAZYyzq!S61T9i<7Tzab zgO7^eiYLxW=Xf0wY)iq2 z_+EHIhP$)F@f`6|yh8jUyd^`<|JM@?NWne$h(yk2~jJUh|K%;5Er_itl@MjP1in;&<;yT$*94~ZX(kBOg!PdRS- zUqKMJv%7=a@Fej^@HFw4@GS8U@Ivu#10Fd4S4i+T1>NGSA81E6BEA_OyNkPlo$++> z1MyPhk@=fZpFq$c1?S?;;#cDn;&Kp{6!;)d`xenL7Lp>VLVs-dA!7z z;9VNz)8J_uv>t35$9LJk;bb?wKHu)RTJCcn-XQ)o-j0W#{~H8-QZR%MivNUiXbN{ z2z?t5Jl>`uX; z_#ya&cnKcAkGp~M@ig&k@Z6w>=5NM*Cqao6wBuFcui%a1AL1S2-{Sqz9_T+sFcuvc zU+r+dmG0~AY!f_LdRCcgMqcviLGQM|_1N?Bq(t*TrkX&ht+rXbuPV{o4cY5l36(a2K8<{y1JN-h)?)e}p%Qe~0^>68udtARd3D9qE{O3ZC>ocW0S+rFb6RWIgi! z6%&j|K?NSWzuTY|&l7LLo5kDl9>-1p9)bxcFn|9)o^pWOcnq%=_X_QVCdCu*f;{&= zsR0k1|LY~lqF`J+A5S>Yy-^9CDPD<}i`U_u#v}7LANXd1*n`{#9iax|y?Ckk5Z)m^ zjwc=*zQ64sbCexjRwM|%e~Eapcp6?Ko{e{j7vK}(rAKl8&&dz3DA>4)f;#c~Py_K6 z+&jd*PbZ!&-iMd?5)2d6icjF3;;~2D$qk7o;ohO{g3|GHJpBA~2uh`(5N{MO!^gy{ z@%Y2s#tnFp>%P}YQ0E3-7v3)3j}M5C;FIE$cwT|KptxfKlQZZ4DhZN?%mKuW6KoIrSh*yZW;nm{Zc%AqF-WcV<{-XpfQ9+>p z6y7c#Ut~XYUE(QtuXrXtAf8vm&;O4|P)xyucmK_9JVo3))=sEgJOLjKdFc745~LjEHps#Y#PjhQ@e;g4yb>P~_v;8!j&>V2 zyj?sO?-MV=N5#v1f|%pooz>v+;*EHkcpIK8-i?=t58!^a1fv8^ z;!}95c>D==ay{ZHc)xfiK4d-e{^b!&NV3mU`I#k~{lgbKwI0vaM&0Wync$WC; zr`VAei*JUPi|>qAi~9!>v`TOS-Y2g{=+$_p_?>u}_~X`nuTg?mDd-me7#|h? z0go?p7qncdolvIuT6l5LL-RME_PGSLQm`A|C4LA#Dt;0kf4aM%3-HWn5A?r|pe#Bt zeh=Ot{uJIN{sulS{u!QfhP$Ajjhp^+ygUh(Kh=(|LVR7kReWo_TYOKvU;J>~J5$d8 zrxGNc>8|u*JXiciyh{9jyi@!cd?M^T|F=U0T(|fJ#-}?e z?e0_1F9rGdg!p_s_8fOX=i!OsSL0dYO}Jku!D9p!;xFU%;veA6;-h%G_+NNJMQ{U= z_ixn&c68}BFrR<>wK1M2o`IK&?}t~2AB{IUZu*}=(Cq}CcNv~{t~=^m@Ivv2@DlMC z@N)6@0v<1-0UT;tk@fmf6WQi*JJWitmU|7>~@~OnZNV#Pi%8ABWe9pN+SO zUy1jL-;R6dhwpFuKT1#>34#y*WxPuKL%c=&JG@u?AAC&wis$`wZ`Q2Uyz*Xt1Hy9l zL-+ji*8AVEz5xFf*Xy@_Vfy==glE5H@ADD&S>trRA2{WkMd_BBHd>g!7d@sB^aXW7Yhh;L}! z_XZ`{o`Nayeeq;@WJlvU;%DHM;+NsAK@ZK}jQbV>uiD-5LwJh#3wW;hdw8+P!k;(U-fJ|x^D4J@P6?f@nP}(@t8~9jU8v)^q=D;OK>&?S>jjXh2pp472=QL z_2Mt%ZI{aV|3iXaDfkW_5&s7t7hmHXJGm+G&GF33LX+V6??R9h4($7P5MCyJB3>_k z9^N5-4L&G-mrpPy!4r7$<)M|@1-*vnh<}2YivNh$iO;IA6Y|?7Sesx#d`o;%e0Myl z#$D*4c((Y-c!~AM`*$HhtrT33w~612_lrM`Pl&&XCteY~P}Bc&f-EQSykGEQ@fFUs zqpJ~L5AP7)1|JdME8v0if5Mf~EAqS}D98~%4X+Tt1aA?)2_F!D0FSv!&i~I6WSAiO z>m9sA{7bw+{5QNue5Ld31d%g*EH{}Zlu z8{a}fj`%}(h4>42i}-tZr}#H`uP?!$1cTzMp3msSH^JktaW}9do+iFOo`r|szvBoB zrQmG5Li|d+Ui@~vS^QDF%XQy-nV`=NybtkF@$c}MYuz3HgC~oxQE4ZaCBAvk13&*S z!7db3h#!R4i=T+MiJyn}ieG~d20T1}^S<3hFd+p`;PG|tj$gym#6Q7v#ec+0qCD7t z)&+J%6;VOp{a+ie7vB5R5w8?a!|TMe z@ec6<`C_X7Zg(uzWjx?ULWVLt--XfkE@WA=MM}oZ2p|sI$P>kn_SKu|` zwfKm56JBwfod4Si8ch)W)q}_1?)o5}BR+o5WYSEHF`X{%@BcIT)DNQhXjhD84T~CVmv|-RVxW3{MDnc>aO45Tr`MO?aXB z{dk#pCtfZ77Tyr$!Tz5Uv_=Ji_wQ%COFZUs`(f-CUk4u%-x8k`-|h0y@Bg{W9Z^07 zS>p5YeDU+}67j3?a`7g-<}Nw^KSt0f1ux@m;veAM;-mP0_+R*F$V1P6)fzj}sZbD@ zzxmo2kH6cUPzIhYz8_v7el%Vq?w?N3C_y#eE4~n)6n_9uZFU#>44x(4XWjSmC0Ig1 ziTEzujKqcAi+i^2>g4&sQ5g5N_;;&{$6)-$KWaAXX2Un z%K86tf*dKh6|WF~7;h1O5$_a#AMXo0&wnYwU^p-XFkgS+W8$k_WhXQ#z9}AepF4@2 z@MQ4=e1Z%Kj>k*H&%w*Zufl7@@4y?yAH)4N30@)S7XJwE6aOBc5dRmCZ*eEFX04rE zruE4Cw*^6g6zqx@iyw@ai_gca#m~n_95?;1CCI(sUFqF;f%ubnx%lgNo%pACtN2d= z51#)en0>V!(XjYB_>}loc;W-@2KK-+#1F&sjYsBhKJBLvlu5xwc%}Fac!T(Tc)R#w zyes0i|62qjks$c`Ey3d!xjS2iXNa$Ojh$Ss`1*K}__o(@{;!l^Zwea3kHnkB7vNpu zK0YA65Fhg;SVU0R>hAbCyh8k4yk7h(yiNRfycZ8Y|CO(`qZ^TejqpkFd3eTy?n3v& zbH$Iri(L1;GYQJwz`Go;5x*606n_|R6Mqr!7JonJ=KMb(!BPrF#s9)n9&&fQTAiI- zy7;Dej`&V^VZg)lH=p+d2uh^jc)UUU9K5T|UC>o{zxW;aNR$WrKSnSa6$IYDSMaz; z+y)=v$>QJR8RGxq+2U(n$N4``f-SDIBP|r)6>ktf7;hDyj}MBUkB>d#yF0soAZ-ozw?|~<^yBqTl zBS@9t6ueOUBD_re2E1DQKDAK4ZI8PhlXNxbu3&efAG};6G7ZOxN2gVoSwc^j=P2%t3?c!hI zJ>tI`H~r^$gA%Myh_w&717#CZu2s+SDxIR6((Fpq*t@qO_I@uTr}@iXu)@yqZ&UxHf* zhQuGj$Hia3dkg^wc?xLZQ?uPUE=%WeXjf7aRei7 z;GK<6h+m1vJm>ECc05u1Q9M=r<)EAMe~|@IuV}~KM#+8!M*+(JR{13{qG_uj0ytp-xGM1_-lBx_$PRe z_>cIg_^eww|Hr-Pu5|5N?da0Qx5Nv?cgHKm55?QWPsWE|^xei662y1Aem$NgelK1s z{xset{w6*c^3e1DoFL{UxA8A{y7&r>c0%Ri>*0;!+u&W|{$2#*5*&fYzU(gOw9t*j zFTv|yaj(A#ukLaE0qefk{Hhx~Yl7+i&*M{W)G62hgb$0)zRgZ(One=DD(Ip4n@{^z z1hKEV3)%xu5kCyi7C!~g7rzK^iuOSN8wlE>1LODML*k3^nAhEfzJ(`%~{T!%nVEd?UP9e4bA*BEf#R_lCQ(WAGC3Gx2Ki%kd`h zTXDZtf` zc!}et|2YITPT+Z0;jQ9#;Dh3i;mLjOf?mOM#6Jpn;QU`9!S@t2ivNpuiLZI5o!p4{ z7I@s-?t*s3(~L*vZ$9k@6XZ+5e7r*Ze7sToTD(jAZhSc6w*Qj^G4Hr5eH~8~{}j&? z{|PS_pM95|P=ok7cX9sjlwd0ghQ#;4y?5P(9)_ogpMvL#Uxb(W65K#gFMc21A-)(N z6n_h!5?_KR_uCDGpZ_v~9D?AtKl8(iciYjGim#8?iEoRyi|>sOxbAyL5=^>*w*XK2 zKX=qVo-Mu*FA-ma*NQ(EbaVc1li*zn`o+J(C&Yip6W?ArSG+;|AiP=p1iXDf&i@qzeNu20?tS1c^maT!{1H4~ zyc@3xdFc7SPtXzy0%I^=-{3vsf8b-{arfHEC4A^EbR#@P+~1xcM}mFuQt?8(Nqhm` zBYp`!Dt@DN^WXpa$X#g*1v%o2@nZ2e@jCI(@DA~Dd@$&t`I}MCzR!+sN($D-lLy^} z&c)Nkvy4yob{xy~rP0?1`j->bM+e3)$2-Mu!H2~k#A82p7utoVi@$5!^f!M3N`fyb zs22YfZxxSiv6Jf;Umu?o-v&?qM9%+v66Aj3?w|lK7e57W6u%Jf7QYT34Li@jnIQgC zxABvBrub`kvG~V$t@s$;F8;4iFet$q_uG+rL+*k$!&AjG@qF{ zYw&ULTk*ut+=V`bXNy0Nms*d!fBgjYQt%btDgGNiEI#J}JGt1;-32A#>5iNJ+Y%Hy zf#>aoSBM{u*NKPEq-Qw2=JaGOWlHeW+Cd51N_$BVnUdPkKKf!awf51zON9J$7 z;dqPe=&Ge)O}tTjbG$=*XS`oL48|t$m5Cs+K9?-r~}&?p64<6Yu=;=|&H;|WXM`=5&Eggo^8FD9rA1%bJl zuN(0i@%!;s@n`Tp@wf3IasLZ~2?>71V@BN_%xSZuOBCM#PZi$|&lKOsy6=@qa1;gg z;-}-y;+NuG;y2@i;t%2zK@ZK}jQV+k_;1}E{~w+v{xzN{{s&$lzRDwZa^=w;=)W;R zU36f42fR`Ie|U@dvG}m~S@@Xv6~;~fIo_lMw^5MtojZv~@G9|_@D}k8@P6@caqoLM z|Nl*p{k_|G^+)aK^2Im9>&17*JH-#g$HUI^KY<{1%x!!wUMzk!-Y9-2-Y@<*9{YoP z|5ts2YzaQbE5(1n+r^iA%uZ-jd@VfrN4N1@+%J@1H-dWcL-1bllkidT3-Fkq+{V}8 z$<`z9-#rBRQt%XBE&c}HEdCkZCH^x$=(y>>e7hapgcEq)x_JD!yMwLqH1R$0BJsoV zYVlJ89ytHENN_O)UE(+5!{Ybju|K;DeFm=+e;e;M9+|)ShVuo%h!p&a$N%CsnDe-u zT$=a>c)s{{cx}XO|9uF0B7s?s=N*NQil2@rE^`-jsqyK4>g7SM&ynl99_RdDB*D8g z+~{|1R4LcbdBRR2VZvR|`gpqd*2aSib>?q&d^iQ!Qg8~MFMa`DDSj>9D1N8$=m~}U zze+)y6nrEF!RKOr_?PSZ<@(j1w38SW-_&??WA5X72T+jkt2?@5@l5eE@k;Sa@n-Rb zc(3^VK{x0B5eYgem=b>rPy5YX=;wH$_|JHScuYssB*ODI^GGv6;Qx*rq+oZvLp&ev z7e5gn6F(P^`8~3MVE33b9_v_kry?%54kjL|VUDx}% z`P`qIbqnbAc?6zEzC?KsYw4^;`LR^K4L*(hpJllIucSc6OPC4rA@BzBfbyO?RE+XT zDt|e={V%%ypN&99N7oeTnYas{OCEz4k-q?+M&1CgHEz~_H3DrWptGviMtIuac89jW zv&naTS!OOoK1_K}GvpqP3bU!gICv#_DSQF>j*AZR{$z9X1No)nou&WIJ_+$w_`&dd zR(kF_VFc0;=(R>FBtDde@F$_2m0yZSP(B^yN4AUmQT}-N9zTl*QGPId=M>6&uI7Ia z1ZsYjKm{u71i$Am@fh5UU^Tpz{BocAEok*O;v?wLacE~oPfMWJzj+0Env@Zn5gaK~ zYm0vmOu&>=Kk4phtB+4 zJch*QqWr;*jMzatkHXjNBA)z6+RumofM3Oqe)5cL|I_fZ*oVCtaJK6;zzO8ndqp!* z;X2RzI-}MM^5k&%eLYR7ioK>>4=nt-BsLxG_sT$LJ7=&Hz3vUK1)sV8IY$Nbp|^py z>N4fJq3AkkC>M#JhWj_zBg?3hc3P;Np~`hT$?v56-DqcqiweGf?EU)=REVI$fvE5$ zJVu`PDn`6s60Ae{CCc@{a;g0lDDMWpmkKddIPNv6P(l^XhDXTD;ML?qua#{jfhEXB z`{%)(Z@s*(b2-*NhCmWiUD-=&>@q_da@I&kx1#)Q%6D-3J8fv#hkth~m-69ODgOw{ zzpl0+y##iL)b_Vc2h?xCCtIX~IUY<%h^H`u)kyHVa=np8v61@WTj43%c!Mj@4%$b5 zoK4zYmDu@065oZ${%@&(>S-&MW(@pt?W%nEYboD>#P6Ye7#rgSD8F>2?r2}<(1T>J znTYbU)RLKVf$V<>Jb|@rqP1KGZzo>`Pye62@vebqk&nevCN|0d)RIa5efq1OI(?nC zGyGmx%(49$OkJW)D*TC#=Btr;ONNFfVZ`k!u^AbPN_(%%MqNN1T0O?y)0^txPm-Vj zwFc*kN8yLSFL+y)hJCO~&{N{Wkhq8v|E>q1j|VOiv?IZ(4YFnz<4AV^e6HsM9RE@F zk?|vxfAV}eznzKlC;vx>`so3vZ79($19n$p>Ms6|3b!cNhs+obndUTIuUwBHoRWr~ zLpv)}g6*6vry?$gShJMFSILNdze#zVv|MKj0-;|dp!Nsv^{lCY1gF9~;9-pwXb)iGyA(a(w%v=cslAEUl`fnOW?;;KZ|y5RvqGv)Z70Sp{K3X z(|UOE7JL8x5FR0Kg;$dQ4xdN9!*X2zH&S5F<+8t~$Vb8bTkQ^QnlsYd=$xgp(N*j% zLq0~8=Mn43C1|H;D_#GWBhW$#?)Z;}UQn)2LYY_svv(YNz!2FxHp^0uz!I#7$Kk`x z@%NC!MtK#Y2<(Xp#c%XHf?3M-dENQfo{72eZ1NbqnB094feH$&f-fUq19!IBiQC~h zr`I0c=3fnB4FZd)LOZ;Ud>g!(y#ETBIe%}v zqa)yjosRr@2t+yqGNq@&W8@dW8_B1@*OSkIr>EH+deB86n*xjAW675*?`d0UMfurO z{&#p4`3`T%47suG?H=ukKt1^=c#8ZON&b=Y|KCxS|2I@K|^8cT}aZW?|QYs(TuAl!`P~e*X zXy^enG>^*H!sFzx!CT0i;3?%@^RG7euMkL2w?~|UXOs7CkQs`T?+#DzW4ALBp4;V; zKOcc$SHRo<&VUz_PlT6}Pls2MS1RvmX`VH|Y#OHu%h6B^`A6{0B)pV7A6`R#2E3VkB0L4}T>t3^Y@rI3@bsPRkv*ckrzw2{0r?B?3i7w%%g9^cE#&S`D$vu2 zw|}>1-~T^++<*9t|M2g_qzJ ze@cb(@kBK1U1_KlbSSZ-9Sp%6CXRXTwi;FQA_PtA|0sza_8|x34d$fOe~= zs?xP;#64{*^OWmnLB4;b9rM`!8_du&nxWrOKJYJ||L=w#o%p^q6hcG0;I{f{czBy6 zxD@5nnxuRZejNO8xZkPuM6bAh-KSiyeMM)7u>MaYP}>>s$~&*Z>&Tnn4dh?L+sJ=| zZzkW~{Xlx;^s~3>On5f={_sNbhi@3_EkSU58L@fS?A*J>LvZsJ%&yhqZV*%S3f>g@ z_I-H(x$8K;Hw9)bM>J_4;1nKhKY%P#uD2B@O%flCB};kb`#R6M@?i2@nNVlU2T~p# zb=Bh&c^$1r*3-sSf)Ph(#8<&9$SdGgEm!NmKn3*H>+C2aFdJRkhuEsq#mz=H zQMulT5>`WwGacScUI|}M{)l#c{qOX**M12qWRS0b=a4tU3&^vt%Jc@7>LUY4$4pN; zSRQUCm3!O2>Vo(BdXfZMslo)cP3SeQz)T#6HLivyv2g|9Z(^H>!p#9{GS)s0SKF5C zf1j#=ey3tzY;@+3dG3djxLXCUqZ`zSd)iiJ<4Bk2DqC}gS*pEA$Fz&!n;d?1@OR>VP4`yKk<8Tj(7zg+DZH( z?8iGLd!C^KmFpR5vf2b?1KzybE&aVb2T{2#SsdLs=Dk`9@*KRYSj3jZDh zYxLYz@4;XyUPWNvkEKF1QyTge{*>`O#m%-dQ+24Pjd4CYI+i*bhljP}{NtrqiNG|f zuo_-Tz7bwSz6Bm9-}Pfzf`)GHD(`8kn@~PZ<#+r*eMSi-t>oic{B2;K2p9W9Qv=iS3A4~o) zJVO2)yvlPk|7vsz1eQ^SPvHsjAK*>of5SJEXEe*qIeT^+fX+V@f!W;y$`6Le$WMSb zkQc+(lV1T(8`LeaYX1i1Dt{j*n*#TsLIL>#_%!lY;PvG1!Pk+02~QtP&;L^hWDmA` z+WRw^y0PTD!z;;0!duAm;b~c>eXRc(2vl?i)cmN|M0kvRI=q>@5}vh}Ng(Y!0?#8~ z;v!H$ffeutf-tcrE#f@OJX?@UcVf_9w&3 z#Jl!C7lCP1;a+%@{3-Zi@;c@Ez!e%Q2QG7O+52-DandTU^6!p7$_hBnNO*?d9zi}l zll%;LKKVp=G5K`u`ue|=0+pyxN&X0Y8Tk@;l6(ccgS;7@yEi@m-+(|!1-iffflnsi zxkaY5oZJtOk&l7bce$+pi3qfG1-$&{!8em%1$Tzo9lZ&jNB#i3gnW_t3ufgMcmoyU z1gNvcPjz| z5isljFg!rM1Rf@T3tmpX8XmRXb$&#k)($xT!V~2E*UHqjknaQcjj)&C2zUYc>7J|S z|6vMDM1?ByYvIet?|`o(e-z$9{sKH}AJx&$`B(G33V}Qw==NF*ZzBI09^Th3-|GvR zp(y$8@ba9l@?QS^5LnzTpz|LMPm-Sr-%Nf9Jac4M0^QC`cs}`EU*P&bOo1m*VGjAr z@HX=I;A#8WiNAv9k^crS+0V5r?66Lzu7)ZMg0Cb0p}#yvOYS8no1uER>UHcL;;qBP z3xu6(zmOY}2u@B*%=)iIAccmqai=nDomB9nf_YT)BRl{%kLlk33g!KhcqtNZ{aU;g zZa$vxj%}4diUNC~&MK z@FT%Q<+_~!-8rp+hvA*i|Bv`yD#Q>lYdjwwhnp*zy?>DMNx1n!!kKN-p+=0@bZ8|! zhyfT+ZdA|z^%T`n;Nu@90dFk+pL+JI|HI$-58t`HvmM#~&DL0g0B?-Xc2)2u*_8hW z&Kv3Rn&Dg%Jofc3$?Qa?i|p404o2kUrB`=E8sZ8;Q8c- zzzfL>;YH-{bl`RDLT@*m+1|ohCl&TcmZBY{x*CLc?&#B z{u6vzH}~@Yi$JnlK<|J3zLhE6Or8yQa_x~F2G1uy1ztuz;agn)S5hE?3QgoU!+nR? zi64NcA7=YPxO2Ge_3*sI>H7a81R_-7TlhTkKj3xbeZG^KYbW0e?i_&*ne`uyz(5o5 zj(?7G0z8*|JiLhfO87ML8{zZF-TM)!qrgIV3;9Z1C5J}HY4;>_^o0~IWN@0!z}545 z<@y@47FWpul;7u9?R{NmreaK@PnE1k5q~VAY|Xj%XotH1l|Sh9)Z4 z_lhaBV?N6DJj&-%`4t;nnTlcxe2NNHN=E1m zFDAbSK8Jh(d_gz&^1p&WexaS0T5BozBq^SHU@QhRK0Zf4BkVnK_r+@-Cqe3b91Mmv+h01kDW4SUD zS7OQjg!>K=9|te^QwC7uwPWUA1k)@$eZ8;PqRDpH9ScEn{t(3JprM>_8ropGV)A#lze}9 z6Zz5bQK#D-8V4^tov!~&5h$e!GvHD3JK&Av^Wp2s&TbFJILRLXP?vAzU+T% z5SZ2#@bYhh2hQ!R;Q4l2Wrm8$cY~LakA&BdAGHXx--D-Ouj5WA?w%llZxQIL-mBG5xt#sQ)h&|uIvkJJoMXg; z_%7J@<5mz$rf7egOGqUui#flC<-b%Ioca^LCPkmYl14q+WXG z(yz}wAK*l&q02I){97n*cFx6~4{)lnarwPg9Oq|vCABkp=h3crG6)q)j}~H$ciUBZ znhc3=Lqm5c*Hbq_Pn~-0?futrK7bE^n+Fs=A7->j+PM%@benSB&Z2&!lrYd7j^2+Bv^eyhM(FY8?=G;C^Xn zJQ})K9f*2*0&+7BP?^PM@}^WI2RS_$S;RC zkY5iEPUto=HGn9*l>A9}WCC6Pzl=Z?Rd^S^n0y_)jrB z1d2KXs+@Y|z-!2lgx8aw4sR#F2%dSNNi6M8a}mg;z-{mn@`vGz$)AI_kSE|pVLS1s za5qeW9}uV@{~KOUp0S-wX$SdGc-BRB;)CHK@vi;v1O%$7LNR<9`4#X4`3-RYL_6_4 z@POqi{{jTYS^>v-1ztw}9()e@m+%GTDR?V+?_O%=^!0z%B)g}(>wxkQ`AGO2@_cw5 z`5EvnLjC|e*3G^Aix6n)7SNmZ8}Rfi?8KkI3&?+fPb2>a zK978t9d^_C`#5zJ7`6j;OY%eEDe_a`zR7k+FM#KgPlXpvcI^tcA`qbp55wn?FM+p` zzXcz4rQQB&c#(0l{y!ox+XVFdtJlA9-&J-){dbfZT0p)Jyp{Y2_`s{}cHGku$fLkS zcnSHn@Cx!f;0wqfg(t{g5OK(n zAy7{hj)u38p9$YWehJ(^#U8*+cyV{v`R_ttcK3ktC*aG-Uxv4kzX$hCwG)2@&n5p& zxyrA;0Y!lw`pDE(kPm_{CO;6~M1CB+gZvzL_BC|nmL*VrSt0bWjiFMKii)9^;} z*Wl|r9qa!g0?sr$@wf0S@;~8ub`gkC;6!+m{5-fb-R|gB@BsNu z@G$uUa5qYUMF=Fw-+-?t{{)_Xt=*v?;Q8cFt54H;54q0s9?7`Q9(d-n2?76jc~)b5 z4?MMsTqwR??HT&jcYr+Gi5H8T$8Ih>c8++J6nAbLDCGm^iofEyTK~1XNg!nf9B0fP z`dQ5YCxxe0AvAO?JXj!)*NngFd0(fY#P5|n0_C@$d=%x)6W3!hRbKu3|KancM;)ke zn+|9%5wC{T3Vq_OcdE>o?$it?uKbD707onXKl$-Xw?cXH0*953T|ERU> z=^<3+PO`O^(i-mvFDbXTiF|m`%ubj6?{owrT>-DJVR#k!RCqo49C$1FgYf2Aor%5n z7wv@W|Hj#NU^yzJUvGO-xqkO59G0mzUryUILuR6o%8!CKkRJmNx;NMf&O{(gela{s zUJj3w-w98WKMLOr$MMf`mLlMzE20K?A^GRa@U#khMoZw?7f_*?{B3wSc?*0V`A_f|`M>b>H`7McZ&#U8XO7*WYdtBQUBnAp75G z@Ivy7;HBi#;SuuN;W6_0E&@pkEQLFFnx0CB-i8Or*TBQ%o8VFM?FPsUxd{sFhCqsZ zBz$0%-Jzr4dF12ZRpb{d*H=)9i@Yl+S6x`jYdtEoQiTq9`dmBlk1xwlEJScAmWy^) zzbYPw``~wO@OyvAD1|>{B$wf8{SR-GKxpP0UQu&>z5$-FDmc#l8>M_Yl|TMR@mebX zE8I`zANxs_ch#R(Dx<(@?b1*SHS|At9+h9XNy=A~hkh2XAfJjms)U*$Z~OlfQ?yp! zFgOF8(1~(qQx2ayRJ@Tq=ob&4V3+?LUR!AU(|b$#mag)$|BW9efi~PCnZy~x#e*l= z4ZR7kBcGZr#0YW!$#y#*k8mYWO@WMoJ>T){r(AEn{#kPUzZ4%RcnTh$DQ-S~ zH)J=Q6=~xQz*}4j9H#=_4aU{d(0N#bFHs@;E_*Nd1?8htrThZi6CSy{wBwsDZa&0v zhjM+$pB+*TDQ#O@C5m5Lva1yMu87dA>%%K1g-EK^52!~CGcVQdqDR_z0MgX9WA8tm%&T! zqwD|K2t=sD-S8^%C*aNGFTppHH^P1MFfgY1uME zE#!N^H&C``X>a>BcB8>Aiowqnf!KmWp~&4YY?dK9#H-~ zyp{Ydc*%qIRDTAaL;m8~_-W^dWZOCo2dJmd$&|nUn|xFPGcoA+c~Zd-e**sO_(9%A z+WLr;H-6xt!Jfw-7C#6Ho;fGW^JtB@xz4DVA|9x&mH9UnW>w1<3PX?C6~^mduTuMW zbiVi;bm$rNO=$fj(|4D%M%Dll17GUDWl2dS)CrO)fOdwdAMpLh`rt=l*o!iYq0-*%;ZD zeZ*Vg!{G({iu-VyHXqfjf;)6pJSIoVhhozH=UAFI;cnEGz;cZ2kdZQiyi@HFtW~Z% z8hlX7|9}o%KU$aX>+lB`+tkL`(=+28M#zCK@PyZn>zGHVXQ+TasWj8pdl4!)3na0b ziG*ngZoaViE81zNcGC8d#F3|@of2;VYW?q50iD=aZSPLC@GSDz(NOGZX~z8?x>L!#=dqf6?}_Q$d=$CwAZb6T+t>5I zGe&$O0=~G+1dhngwQxTihj8Z^cmQsWq%H6ud7l8b3HaV>&AjzL6M>4CB(eD$E-~eL z%|bMS7vVMJtI$s3Wobv()~`KBOX61e@xspJ(dznNPj%oGsgQ%fTdIOi+(-#NgD;qG zPjwr-iTr=?Hu7B#mi99rrR)E_Rlr+&bjX}uuY*^>&6i8oz@v3C0P{Kj!^TL0;G=d& zPk~n(H~ZfN1R6~MGZBGrCchb;_n4jF0pC+xzuiJ_tPf+v&#Hh`s}D~g~(kSfGcp_vk|ga;nCJGvS^nS7&iy=?_INJkgw zj_Ul`he?mhsX`t+PCgdiLLOGG*S?qr@D9pXJz;nB3*{<*A7={%enEwdC+!No^Q5DG z@;%_CEpyDH`5QQ&= z``!`1G+h#8T`7Nt1)i*G$IIYXZsMh~xe6=$5q*Op& z=LPk%T;3gz+^IN^V`RtR<2J$9r2HZ9F@tc2M7{#Iav|KP_)&hr!RpS*RX2;}bW`|) z4k(Y3=Zq0g!TmBY=L)#*bXjBLOW*)LF`O<#M-6(;>kl+**&>d>U{%S^$JW56|wp2!t zg~a`j7U$oNTMy^k@_mny@(mBj_YB>O(9jfhpy=s-{ch#@9Fg&qnKY^JI6Rm9MR=I} zZFsfquJbtpjdsBK5uPI7s$4IDum3`?CmS(z=LOWy@{;dz91{1DhRmJKlgjlBHB$MP;pxxV?Y|43tsUndudnM6NKu7fOhdJH zL%oid#8u?G!Pk@Lz_S;2wd3VK5`p4w0o|k1mFuYvW9o)`-E^FnQND`GzYEWOwkv_I zvJSp(vF*PckL&+nx=g7#5X~u&kvY%V6&{3VkuQShkS|xR2N2s8YmdFG-w9aCU0n&> zf{|UU0(vbAsiAUsHTj)rsA4B+XD-^g@eCV+;XR<1{o+*uNs zC!YruN`j0f_6!{dFC;%3KAGGtL!gENv*1bcyWpG2ABSf>Z+B=JJcs-paaY}D+ZEQL zLIwFIcn!I8vdlyy`2hHO@_pb=T<10Oum1ON1hTvU=3o6Y79J$O5FR3*3ZG4W3%t6! z>-^OSEbAUn{wzE}{sz2_{9}05QhP?%!}G}hQm*o=-~XXN-&15t%gOhG&m#{g*BfaR z$BCJkyvt9McIv47_3-AU^!cAC0-LGAlkn^p?2)|;pGN*JJW9R}zPQt|{=Xp5)EST= z^gdli;Cs95{OfUxqsljAMy}>J7V(3azSD4oX*=%u5g?IlDHU$-q8n&hvb0f zI#bc3_i*i2cuwcVp%-~UU9sp(u_$iM2BD!{junshmISvT^W(?K6;uT6_|g7)<+_~+ zPT%r7BWnFaCrQAUAq|Z|f?Es46S$x_84XQ3MLdj|KyhaYJOVcttN*~GaC5Qxq*^ld z{?o79&~E2HE3lT$w3eU3JIKF>4}8hqhW>&VlJ_}7HtIRbvHeT#!3Zp)3J1W~lOF@m zc-c-o4xUS1s@%Jt*j;8?J+PGg&!Iw?DkR{`$UlXrzhWo;0X~ZSZ+M72BZTMw^C&Ph zBvTY8KN#LdegfQAXLqO=o<)8IJjbQL4G83t-ve(VUjR>$zXEq&wLA14+z;@Q;9JQ5foImM4t37I+5>k!Q>JvR4s?6@;q%DHz~kg6!t2S$ z!?TumweRJhj6hzufX?qK_s;9sU(Hvkrko`mEu!*s;HBgb!sn1LIt!owNl;)pDr_N7 z!UJz~jX-zwJNPv6KjF>feTrlNsW<5Pe-;86Z`uhCg6EJQ2QMW*8(u+P247&@tp6+o zT1`L?OTF%bZy|pio|&*ax(q&w{2h29xw{sDA_{DRmyo^Go`%iG*gASXsDGu22WpMkN8D+0r@I;n0yU9hJWl-a%dg&wi`h0CfKQ5XkKwQ2sPLNd79kg!}{eJo0bg%gFywuJWs2 zK%hXMb7f?0R(2bK>gZ^AKKTjoF!^}+f|Ydrea_#!} ze@ZD(g$kAAF?c=sGI$$#BYfa{cH(u)y#v~Q3uXJCgd^IK=gSo3P=zz#dE}GeVe%R9 zYVtdk>%@rzWMfx%Y_k4+OC)iEDhz>Vyl;=-V0bb4iSQ=!zTe8t>z~-~$6&zCFS&bp zJsOGK&jbelE$>nVa-^s2xXGKMT))K{p|@Cv)yQ8wNMdC2g==+hiJxMuES8&EbN0Iz z9&stqNBwZ1cejg%%+GMvg@zkfNUU+Dj5tP=}6#C&??}aq8%M za36KF!}|oJ`uu-v5T*z>=I0-Y#6!e4>>zXZ5InKJ_}kbf8uH~WmA|L@y@Kjm$9wH? zl(Z97yP19sNBJW4){I`_3Vl_rxBos~*l|udRRaD!q{6H4h1%6_lfnapGBlJsR?0_k zd7gptU&33_j@jrcPnYu1Zrhf(|NW){`rYg{JTfUqLm!4@WMAaSvz?3KzH#DvT_Ib; zbok%Od)jy>o!PUWSE8=}dwSEU9Q$#w$=>hpfR~cjz$?j@nBxI?0^Zi-+6g{E!1sae z>)~1Cf5LOf(qEPv7sK<(%i(j#-8&Iz zpunT>w2$lrOX1n%4e${8=kUqoKZ?6fJq5O+LL0g70-4f^q}`$6@G9~{;fu*nhPQie z=3h;B2?C=&wi8?p50l>nuO+`9-auXpPj+{m|8)ccpV)~%ga^sLftQePhL@A?c%jT( zHTfXrD!=;3H3bep1>dK3hl20|^0VNTif*@Xf`~b{4n@f@>5&{$|x`a9wm>!o5*j5 zw~;>pPg`wwbRpc$qd+|ZVe*gQ^T@x2$I1VIuP0BxNM&Y*LZ?RnEpNT+vi=B8bJd->I&n15mKAC(KJWjqwyT1N!r$9R@)E4~M6%vlE{N&n3SIKAU_xyuqcw z?FgiQX(yNuA4|T}Bp`nqzLakeP{bio~!5ob13jGDzuY-2`^f2H}osK z_<~^Yko5d>*l=9|*!wa8@hYzwn z`*ZIPl(#b>x@Ao5^RwJH#>nYA=|Jz`#H4k;UM7Y>~)Q4Ul{3INzKfrUnglb5?PKH0L68Cg~dKVq4?dp)M z{}%`(y8>QQo8YbF+u&Qs`(GhTGw^SF=0?B^$@8wj_5WfDoT@5#?^K*3BQxKGcnl4# zqw+7nga6ox--buXTi`L50zV;;B>xwl`#(EDzsWMhnuYoTkZ-*y)cmDl5>C!d?GScjk^^Zu0 z0^}o<>luolBqK9lI*GueW4oqWXJ|n?V@*3|{eMEB%mgq+|DvG)4n()W&zvG1nnUF; zhBuIx!<)(7I}vcUw@3UaJd1oOJcqmi9wPr7UPAt(ay4`6`@fhX^U36bsWPPjxcRw~8TkHhj_RL&J%~UnMsU2avjrXq z$%xH6otIoEiPLwqmux0{6!~57P^V-4pFkko8Ia5`!>5tI2d^Rj3SLkC8$2W3?&z29 zwfMy&j5v%D51%6*hmV9G`=i_w`fy0r{LQC@v1(|g^9PushV zbekQ-yVm{!nQBv^5*|T6dT?4cup|=TzU69`GUOr9Y%+CnA!7HZ?*`W{a-|&jw-BzH<7P_r^wsk>HX{u zZG-!5cb)#%%arEX0cQj}L|(0b3r^pRUML%*`3a_jaaS9{M%o7(=~R60KXjgyH>cx; z2kG5gef}qUwgfs*;iiD>_tA62KZM_}zvHbEhfBo0-|tYd4tOgP%)(w&C|2$0`8PM0W5*-GxssqC8hQnuz{t#H_{HZ*`PT7L{t|RFPt9CUx8LVrMkC#3 z)LZ{D1gg6QbXzl(d;5J@5}3rh-XKespz_0%>+*q%q`W!wE=T!wR6cnFuK(L8@Es~_ zCjS%e^tU&zK594CiCZU1V)MzVGvLuuaWm6T!ktq3{_kHn9%N90z7;a!0`k4!5%K`M ziu`zZqj9tUor6HT31BTRgQpL$M?4!|Kz=toO#TFX4!Qf13h1eeO_C`xcQDS4;-O2# zhoeJf%JtbSK@H7)C}H^~4Ncy8uj zjcEV^>#4#%%JmGTF2+WLnYaVxvv;!xFdrTykE5Lm%&2#xqVxZFi}a|JDr|*Uko#`M z2*`)SHl$OpiqZ+r8TkF5Bu=B|R_iDHFi>oYZ0)PDwO?|z{Kl&v z=K^!n`PxV7bgcG{$W>C_eEPLNZb-sq;^wq_#ou!J4oEw$V-76esepbL?4enMyp;PP zaTdNv9JyQ?`W0uz-w%+pUjzyMgiPcy3M@f|2J#i~ zHu7e;&u@2V13aJnA9$tq&iPlXwewvvrHiS8AD$#115exAPJALfn|wUHu$z1NCnHeW zEueR07e0;rUU)6}Mf2sMRia!r#!}sgdhL9*{8U?Nrg#H>3-0u*hsp1MCa#x283JGY zA}0xFj`&(>$GJ&A%~HEl;5s{j4=0r{5}4g`27a_UhVpX2cAW2VjtErX`u}~LB%V?u z>*>(@7Dil0BW{K_kUuq2&X%nhzyTP*25#T1f7;zWC*E7R-j7=;!I=LjA42&KDnAjP zH_YBv+-V4eDR3)1MqUlCCtn0_Azu#99&RU2Dpxb@Zo|xU{<8@cLR4WJJVM?-Dl=3; zJ_24vo(FI7+|0j9f2s=fwDx7F&_)f-glA;iBddaElRpYC>h3y!9D(xg0p)Kg@2Nvy zqkJWm{}sM~y!SmaLkaTTl&k#e9Z(AFiwZ5|hr_c**dsm_o<}|bUP>NOj)8TXe>LK{ zsL((a9)lO`V<%n;50S5gmymx3FYk2Z-+;ip&VcHTdi@QrBj4#>nbHRGA@DZx(aL*T z%F|s`aQ3xF7KV=^p9;?>p93FD{($nH62Azy=U}7A%~SHT?vt4a zQ{s!^v&m<`tHrzW-;Tgys_=+%oj6)0iD!EY<2d7AkaI!oPVtTK`(G3H-6H-q4(&(1 zE}p6sf8IOSsQl|yf}W+jif!eNs zx0)xymywT$C&(wm*O9w$XFq!Y_ug-w_fg;}RLCZ;gXfdK4=*JD3SLV7t8#Cfu;yQl zx&H$)b@Qk~HoTGiQ22WCLU@Y&Jb2#zG83KoCnHdR0QM&526&h}3SUhA1iXd(C3u_d zuG5G><|un@zJTYG|E#>H-D%ecW#%GOes8${0K5G$o~!HsdGhDbpMd{`jq8wy)boFRY){-J37QaCt}5sRNlNe$ z8j9X6<<0Ye(ubvdJC(l{o_>%$qm{~a-f$Gx{}XUKy#^IVQH7sSA#sl+HXlkk<`GF; zMCHdR*9rXhqCDDv3gyG5yjlM`RH(R5Dwy|jvTGzkrKx}!I!w7vkV5$x@LH5#K;>VD zH;}s@BCwtU-ylI`p53AI=1Ygt0``<%sa$uc73H(>1^<`f{+P65KDM9ssMn7A{0}v> zhYIM1d=E>7?RJo%h2i1H#mz6JERlws3TkHsyoJ0Oo;F$!z|6n;-wjBRz}Ai>b21;3 z4kc+XI0c@9<2u8sP_8%LfR{izum5`=%C|l#16ZpErt^P_3Pn`m2UJKbk_x5fnNLjr zrn`D(IQtFVu45LWT)CdPz+x$X7Cx!8Lb>ixoZ4?z?&=EBSEa)7UUTXj5szan;pQ_S zkHVeTq`diS7wJz(hf>s`+u{D}?T+?+Qpy+3enaNpj9?rBE!5B_@N{bEtOe3gEtP*5 z9wz?=Uf$_g|D30!p=f77rs8UNg8XIWdP)n%n669tcTql%I(q8U(takj^MH#$fCAsZ zL)6fuXC!e|uATT=`0PV$zg@XrVy9h}44+|f(ra~x1~_i)LU|}sjE?>A%5>#Ad`#gA?ly@DIxD|o$B)h_>Mbc0Uc{#j;5;VZ;O6_(|c~;s9UEJN( z`X>=+v;yjnM=q8M!ArVVP`_pkk6&v0r01l3PMPgl<$HU(YbE_=%p~pl@BhXqum~0E z$oIWYeq_eM0i*>>b}>AH-SYFjB(PSwK29X5oxNvDJE0bQ{y&Z#{6Q7a722pmOGLd> zp*9w0f<3bADdOei5qOHc9$t1qXFIb0rB9WHTDtC_)v6DED@!EGcjPOy?w&ucq?X!WWa@ zj&`E%7TGWF$CJ-bQ6Whcet>t7|BZ&?nRbVcj>`aidG<_#RgzvmJ0&!_yA8N3an-kbDcgfPB}bG85(GU#Yj>ywCqQd&tx+ z!Rht-i`2%b-rq}JAzP_Q|JOu$KQP`)%2(ioUoZ)8IAUWoe{6DGsd!+UEV23Hl#jxL zzbM!9Zz>GFSSo~uN`iVMcops+ApR&ix>dP;$F$>izqj$4PtgW1kpaZ6vIlT8ysn#j z>%R(t%5DMO;@M>w!48u60BocS;E@g)*#P*WE2Mn%A93?m?QvI%`!b}RGz{#PD@UvA zfAx{7#2-@OansOMn2EkpVHrl;4)+ZgABysKUo9gprU7K>1DF2u9^@Coi?49)DVnbj zM5;oN*8XdFgnaL7q^VcO;3m3pmKc#^zADR znR~_C;eNQeH5>AR?0zxY{Q}BWJFe4ukTi5FM*NrroD>=|Z#EaaC=Jz9L+2>h9SY@0 zJ2TPFR+Mj{^1CjRb~bx%=3iCX8-c7N%pNZ-je+Npp8zi+KNmiY{Bn4_yX*YdtAHLs z#Yh=J7DiC|lJvBxdj%Dn0dFV21D<}QJ%IV}Z1T8rm0$fGZwjnb0dGq8lMY>p4*6ad zPr%Jx@CC|sJ7H>P3VaUv9JJ%#f04}p1Z<6;A`m%P5^qA{;#VYbV6^z_@YTw7;us~^ z2+z#7XJQN5@gFGdj5GItp*m?OpDIjJ?k$a}fZgd8lrN<6@4+MFU&5D>r(6VDDA4;= z=}-sx?(oc`?2(OB?kyQ+&ip>$vnZcU<=;SgH+G0j#j#j|ZKzO475cxXuWkoBWpqPQ zq+BmSC6&JvzKnb(JSpC_|IJ09;AnefF?cQci*V-{yZkD6G5H$!Jj+%7b_D9IfcpL~ zypg>B>oQ`0&`vx89wN_Eu9qfpq|CIr1$#xgy8c&xEc$9W8I)tIzUoPN8$FpT72bl^ zz{6w2&F=taKx?rIL<_s4p98Uo{myoouq|W$KccI&-qQ7#_%% zhRh!%drrBxG13yeiSoXqr2IYTsBby0|KkXlZ$e+TTpFsOhGr?(YuSqO=c1t$$|tCN z?>D5KCi2~t>vrO9P`iGW zJYL*2e}3ay1QMr9U=)rAFDmzLB5$yt;rtDET-%RINcl|i8{utsJFfFK0%58!V1+bP zPF@PHvm0_2Dc5Vij;4A!$_J>O9p2LIyMvuV3Y?(=x}ngq_WnH)UO_$`UQb>LZy|pK zo^hONzw7wtI7<-7*MV-Y70SJhGIp)ZRDrDE$t^}+T~+!tLOiE1bMS4(0_=x(bdw@?6QX( z8B-ydi9NA_k^_(*{CJzIIqB?*bBU!T(AE~S0&ab6&#bzvHC&f zdhZCJp>i*c<9t#f9+_hAHT&Ku-a+MO!`rC*TIH@z5T0r`ly{Rf)IvTV9=gUZzx~Zp zzLES&c-=I+{M+!r^m^I;&B*qeBMk+q!gP4;bi1Js;C?y+j<`j&qi$;7E0IrDo87fc zyBcu3^LT^(?;TXwx~o(u!BqFXRVw7nwiExUj%Ynyunb%!hwA7gIUbn56MhlgxkB7* zb3eEUL@u=h_r4=1p$a+|EP$uTUxw!#Z=X9F;nn18mFsQJ4VFpb!PsqLjS@&*B0dE( zaq_#;p?YfQe0T@>mCAL31O|3J+8OY)3tmNj z7rfSTwf>JI&}ao5XBm7m`8)8?3HDU4g@?&E!6W3(`)Vfi=YQr=pbgJ(LfBY7##!zi zTvi9JmZiDM+_I^S)O*-;fp`a&a_Vj337muuK|5>V{>yRw|2ZZ*Qi+Db($HK~Xn@B` z#m6G?Kk)En;^z9l@^)z_HU;gV{jKo8RPi=*{d4UdvcFb84^Za_+5OCf z|D#-w*nf>Qv;pO3+^O49&-0Uo+md;$FYCfVBSXo;_cCtV7-2&^Z+7oH-23Z8MInH$Mm2hSmYAD#=x z@y~I-LZFx`{0griPy0YdR!hDIyor22c#G|>a})yW?SK=4r^qM4eJ9x?z80QGemgu& zUgNo|o?KAic~qz+e+%AB{u#Ww(C$zk?sgq)6XsX5N~>h!4d`u4&%gP@;`bro%#e-f zLF{I2DnU;tn;kxsjWl+hlsET&XDHVhNAL0AIStr|5SAq%-F3&e1@d9|NLK5qA z`t=tQ=TJL+lhUDiCZ0Ts|ajo%{)%&pe*sIZP2dNm}U^AFu9QUW z*X`@|KVJoOg(OYglkgOLA6-GceuDdvppURK<}PU`05^NbEO-cR+F7aG)rnKsFSp0q z54~F&@?m5cuyYyQ4 z_o#-{b$b$PS&s5m@I-}udHx-|ko<^yrJcMRO?m8pl?deAWCD_5H9X!~LHsRsJm~3= z+=}Bz0>=+?NFMpI9EhA#?BmUmE&_fEoCeP)zfifJy4bz4F~%_yy*`lyrBr^Pa$P=j zpOiO`VqZmhw~{I}p+X!L4n=}FpGtxSRQ^GD1NkC&EBSJG)~Vi1nB$-N7!Cq?5&nRmOE!ebAJk3*NXp`lu< zA@$Mi&(I;XW3B-&RIX3QO;moWc76TdLV;V*P_RZ4zmCMcS4%^isr>HB^#Gg)rM&#t zaV|mm$z$z}?mBpt@~-(;NvaTNpbC${ljJYJJILQwt~=y=NV;O4j12x<1~Bln&JIcb z164p*2%>@+!F*IG?yBI;MI2sEz7k$Tz8YRnzVUN){jU?pAC{CcOm%6C^wc@Mv!`BU zhH_m#^oW%I2IYT8c|VokVU4s?NWLe$%%#961ggl7QLYmQo{_|V;80zT^7T~yPI%23 z_5dD*H^4jBe<=c6s6qogJ7hQXIXs{IM|gyME4n(W5yjUvCz*9 zmwg{DWN`K~p8@&A_&n**610ElJbeBqh5g<GJ-2NppR0X`<>{Ur%5?=$4yew`$u<#ZmSu=_gM zs4HmO%2BS{k7C0VEEUPU<)NUM7d5-frhfsPlzcY4iu`VP z4fzwwRetqbP84_v71GYO6F0)M$-jUH$bW_xk#G0C47mJk`u(4Q2-Hx8ec=t{N5I?2 zPlKnOV-Fw<_jNk-ay^~ZzbR9 z2bogex%P;EIZuA)$9Y3G#yK)BC;L?Si>PkuO$nHj%9X?AfkWag@x4(Yxu3WX<)45b zeR-A~a1v7f6Zq~^#Zzb}jFZsCbH!sTyz;Iy9TjfbAb}`)It9M?{DUL`5}OW9UMJt@ z^&>$I%0CO|cB;OT^0uq>FH@gd)n~KJTkNx0Z|`PQo#n{4s*{R$e~)9h`JvLsAC{BQ zy=(M?1$A4G4h>OD)6>0TzFsnY{U4+?I~{9TLLP=k$fqjT2b|>FvIOQxx@d!V#XI6x zqeI)b$+l9Z+QIfOkxT@Vlwf~&JNeP@jADDE8wbxJFNGI$x#XXLKxJ3J>(L$X1?2PL zaq>94o_r;IJ^AW3b^Wi8fWGne2sWZZ5&0H)uG+1-zjoay?Ua)bgSU_$0#CUVC`4f3 z`F4Wy;iJf}f{!J?5gs9*2XBUVuK%0rQ}24KZv9j?7W4Z*_u|84e)8eoyWi@~Y1%u! zQ+t7KC)6PAn0vqdAHiM&-${-Kt}~=Y0#Vv}ub40HTO|#dKclnbW8x`n)t6u$s^H;9 zDQ|p8Ov)$W?I>Tae7jz5Unl=DzemFmc+Cq8a0+Q;ThLJAT}fcRfVk)hN#MLM{ts># zf=|Me;^uO`177j5ay|c#;Lv!=0;v#dmI`Cx?<&`q=eyrE*z4kH=xE=k#QECG`A1jzA?&0(|=PB16nnMkp3XhUs0IwyVBJMg(6qthw>&YL4r(a;t#3Hz#d^tRiJP8kZ zZsuQ&={p3)ZpR zoc=$4=weGURBTF3R2Hd;uqdXBT1p1VMryjKr7#heE;C3LrHQZzQ^KlbsaS+TSaKOe zNiq`FS87UFM8D5@-tSZUe16$K^8LO(w{t(A=RB7|1DSc`S@K2X^|nJl@-Os9k&hK_ z$6N?;_sqYWL||JYajU;c8~(}y8Mx-|YHky5&vt^dk+zpIz-sa;#oO0l4DH?LZACaRuyf4sNBE)Hz18vB#YYo>2T9;kHF%Y|$MoXmfjOH!gzY zKM3$V1<<3V)vJM_P!elPOqR`3Pn*OG^R1z$`4oN(LHmEzxPe>Vb}UI;<8 z3OtTHtN1B{p>Lgau-S<7U(t7^IcKdGZXnmt_8o8r;pA6*U8o{sBIR{OCi# z!&|`JZTj*cIlIg)M28${xqSaW^S!@`5u&G@i z|8NJsP!Rhc3gl+TCV9x*>ZiG>IQ?DnFuCW4v%u+ZkY~m{eaC~f>R;dw(O`gFblRGkFTk%OU-Kja1bFS&h`jAn;1OQpIX)IV zZjuzdOM^oyU=U?V-7(tx>7Si$+UQuH6V8nr%oUbDg95#!-}`9h>aeVVR$|Tn_!B-TIt=lPIWE20O`9claF*e*umP6n~REahG4e3en%ItfTIe8~U&Rs8(7pkMOP3UB=}t_J_gmC)V}4qN}mYd>Cs*@Hv-cNuwt z{9<79w{UxnH$Yum9`HMO@g9!(*Or3B9)ahot8ly7WEo&M1I(iSN~J%KJfrwB@*Rr5 z`#Yci$?k_$y*>l<{R1V1SndS^X>nzsQQ6uo66&2mjl_<7TP| z_Sv_UDNxyJ``Wz^#$Lj04WfyN+`r#+YvHr^t#|1gRPoSeG7UAkOUj=?-F?g|B zKemw@rQiD*=vR6A(*AB}JVZf8IoeJhQ@m&i9F-~lD0z+IIr3CpZu`IQvv3qrC4GHg zY#td-n*-Pq3j*NDqtVpYl7D*{c(w)jP2{VmV~>a)0v@Ud!8F-ByzhTT4us$??kW@S z2zq0pLKUci{V7Em6EOyMUA9A>ps;Ixuqpf;%Qe3w0ba>5)QJW9OJ2vb`ob~(ouH4T zL{<=E-~UR3K5t`>2-j^okyU!Uv8mdEOR7BT|4RP$4TpKe`9J9$>qowr!09UWhsFA8 zq(oI}9-sIgc<2%T^h=UgDE>2f@KL{h-}m9CT=DsF3IdP$4R(>2DL!}=9GR3~{~7X} z;(wEuDt^`n@Dq>C_d9x*f*Qro{167UYDIgCJgOF`v-UY;uesz{;dV(5$T}i_Y=8M* zH&W0V0xR_X?jrA`_#@=q6@QjIqWBxay%n$%1}X9eiND{z5TtwpW6mKD9|waESfI~^ z+Zs$%0cxlp=nVY~^{3Q>ep2ZtEw|7AELMWYX|PH07lhjyB)TGi`)Kuk^${Sa^baG? zALEudl;}9&)=%VwMQDG!x7oj0G-$63=F=e2t!~rFhl{BnQu;rTPgeX-^6EVt{okYk zN)$W=0bGGD6K+xtrQ|`y?;Jx!kFw5(*;T=KCks679Zd85vGoS4k@1j6N-&i=UoUkkT^4O{3~Pijnu z40ueYll^m7!B3E9$ldn6gFI`w9sf?y`x7|IDT8~+4F?^!Z?ld(p!kuW!cS1~@#Gw zgK*mgnL;#mZ}Q;h;4!s+JVBl$cP-uJ3+unJneb^GIm~5r6r&*Zl)vx)^0<6BL=~v} z8WgmEqumvBDtSurt>pQf#zCxq#&liFnyJ1|kb8qg3h8R_F}Y#OxiOLdCH&~F97(Rb zGQLJuy1kwG{3hIP5`k0E)UJC@=Zr|IemY3T#zIb?|TM#x#F{U0aK~?x>{WOnI33~GdPHf<%K32 zH+H-F{(qW+V%28_|H2@k`2FMsik~5GK-mC6RiGh;H!gQ`_WxTHWOobD*2nDwgKEVe zATLz>Sh-}gfg_6lN*-1PZ58L8$Yggk(N*l@n}u6P`DOlDkarz;jdC=L+$jC$W#RI+ zT~6cnoR(=>h%ApM7}zZ!+hn1zgRW$ue-O=F2VT6$&pUnvo>lsO0FN-F^vO;C6(To1njJBl3n~>OcJ-EwNGjcsb*_DA0G*uXg%ee~9HrXxI`p zswMs;-=X;9tZ|M39-^oHo9ul|94p+mL^6T`@%N96DW)Jc9D-^t2o;W>2mUhytRat{ z5B`aqvf9692iVQ2u{m*F(EI=Lf4slG9&c?DpJG8Hj+@&>;PuU=aCAQ<8S?N@@H@!! zn_^VwU+y{u0T#T3!>KR}+8NkfV!O;1=&K+I{TwTP>YMnsUDVtCpS~in1qzQsV3+yK zB9D+aM~Y}_$fM6dzYRSV90)&wC&Aqh8BHJ$KOx-qe|s8yDFQoRL#k#!(;zk#j`CQ8 zU;qIUJj8ZQJ>2mG^xY2|%oJ|@PrhPL%X#DPF&ac4hry97(7!ZD)iJQ5z(EKcx&`{D zGGpmYo@Ptz>#mN;W7DC3E63I^2OSdknmTwV1Wo9u>%j;RT>$8a9O&TRnDt;~bT*apgmjcQAzbw%h2Hr)3v@$sOP}Cr}7&UOO-$aGmF|l6hUrXNY zN`FD8(@(-1q|*MJP3A=kl4>6RL|#eG!E4&)BXCp&IG%j6;%5r?7P@Cq0dK6^{$D8q zn{tI;_V4#CTY?8)@$;DDule~)_`M!t2Pe}3p!oBZ*R;=(F%%MTK3h=e#sz4oE zF@W;(WDDjEccaGdvx~>YcwKNO&;Q+$dH5D?m$P7y$3vW3w}J=egCER3TSXq?;60WB zu9gDr?V|Qh;kFC1?1H8^|B!mM08V2cq5!g+eDdgry@Nup{!tG#O zp!)u6>L=i-)Djp|~ z7b?LA6qG35vMrm=pa$JpgYm*`jq|T^Z3e+q@|B7wh1-gi!+(7D?Y9jy*sKh;k@vaU zAE15^jw)3_&lheBG*szdM*Ui!zRbTDDJZzp-}jB$p~j{mYV5xCex-0*gMiY1UAPUL zQh`6Eepu;uI70l`-~Wm!!A({myiD(qIlCT@ROn8FX z_3QI4RlO+mv+qMc#)rmF8bLo>z}=yAyl4~z>Gcq}FP0aM0Z-7t73iX|43LBVBHodh zLmvJK`~sH|l|VoB9Jo86IO_`Uh&FC&)UI{Tco@WLVDJuG;#nq*nXkc@awSS##{mBW ze};j>+i`@G<3bdqpI$qVOQyY4OveAUG^(@2wurC;l2q~ zydP?CBY!VoIQ1X4To$xKwKBHMv-+(}PUREp;IFw`npFt5jtW&lbL1iAXK*3(qdqSEzk-5NpTL+S zPJuyzs__-%`AYwJ@;p_bzsReUpI)bmf1Cd&l);@Muzeq8(_P5H^^Y|W{UQ~3)M?N+ zr}&%tRpC}YtO7Ua4qh&Cz47m+(>WAWs{-9e9#D?HCNERGLk|SVD1Ie*aF2h?zvUFv z?h$x({ztf%x3lkWWJ~ls9RW&|{vG5I#Xk{l{bWu@3q?5?3(k=I-wINvLEx_MZ$AS( z#4d1rD|xCr^oOxPr-qTX&rs?10O7U^lB&y|7jEO4cn>&QKu5diC~>Xp6bKIL$r`Yr zZh?AIxV<1*tn{nMs}+Brd=oj^UtFwbfJzp~9V~S2g#bC_C`{gZqQ9UQkVh0BBiySo zyOKQ+HxEz{pr8#~;yv;ZIrkc~i#$i}EymfoH*Z*TFNPn?MV9T_Oyl{=5?^6Uv30njCa}^j!Ua9mSCNEO{ zYl@iv8`ab&o`nDfs_AYa&#IbzOrEGyGh49MXTwjiYN5-?^S)8}|7r@78~impqdy#_ zzV`El2N&Do%imAGA-hd554h%d@D9J@35UE{ z{%!X;^0jKg>G22jbBf2`6M>zVF$V6)iMfjgX=PBpKQbJ%(O=`En}C;Q{rqL}oZ|ft z@bu%Rz*-a7L2PQT#gkNye-nX@B=B)d~ty zp1_zD$P?slk9eBAQt`ZV>E{~w8DRa}{*Q{l)}T_A^jaE(u7!bn z5OD+bS1bK()Q?Prem@&P{?3aaa7yv#gnQ5b=P2j{eRI%xFbH4gcQk=KP3~IaQ^#+F zesB6Y@qE_!CO?0WJbKe&jDMHYnG0ZGCc(h*apWm-7kCYMU^4U_?>7j3669`=c;$C| z^)kr|N`208pg-Y;d z1P0ZLAABBox#AbtHP$B$fR$9ej3a}^DqaDpq~$i4eBYIYzE6gO&8-^dzY z(v+NC;9Blc@<6}E82^tm@V691&W0mr(EdO;ik;) z|Ac_OJZ@~V8}Lj;kTsa-ae4S$bN zK|%>GXa-)v!0zh!C-U581aJlI)Eos0bE$rt1?t`cJj=bn&8E^rzyonEz3c(=CIvxq zmkl3qCG;ojwR(w}nOL0+c#8uFOp9R|aH{p)0SV*H~I zP8NX;kU!fWV1{tp$HBSimGH!CfMA(natSQhx3dZvABEK!2O~@#23*gCb>c zR52Vy6`w?2s(7_jCn8La9LM_HwR$N(f1>8S|ZkB7|N&w+li^3xlclGI-fidKVoL2?fq^qrL&`)t1e?T6)2!T^7aEoH-CvUO-C4OTXY^ET4D+13Xf0>z2_CD}(j?#9QvY=DI z`;*_#TQDgvfHCgae%xiyPt*TF*1zrl+pk7Rld2^SmpdMIJ*ZIp#0lVQ75|L9M%B3A zHPFu}{)%w#`Tv}9RR3BSR4IeUgxduqa5HLr4Qu?riEN1n!QI8{g#Gvev*XmCS%%Mh zB_3e@{}Tm^nOeoB!;$;lzk4LLvio`-r;}S=KKFQIbL^q*yw2+C{VT6@{{{V^(!a#x zjm=Q%w|DFB!OVP8k0S6G7HFd+4ql=$AG|Ah@xk1`Q{a6#+Mi<{5aUu^Kt8TDw{I?7 z?sdNw@wO1;C~#S9Qn;;g;1|sMAZs?U9rR<<5O^C4bm|e<{fZAnOW1|j{!R9{+zC;B zUZZ~e^hb~;cY?k=8HfPUG6Yz{8eG^O0TQaI%RMf4JXBMEMIKSSO$YeTVj9QI->ktH z5!j4ndP~&6Qnt{qH zxBK;n9t%GuihoXC{Hyx@Pq$8DAYCww_v=Qm#y5~(!Lj1_%a%(8qJQ`UA8;J_TE(N} z**%+?UH^<(LP7DLen&ekmjWF$2w7|~3)JV*z2|hph1&(Hl6inj=_<(6(X;1BM}!DNvcrFyVGd4&LKW(VigBQ+%^E3KVy#)$cS|rVJWIQPSo&_ye>SZd)QW$KMje zsNYTLParS$^SGHt!3w{?JRsbbG^o1fSL&}-`VB`wKf;>17ZcAFZj;g-N`Ius<@di# zslR5|(V&y!Wekv7g{E^$^-tu1|{JU)RI}zCFl;c8F z%E8!W6nM$s{@F2!JhjiOo~G0Po;*>{&(9qVKgoUfaBu#-L_tmcJp$|T$je|5ZQ$oK z$qS92|3RMH=`ZMrG4Nv)Up0p3|Ji^11}Bb%LD4Qhe~i3D={G8Yep=~YOCD1d`%q;4Sh})pW;= zhkmr7zXH{pab1u~b1=HW^$U3ALU8w7P<+ic2!fRm+)RTzByaad>HFa8I2ccowA%8} z+u(1IKV1qQ{RsR?^6B0iQ}R0Rz5aFLXK?xbKP8BKZ*w=fE3TH(<>a-BANB+E%N384 z$CUp~(lv?;x*M1sd`b{N&eNF>U|9MnOaw9Qi*O z)TjVu?+pIe99`k?qh*T3kB9-GB?ruWwCnusd4+#Iye?C~y2+5@39^uyf7u(!Cy28(!dSU9$itOBwJ`Wr&$Ggx(Wq-l998P%XH0f z)0)OE=yg2m{f_dvlm3KE?6tgz{R0t1t~yrGP|lH481bUYD(gBcX4gpOu7{;9{~ z=3bU4d=i?j#eC#?Ls+wkveNDC{BD+TuV!`|l|Ps3trc$f`_XFK{U7;iAD8*JlY(wH zx<>Z=nWk4FKx`udV4;=odywb819yXW33>8c@R#7m>=14XG)Vbxc$IMP`#(z1QUu=8 zn}s9SHA}34I9jjt-ypA5d^P<jvDHX8mk8w}6O%#C*(E28SOWaO_5NqrP z-CFARQTjiVM-=~;eCQtT#Wx4VP@?GfsIdz$Rk$tCv^@s4yk@p=n|!WSE82b&z;lXE zAum$=*9mb1&eVU#bL@V0XVNurly{$h*V;y&RF1}83;m$d|C>Cj^e0S&embrMKT=Sk z_@&pOps9K&sQbj)_rh&Ulq&s8u7`f0A@p6cx@*!~6UB*W^`- z7f*tIEYGk1naAb%pBg0?I2i^}RfG4)g9rE>jhq7g3RTd*$;*}g&A(vx%ewskM7G__ z6y(0dENIGI*aAPR5E^)4{(96_Kwa-w*2M4)Sm7aIgR0ryxUt zI}zQ#5CMK6mun^OZvgr4bsSm2O!9ve|A@R@M-+4h0|ZVvUY`G#ZFD~h+~#rqDG1z} z+-5LSxMLh8a<@(%qF|-kzt@wupd;6$ZBE0k7-W~N zL<5=g9On}L0Qm}X^9{QAAou+L{XMW<8cruypgB|bzWY5Z+>VI|_1*4QE8JVcC;ON1 z#(3!ka@i14+>=9U4-e%42cf37#l>7a5@x5@>0d$BVVTYdh(p&Tglr`wf=Xnf5z;4Gn%N_6R?=_pBCgZ6fY3&b;04N zncJpcrT#LdpP_z`E#d9DHvW~jz)|IqaMX@X_qK4`XBp*aE%n1~p?@aJy8Tw@=ahbf zY2eLw|JVx*@`X$MMy9(G97}^@#ZM<6t@wH5GZY_9UZMC6!o9tt<1=V~SA&f-Sg8zt zBhM+GcN=S#@Q;;N+5bH$DBUeU6AdC?srXp(&5GYdUaR;_^7=RX3z~{k z&_@ZDk`Gn<9rB5ae@Q+=@y+Bb6yHT2-=PEtPq(|7yq~M~`zU!r@g>6T7&5o`Yxah4 z+sDDvFi2f~5WXF|W$r+47v1yypL;1Ng<$tXrN3Ut9}GSTj;^PtU4w9wD*pk0iuT$N z@T@B60D1MwR;=2`rT-u1J6YyH1nAG{^aAhiB?90lkvEoCudJhj`~89MB@ZaxVL0@Q z6`y0def~eJ1ZT<(L>r*iS5jjZjRcP={mVv!rxbsMyiDKg4RI@Qb$AZ33IXD?tUN>jjhz*VG|bn&{+ZW z7m}ZLI(XtZ@U8UI_zdt!5F9zQ^#A)JusPt4GunAB+&f%N!j{Xon)9I=WPpLfZQv9G z_ay&?Jjdn03gx=)s;K*I~r^o~3 z?rQpgKG08cn|9{` zioRTe#hOCDl>9o&rKJzL7FqI0;okgvfd;97-yqZvj*z^@qQxIg|yFMFwju=Rvb$kh@V(udpKge#mw^Olw z%CPN*xb3>@g0qF&CA|1S|E3k6O@rhxjB0mKu$=~BWpK(J*zb$fem{VGqT<7a+rTO1 zXEAu(lqtcVG>9qQ_fFI-&4Ri|DJz8A1Z1uX{EBdIGgE%@?t-7hrMAM-{-ZcOMp96D zF@@KO%)B+*EJCRRpdJq z-#~6|bt{A@%ilKoPb&Z2XL{fNk;5Y;xLpLcW>LjIB`;F^@VlX3p?HaKTjP9Hph@JR zTh;IX-c3PR8O#%Iw`nsJUBj1P%unP=a`*6g*ICdHdVMUHa9%se(=g;Yjv<$Sn7>8f zEt&28^R-_Ry!J>xzn47S!Oy=ZFH-#E+3-`?(XW3;oPtUv_=>#XD8IpR_rOs~@i=*? zz_0%qd4=Lf-wQwS;L(1AQVIgc_<1#X>9KyEKL?J=lzs`hQTkQn<%qi{|6ja|HzGOx z?q;9e(*Qp#66}Y*|BIPVF&{V#3<0mlefaL@0RNuK+_2m~U5B3ro=`kZo>lz1?xJt=|7s;zV+F#~DjV+B13ant z$HMLGh=x(n-&ukEPKSP>@;{n9Cw{#B$1N9cP!LoGZ6r0b1*%YiCy|#bzLtEg;wOgT zC$h)C7vJ1NLEavLSBI_SwThqJ6OICEiG6~+Qt9vC3;N}XPv{kgpg=hq^)q;ps=*Fk z7ep2Rg-5qxZo6|iR(5TZv|UoP$eHMxkI0Ybw9l6Q>2QAjzu)8mcJP4ZjM_K)AJGam}KEf?nI)R%r*oJVfg8$15lq9#f~gbPs{ z8Z0J{k-Jm!ox<&=73Fn7DfQ1kAAGIi4_Pi`GUl%gBol_v^nqi1~j;368!Hj^xK2y^=adcafJW{tJ1LD(Ja` zSs+!h=g5oOs{H@Zi(rsx>kmAIyfo+`~GPB%cM zXe-If75{>Knc_def80baLx3B+o;K#B`w?KRGB}I8R`H?a?Wehw1CFjH4=H{Nd9lY` z`-{ze6qG813gNbelBFnUAI`sDs6SWfn+H&VWr{Z=Ut5>k_#G*zsVfkE3VHr*{+bOS z4=X;LyhQP9gnRkHbX33{#jg74Fg*XCRx4WD{~aa^i`-sUeAv(6g%A5PpC8Ec6rU&$ zqgg*e#jlo!(JYTVtiJ#M76myKxW#rDlqg3r@`U26$SW0p`d9cV-_6HCpVs^Ix zgD6X0t$5AfJW%AUna?rt{6k2^k~gEN8**F!_8A=Cg+_t93zeR6`y0$`>1g6Tsbz3JW`9fx7c@Z+DIF{u1$KPatn9bi+#L z#(Zb*Q7hTy6pxXYD*o?@Hh?^~uXvcJWzj29pjW+$N&l~uCDZQH87@Tbp|dWRfJer{ zz@7KawOm?A_vQQ4PqWM1{lLR7H%t$x)pwwQvWSaU%sxVTB5;l@ncWjLa$=~ciZbQ3S!6kH=7s9Yr6P( zAPPq@#V;qX?d;colRUA9WB#=o0Y`az1l};3=y+GZqt)aI#k-AU&5rl$&mpf>`a4F( zVNk0K29ILRPVhUbvRt;;`|m>+4B=@1i@a@~pLZV(efu0<%gC$zJZ>JQAmbO9CFDC4e}g>#c7K6ZlXp|R+I~}7rfaSO6?>Q!Yw3ME zTHgPSJ_W&-6g1Pv?@w@@lygVi%&C6ETKdai_|d zumuX+0@?OoK!cC1K<07ePB^-SYqhxyJUaut=3p3{Alwed*5kdU)HJ7`iPXoeodu&+-!G(oiu&%C6K;JNekvDp zi9MZ;uAd7>G3BU?JfZl*ryE~wzmxBjbGnXH{X}JX0vKaa&uwu2;Pb~rG&u^P}?w?v?*X9>482v(y8E^n_EZujr%ll`01q4U7Qg?>JUyh`!G zr?tZOf1+<9fSa#}-H1mnVsC@H8tym&VpOyu*uGXBnxx{d6k_tc961Rai>h$~%nwrhBnKu>xiu`4Z|ozKMJhIm>CD>5d8nUPpm; zQgC(r3<$C;sXO()Z!Bt-P&NCKT$;{nWLM);$3Z{*mY+{0uT=a^;dTtgBWe&Wm%*~P z`JEANn>xh7xO>*j$Mnm8#6Mk2$&KP`gj+wA+q{Ctjl1Dk_&6Mel)(eS?b=?fX2;Xi zPb&TW7r;-c;#ZPa__)l!k10s|1oD%NPatqw1@1%M=??#Ny-2uSxN^$R>(n2w^gp%S zKL4Llg70b2{!V{@TH&_oOb&hQ*8K33DClIRe}QnTAJ`6k*V3<%hlP9lPb1FPW1oUS zga+;;vz$Ce?(`c}KtD%*DE&+!5B!S2j{im;+rz#1=IW>6D7i=Ax%!DbLtdW&N*3Ct zmQ1FHf2DhmJaW39AGZkl)r!wvBu}S$mqKUw4Su6RxR;*~T@3vy#or>2_4ex@^9=M$ zd;0lo@`89Dzu<2QQi|WY1dfW&^y}xy%lrEI2>H^P9gM|lSDaW29wXoVK;`&9ar-U3 z3Vr5IE>;M)j>?pyU;cuA=0oUD=Ms3=-{9Fb;P2<5&#sgYmRLW5$9(HV+^nRa_EDd} zwE71Im5N_Oo>lxk@`&O=`67x9T(0=fa=%f&|0%cMl%SU=TZ2NyA0#hPJSW^+(b#fs zcJ$Z>eiB-rJY`$dj(<1H2gqFt8@Ng}_0QxP#rxHRepD?uPm>oZzM($!^Xe4Hn}472 z7Hjkq^jVzqtYbqMg#CSHrjQpXzM8yP@rm-y7_Wu0@So%~{_&hP`2DZIcMvpX;M;hq zRjJm4M;qI1TD}8vDn`3&xo^mWiU;?{?ix{kk}be1w=(}fgC*+EyI{GkD3I&RgWJF$ z{4Mwg+`q?>XTJddoqp1ef9~f)g76dk5&XtDr_IL{r2YrN-Q-=`!638+9Cxkd-A&>4 zu2xJn^|A7C3Y#f~RE}D)1D-P;0czBsd(-2M%?0vg zqy0O8HLiapx+cISHb~x=JfwJ;aETi?N$zGx(xA~*tO5Bj@+*bg8n0EO`e*WBol$K~ zF1#9k65O0d(a#3qHV51|+NN|e{*l=k6O2KyZz*bq6w#QG9+w-G12O1=bhLmx(9b^@ z!xIoV%?fO${u1Ff@H0=qvv(zA=igQe*79@v?kYHRjTp!-SISXcN=LKE1E=}d{4L~V zil1{W{FHU~>n{;5@1MvANR;5fi7+r~dySD7hW(D#kY^P?{W|yws?BM!<({F;Kh|=%-?B3J%5yI`#o8@}o z()NYI?OqcvQwzuz8l+n<@jAs#%X2E>DDgKIqVu@|J|WyXN+~}-lUFHz?sM=HIKuNE zH|`p52?g1m2=E8@g6|yP2L-x~frHN@a7G0fE!^8|+Cu+Jj;-b7kv8B_&yVzfgQYM? z1|e`YzLGphgX8FE1$p{#=(`1Kzhy|n%T*fQQn+oQ{FFbzxk>oGap{|+YU(vsAUsFz zZX}FfjsS_f+`fkr#mVO?evfeLC(VitWXm1!0{m2oKF2>C1u4iWM<dUA7t zpRXY=RlLVb%>Q#r@c2szP%_Bx=v01QBUy_{>Z46!){!<}@Qe6ao4&KyUY4P%ChkH-wpJ#Oi@}zIsVET78RO<8IU2D!onha*A@-20bT%;wau&G#d!t-wIfypU;Pj~okS;=iOUM)Czb3%lN9Fc?dGC9{;lk}n zO1RE6_U2y~3ZiucHbzhKgyI(n_ZFyQ*~cuCpJMv0$msKD83cvpu?hFIB z^xpXj0>sGOLBuQMNpiO`MpmF^6{?`4gxi8fyTHG@^=e)PPj`t!;7&OEQ;?;B>zZ=m zw&_-?0E?(!8S)3%Mg5G@Kln8S4s?b72+6;^zcC`P0oE&n8)=X@9tQ2G{|WW$&vZqE zpH1XJ#s6@Ay1@^2KN)`)yp9rOPlUj|iusywTcAG5(I@0F#W#^>6#s+V-0d%DEYLja|NR*Dh$LI|B$iT0Kne;o2H!jzi5lQon{g%|3S9bjaOs zq#t*4db_=^D1Iv8CvIF{Hjsk_D@Zc{&kfC6+~qb+N8fi~;QIE_4XIg?s@a+3A;qVY z=li&fzjsAo1BXsR&5q@?sY-wwuI&pLxXsP1!3og+n0&TyJ4hRGkh=BbQ;$o^Izo;z|7M9Kj- z<~9UKQQ%Uj5#;ZayFs^rJV)+sF#Jfq-(4umNvzm0)8W4dxzoQAgF>2=0+*vz(%?4o z!F2R1`B&sF!#U}81Zc>v=|=q<$xkImN62r^3AbY|6<71Py=*FbyZyHO-HqnmdsidF@4SIS4 zS%}E%k;lk0fk-MfYu4WgI_on`H%J&MIv`r^}OTB-M`Sc^)7$ zH)mnr=*uYj*reP2zU^SHFX znf%>1{!1D7H3}*(@f#d>7Yqs& zpG#gm)URJ}2K9&e`4!|vmpab*_X!0V<*0Bb9Hn;~prntHSE>MccSFBmxC;RN3FLVr z{QT>Q_9avnclDFd+>hm9d#t65Y z(=^}aB>i7X!Carfm^;arDL$7xqxcf?&5EbV^OA0*K}k0?m&aRPO-6k{=b-llkbNhA_Dst^!_#GGpWJe zlG5LV+l9*v;sQne=RYLB0DL}qkB`s=p*<~u`FAb_u{{FMWCVGc;@6TdQ2aLXwBqID zHHt6#D2@^ZX8Zf*H5wEu{t5XY#W#`16#qlGx3se*+-3Zrj}do9Tp5g|phEGR$g32e zNxok3lyDn3&8`{BLD49Kz_rxp`X@h?NBAE0lj$k$>hx+@Yn2Y@;-`RD%=({ z%mTSt@bYJp|JxFcR|X%_QJLadIxQ`lztDp#M;0^pzp3P?kA58i9;}v zHQszG401Gx@yg@UO+n95grnD8?Uu@lX#<4F-R88DJUYT3cnSx5jxABo_5bl4?J+uf zkF#Jsxeh#3YP`3xQYzdQC_4&)-SOS)16ge=$p|99Ar!1aK3j+9ydV>W^;v#K4>?g)~4)JTu8V89}Bm;Vv||2;4BR;~gHhej3Z;HMl$G{H*l2Jh0%U`O^OG;_~FV*!{{%u=~05yBo=~A=Tnj&al>RjwE7>b}{@<5@8(~nG3=8x%`9IRs-l%2`oPLP}*jrQICEV&~u0+ND z;1TLaj!y*N(U9}+pf6z%xf6nE%&pER4^0DaLq`{LRA(lEM>)De!;kXsxGJ@ zkC!UJUn20DdM0Y%lF!gO@Eo~IK8KT=yP?k^V3Onk@}{i78^UdYrXj9d|BP8pL4_*N zk1oJ01aO0^=qnT`pm?=>y4hAB!NBfhj@-wd%5W$TumT zxg1A0=?CFI>hhmwINC$=kMNqTz4xyy-5zgdg5&(Nqw8asPQi!Z$TjsO;daf}cS2tE zxcvNv^0VtPx%XoY`Yy-G{B;cc<$u)pAJ(i^)$G6xXo2Ts@^Zx!!uQr?3#k7A^>@#|7yiRwwQxHo!ffhGIKkU~1D<*qUGO7YZZvsv zF1WiFyo5aW2zU$liJR?C@E8OSGr(zC1W1sVFu*kO(0u4`r2dEGxq09{sDH?}@DqFn zJfHjhP>;*`e_{ay<(y~r+lIX9SFNU58F^aq)$O2PrFhR2W>bI_xPk?`ojhp^YTMs? z5Lo{EAq7De$np77(!KR%>pSqViSTo%KpO_A{tx{h*b-6d+gaoF|4YB&h$TTm5gi5Q zVVY&gTW~!HZQOf-y3tQKjRHj*z)`({Jb+vV-k%qL12;XMC*J{gXT#0DgMNtXRTSJ)h>|AW1^ID*bZ+%(K0_{`< z`bxML_;Un4jREHWfTnK#u)hlyU5+xhpj46eQHTAMlj5}zT!Jl43?e5)_V z@K^bF#bM+j#pen49&lh_&PtOJF2DaJk5JISrB<^ZM}T7G=u?k3Hq#!*Hr<*vZoU8& z*wPG_T4$4AM4qC)yJ~)jd{S{sZ~ZaOV7WBi-n!sR;kKy*U!W!0vn4wHh>R%1rI*-T zLB5te%mTeE+|H)p?yf<6^MPm3+Eg)xaxKxI27$Bd5O@k5jT3Gi_1WzRf+^%>iq9fn zt@yk+1v`~sDS6Rc{~&r>xNV6_7N{Ky^zUfQj_?{3bT|if(;tuY^rK&aJ8us>fiV$J z(UH3+JLf3~G*AAt_pVtc+!iRo0Pb0j)BXpZBXpGx8e6 z#}3Q)w(0!G{pSShS%FFhb}Qre;^+U5Es5XgXOyVPBd&4Krme^e6hDrpYMIKbV(PHR_;uN?5&r%Rp1{Xa8 zgNV{!u>?!+2fc6sGlCWPSGcX1F3|nY`nk(LOqWW(z}29dTo>qi8NL61I?1zN58}M9 zk_B}y9*lknJm%+d^CAV>VCTayi24o8xpTqOiuX-{r^uVKC1%C>+yJ>t#de%!S4PSI zGZY+3gOSfkOUR0*N@^bZj~YiOV(CqMhcV&&oGH7d?SdTryJYoi+5NmRXZ7v)@5jI+ z?6i@<-Ra1!T;FgyrO1z>{)@JtwvRU=a3}WJvCm`H)NppVbz;15s~_C7N8g)&ul+~O zHrf?R*6OrcpmvbgDBf^0^mi!!I#ajk_XzB==K~&<{omF&R0DxqSemivk~C<-nhkyu zHHc8(o#&_jgCE1aKNF`p!lUdaHtgd9}4;!yXI+IAZgO*PvA8y=&=6?d^7yZ z^ZzQq>l5(!d|)#i^`WCrJ7XS4$v+^!_dfzW#|lhT{@)@`c-*zWIQyJ}lrs2{e3{~Z zlBX5l{};@H)rucZzNs#^@k12ss4EcOo7_C+@0!8nO%%Uexb1@AR9yy6#;rxd?}e6`|J$nzHX11HJ5gYTJtk5dp+ z1}~7O6n~F=wc_i^^Pcbr-b&ux$0h#0+t73=pFn;zg1pI-en$o5F~v_KU#<8+^1`S5 zenwbs^Z&U@Fp&nP!f$Xp`Dn!-BCl5b8S+j~`~9TJlfw73zYO@#DA=hCejqPd=y&ud zd4=LlwxdOB6mLsjuxPg*#6O;bl05=%{+&r)p?I+ip!hf!VDat%o}a1Czv8p)uT$C; zutEtIxB!a3=mI?B5AePVp!nD16^iG`KZq+qynprF_OibEWfoHe)cg0~ZSuXj1dK&~~bhObENODMiHTi`v!%>vm z>*wT4UI7p1;K%(CNrTssiXHMKE^50_|4fg|3(Ph*wC(R2s+tC8(!k~Id1>bJDw+Ji zT|4&k2eurQ)OFHdM805$=XOnh)i!D(L z{V4g3?=Zlh;O8)XKJZ=eNWEu0&+ZYg8{d`he|lFi|G?k@XHX4;N&|xj+4mo<0?#%8 z|AGY#e!##D!M`EDM!3y}zxf1LeIv-9C;#xLI4+wn5D zCEuZVhP=trI)TOicfuvUJm;eXztf<*;*I`5(-kY;ntZ(CUC0xP_adLOROSB{Qc$4` zO2}6zK8ZY|_}%226rV?4yPLEBmr)Q{=5L~R$qN);M;=!E7xDp$n_9G7RPknU3g#+7 zNAhaLPa&^Sd;od#<^Bpp$qN*pNFI+WK^X-z6rW3;QoNEptN2Rt!WaAnT1!3%e9!#b zOu=|%VE#nYO;fx%c}npD@)e4ACtvI1692{*aQ8cQ5SCtd7W6uKk~~kQjQwl!BJY+f zKB^iw7K6?Geon~PO-Q~c$kX#exG@h1_rCw1%!7eD2i#!=cAstp?lPQ-pMYnn{}dg4 zMV_R-yI(NyQ|QOIr$nf~nLH!~_1fRvP8<0d5{KXf|9Sos!o32~(dpdpe5bw zA>2ETYk?Y%q@S;-pZ_AJCE8zvzfjPg0_vMx+tgWQ}mUrwmZ~e^Ebh zDD;0o0Qvo&zqzR>gHhxO#jh7`YnEsUM+?|zA5gzS>3>80P%G%W*>U1d>&NE*6u73C zB?4Q6jB+%ee6!-qJx4OQS|h;qY`TO0fuC+w{uQtTdBk!T)Y=q^z}75HNAA>nE_vo~ z1aJ?Pntu^syb92ae6Hdh$ye0jUi?!iSYJnA3p9YdR`KD&Z9y|_Q6RZ@=ly*|{pK(E zYy2&FNbw#2^7;SnO0eH9)NH8YhY9yu=m-Qpmw{8%pQH4bl7FE1JLI{S;{K9;NkQOc zKi^EgSn*xLZGl2vQ6M+XE;9BmkUSZw^sgWv`U?HK{+~iY$_db-CP|)E{BiQ;EBpn0 zfjp@Ad*sE6$JbLZSqZk1mn**SKB!q*@fPHfSN#PlAfKlAY2fnxUnLkwgYK{S9gQHL ztoTIoGR1EvU#$4U_?8cYTJ3!yv``JYvBzN}-%T9!T zii33Pei&T64sCZGd;oGf^*HwM`QZ+1|I=G=DCwPc|5>^t|Z_2 zg>1W0F>@yLzb8NXTWrUf7SE#n&!Aum1raVR3G#o)1Key}CX@XRj?(0Pso&vyaFdU~ zQ@Kvu_yc&9Oa5@T{*M2VB?`izD;@nsUfB-3F&!QG6ZDg9z+DT?Cl64+oPKWoAM%6L zHU7-%?KlPb6u3+#@-q?;{Uq~jk2f;~%F$=SZH5zL-yhf*k^653Pjo>+=d%Lg910Y# zQjTu%1dZj931md>cKJ#gWR!lxZEzGIcUf|oa9g0{DG0oQf!`sIo#yel*+RkM?Qm3d zt-p!32)B-+J>X~t^*j9v{g^7y;NQT@6fY+a`TWcHTPFe=Aa^JT6J2Q3m_gT1Smd9~!uM+{fec+@I2a z?JpEG&FT6L1N=*#>V*pAv*l|3hW{6(i>3a?%%s6FJ5hrg)pQs91D;fYul*OiRPp7) zy%y!X?@9mdb|G*tj;+&N{xebp)*!)!sFns9$NQlMG1lO8a{>Ysf%m5Vefyl?wcKGn zkv+S|`M)3^a1f6BhEe~}ed91Vd?v>Ea0-U(3;x9v@Ui3%ldqi*N0*a-O@6^W2t1Lz zZ9Vuot~d0ZpKZczh0}4ha!qK!nyIGy`ak$t4fn49vusX#yIyFtFShRjZdzXd+rqY@ zAgp$?&g26W?@3;)_#pCf#mADT{XA}Nq9ErNn3?2(w10a|kryhylzfol?~pH3{7a9^ z`@b0_*i3`^Z}_@;Cg7%(TaBZ1fw*BSr7xM9nn+9m1X^J-^pR0IB@@0z0PodxgB^W@yN%7(2I~Bi%y!qSymbi_) zlj7yzaT8X8MKmZ@{5A6Nihn{rP4P|Sa~1!Ce3{2x`%6nx+>k5QVCXXmSi+r@=^T{VGzMQ;L@oM1`zmeIb1nX%~|6P9# za^!`I*WV8|AKbl2aK=pV z(7E6jP=EHl;E9XCFXV&3FW(0qjez%Z>+f$JaEX*T8v=J7-*_4?wHWwR28fa;21DQ0 z-~N5}J6<}83<7uhd7mRwDxBy~Zr8^}U@ws>S)$!K!;dcGm{r3a~E0jSM zd9~uJ$X6@Afjp=9Hu9Z&IO5mO!vd1`p1)>?l6O-481ey%_aHA;JVHKM@lknk1YV#7 z*V7=a_#Nc6iq9pl|GvKh&yqJ+{7v#;TnRp>piuD|@`&PplMhwAX(LpuQt@`=8S>rz z-;IJ=Wzdhj`6_?SE++4;_?6^Q#S`Sy{5)>%r6A=Om?z1r6n}|)z2YB`*DC%EdGina z71-`^$^SbkL4(FeOx5PFxsq6gP>lsb4ga<~! zk2@bc;y^6n?VpKb%|DPO8s!P(x1QAIu|T*DoVpZ_c2NJ&0QoTRAuLd{gRluz(2skR z>q7FR^Y7;0{S=fagEhjv!0a0L6|DXTgQv+|fnIlf1PbJiUZysKeqbc{#jHU5!sZaf zC~yXyTQC5*J92Gu2zZoDT1rQg$+P6{v;FlBg??@{0=wPsE^vAN|1t>N(dsezEYKKm zcVqEA^5{fxmzZ>J3H=Q92eS*tkY}%h{u=Th$b)wJ+41j2@4CY%wgXwjGUJaw55D4?d$W_&F~BY0&|KOJ+jg2Hi#E&+xZhhSSl5xGlY9<_+$iln}IttL4X3KUq~KNyg&I+aJT*$GmL_mGMGTVK=Enh zYZZThe23x-$@4y{TQQ0MDg~{50{Ln+d3VLXBOj#r@8pveZ*%}!D5-dB%kA_3l}gZs z2Gxr9BCk<=FuD1-Zq1Cjg1oijQ^|{j?`ePO&wD7Cs0^MYpR4%GjpRG_ zaK!(eg4P*-4H`GapbOlFL3aidkaLCGgNumLA4NV#@f*mODSlT|=Kq0D{DB{%L0Ivn z>FHn3K`9#I9A)lf6bn+_l z-TnU%1)G$?67uGs`3n@}kxVFo8ZYE}ux=o3T8AG1ce`Js?f9}{jGP~#h@0kz^8H*2 zT!wQ$d5XL}1GLHKdw_mNCUghV>L6D@Y~se;kp$1Ope~Vl%uB=N`Jd3uDCsH&sHuiQ z=1%aA+P?&UM(Z^V^-G~d1yQe^p1+_wEx}raT%QefeAd7JV3sI1-+!W4qQwG9)Cal1lRh!1t-bsZ0kL&kRX7ULk-1x*?(qNr-LDzc4~f9v zDy}mWn#_`#jYEzHAn;8=f%dTm0mXHVrwK=QKd5|I(Re!Zhp`A=tC%Iv1i?VVsH(muO_I( zJm~kPfBS1C&^54|W5*JtAb(Bp@9MaDD{^`IHHW+mYh0gxc9R#}h23x$^1Ev}{%x!C z*X{sal;B3a_syH|Uv9!5dichEK35ak^&Qu>`OmVFoavg0neGq8owQdf>OXzc-y zk()i^Pm1fsDJcA$B_Euf>-bmc$nzQkEN6h0cf!$_>;_8KU2$EYIQ7kNT}z%KHxH#0 zD+E7Ngr6#kJKz70y^g@s7Rb3?<06)@|fW5$S(`tk34;^+y7W{dw~$lqTrO^QS#_Mx1)-8 zmvZ_A!c#bGO0I@M(_9ej z;UiVamEeDJ6b#j;TxxEQEe8LRtJbYN%nEa!s7C*t6j#sxl&}`?^otd?%B%AL?I;{| zI~qYAcoW>5m^@nw`jY48ni5_CeRGQTIC=10KL5{eFg zv+E*&j{$t--#J`;(Cm5uN7At#{K&qtuO6TO3DS}IdR58#IzVA7A{>=z03H|o6!~7k zk2FMJ-#TQd7c;ujPi}t`ZL10eJKO@R z0r?rhTay?2$z9N%d>83W^r zlRO}JI{6gAyOM7bJVbs;aC?dp=q8BmL0jI3rnHXI!1J@aKo`mD2%fJ5YPMYP(&Re? zuK{jb=Y^m-4Js$yfj?-4XE&_>p`hl6$X5ozBfG#iumXSbfFh6pf0Mkr+7mjR_dCs1 z{?oZ?4JgPDi2VqIEE+uM;fcl%;ATTn_CfH-K5(;&o_hj3@h!MH4bL|l-18H7d+lGh z|L9f4)f+VG7YW2&upOgt12MKgn}O2L|15Zj0j^yIx8+t$6m;51^1beYW~?iP{eMsx zw5ZIj7z4D{B~^d79>kW*a#E+Bm;$zbAA_e}lGHb;u6ePNlj3mprgJaxRwcl}-OLF-(H!2D@g?_rwZ?CxCu!OjmjN<&m zvVNk#^ECpSyH`D%!62^ZYV~J6Dlz&I@GvK?b}Z<)=HS8aq0dt;YZG}$@XIy@VG7J; zbHj877CcODvB^w;FUdWE=YI@-yn_45ZJ!W~q##88BWt#jJg^%zGhewlLLTI(G3R~v zJkAV}n}R+`9s##4BS>n2UJKY+%szi+3+#L%i_uF=Z{Ou`^~$Aa<3cUrM|Ccz=%#O# zegXvwariyv40|>H%C|y*Vc$dbY1X(e`3Bw->PDVP-gp@fF3gF>uZru=B{TGtn$WUu zx#-4vPI2e^|AB)j>3&{FK zvUvsdmka$*$TN<+{UjW&_Wzy}ZoyF+qzQh3yp!O0%A=q&1usdSDR?#VxaQaLuj<}} zf&;>!J$d<)?t)gChz*7J7mS*roIe_-uzaV^fIr7ku=jZ^(-Ct07K{_WN+bLLY2Y*r zcG6($P;ei)uBZNcvKW@>&{^m=;SOp&mv28OG&5B%{S7B0p+BI%=T7)J`y0RilSn}@ zmyUX7;LK=Vv~d6lvfinHVP>6jkAjWlB?aF}URm%Yd78tsjlVyY zKnG5iLEz8X_D@s<_f`To$8JB6$I4Nk1%0Rz3YsngKSCbK&UO4wN}vOW%fnHOfw$0L zRdxfVzlZ#c;HSwwr`;L4OzsoBU}Zl4-(LvIDuLbyoD#eidF5Z+0n*9)3;q=OcEN{` zdwvz?{}U-F`KvoX26;2V-yshQzL9*e;5*5;U*l~5Bn7$8xC8%5o+fy%`;eiK;Kj)^ z1g}bdS@1?S1^%<{z)4<=dhbJ@FuUOw&*7_h!K&bO*y$Qw08do`H=EMe@4~g8pMEA$ z|EHqhwy!b_exqQ08UzU%m{%p6Hz2RE$UMX`p;awUZFuu7<~D))-P;r7d-bj z@H0=O`f-P=jfv2oN&SsB4NPaL!VeC3??rFFhikzheX~dfj*CvzmRl=d4d{2LesjKN zA1npFj+w~Gx9I~MW%d~ghN#!+_0?;t0Srpfk>@;k#1H-q`Fiq1J@9+EZ6B=OA=iE) zHNlV2{|6Q}ChIsl*x7CCPe-7hW)&&=Nk3k=k;}&gk&GR+VPhLYd)oL2+Hs zP&E{^Ff;UYd+>-4JWBsRl6x8{uKWLZ8jS6Lz|%zFO%Bg%tv`lNYI^k*#dTm0XU5MM z;BZH9s|f-RB7dn93)&2PzKZLNzfaWW(5XR12;O2!J9I%x$F48ykk`l;I9x4BBBei( zpBnE@b*ZP|-$(z|>1X9reE!E@8iAWr@Fxu-g4gc~M@hjall!=5G=9Dz4+~zn8~k|7 z*a)1(z>}0fccNorSZ;NAVe69Uq`A67KU@lZ!VKedhpPvfMN>{Ew@ijG|5?@!3W^y4 z3v@>h^a-Ef0f(y(i)}%l2vC0xd3E($G5W6;`48md_@RRl5yKSMn_EvhGW|03|G~z`wz`U)PyYL15T!v!8oZ{s-js%g{wnHQ zk0C%m>d&kK{Y655vEsTwAxB^3-yFG4uL^@qVX%mNt>CK_*N$QgY>wk{J^()npk$I5-q>;NFiQ;j8k0*=g8aBs!6etDrk+UU1}zBy0)f%<--e}cU0IkEr$n}V<~ z$nQhonSz%lUn}@S(lDCjQ?UMCL=zM6c2;G4;F{^2grZt|)wuHv7hpq)!#S^tn{2!6UPZXgDp zL~pOeoloU(zE2KSOr zB_Fa2Jlr1oCP42NI3JACzqvcsxG&EQyT`Ep7h*|=RKbnKm7=8ebz_!I^n zaTC7gCcJquTocBJ!cRT!KdjG7LJ$Z+U{1eY<3*=MZVI%qAulfJ$neqYaq^j9jSXK# z9wNt@siyv<%{!gfOXSq;(_VPUJk$*Z8pRsVcn^0pBOSn_6g?9k}0a14l+s{Z)KKHYhsFbNnK@e<1YlW|MuPKDDYhEXTR)?a#m&$JI7muLZ2J z=@UPYr&u7{2nzAjXo2AfVE8fp6rAp)UBF-EW^yr~f{O*gEAj!R5r5-CrIU?4poaxo z@9_Wkh_-G0O@sb4Fr#+5`bw3vDIJUeeHnN!FEEn*!RIo-o&Q1K%K}Bn{~!+!fd0qi zjZ3LLp#J`66E3f&&8C^h;|9UN-08gQA?%c%$ihNwwot|DXh&)vz~Q%_0VUtr_(Ueks$eDk4 z^+nCTV<#%Y0u|~9u70P}A&-;a@z9O;dQ}zI`-81w#%!p#Q)Bk6we&OOAwK`(e-WuR z7Y0XZ;GF_)R*42R;K(-_+??&qRa^%?CIY`jea}SbnHRiMEhO$3uSt^;9l4lrhYBo{{bc#IV;ApC98~wM7261Bm zY#kxbdEOo1FLJNoxoe|9X@c7&DCi^v4=Sz;lw^jwFz^}b_YwM6sqYV?0_H~K?m7q@ z68a|+ zET$kRI@d)yS}Ppot&adn!Ap@}65K~#&eQ4kUa_mM{hZ$KUwybbwz!Jk%Kchb;8Oi*~xQN{m?2D$%n*We&|rr^Jm zZxZ~rMyT0&!HbiZ|JUvR0nPRMzg>l(F%2Suwd}eU#A8y!;$$k!X3W*9qtn~tHR%ekbJ>-Y}=#kT;`}|)&lIFeJs#;7HE(2>6X0K zYxc)bHE+HCq`vX0_h_+sD9}dkdIy!k-p$7*m`6ud8iHHTL*IOiwq9d!|0wV^tnz<) zZ>anySWw&C&Ccw_0I$MeB%7eU+5L;al5@k-gZeoKfk(M@GgrZ59Ip2N zkrxoaY#ee8hC!06Sq2@QAP+>K{}MCt{xeEnO)SYd;Iqhc4#DoZ7n`^a{WMoxS1dGF z>FfR`i1`1$?MK0@#y4WP>`g7d2at*#r0a)M+DwP z9u|BT`F6pNkRQv=b^HHCL1oLFOQ8z6n;~#Z!Ap>b1b>h`L-5ArS%SAyT*c309T0+k zG_Z2G3pAFzyx_CQ(*=)`4;K7G@<7N)p8~(${_QEqpUYjK{^UNvpC?Zf z{AKc>;7iHJxVVbHaUwRKq2=y5e<2^Kija3?Pd$7Qk6QUwLEkLLZ7zX(R)VKd|27_C z2guDm;)@@t-x1U2|0(Y2%&pNEKEn~JZ<6~q`Z4|-r~h39Fpq4_;m>jUR)GJ+z=z1C z{x-fLoqC7+fAcds+xR=3{E6Xr!!ORWIhd3OcXRt{iucB;iQ{^W-{+sb* ziyFM4pWV=XLhv{B=JN)8vf3N!f+pFA%%b%Nd3X^58{Tgi^dsc9IpM559D?8*Fqp$k zG#vr%Wr55qnqQFzqR<~o{e~l{&&-);Nyd(1;3d%i6#BMxW;6tGI_g13eVzr6F?E~B zw<)eKB!Z&J@{YkSxePn0y1C^1J>l@emL)oA#Nl>ct3M6QCD;#iG*blYbRtJ_VhOfPvfbW^-Z#3e=hWw0f>LhoyS;WK3LM^4|PKB>%_Ie}PkPX+9^I zd>{Nfo-5dG_&}h4H3ViHznveQ%l9F8D+YMIHh7d7dX)iY=qXlpMqd{6%{w7I>SNTD z_ylW5Bl=nD@WQqgVGYbxz)=XSs2HzLsoQCK-0v0oZ#Z0iY=Qw)PMp7=sXs>O_i2Cv zb#e4n{wvVnZAVbp$`l5t{iH#ei|HU|%`M<)6)Lygr7i#kK0 zb>P2hKf3)tS0@+Fj3xrt9}j~FHyUdhxWWYRz4FB>#?z_4l8aoH$mm(c zZC#=;+c-djXTvB^LKu8ReoF9v71x0i^kWV#>P!UptVKb~(En(1|JoS(f1HA~6j)4A zPx3z$*BPqA40*_FPC{GCU&$KnaP=J!k7SA88e`w$p25FNKKz>GJ0(qB- zC7h!4Vu9jDp8@KS-!cV$R$aunH@E4V*-CJuCiwOye1)1PZZx-V=lqc&=8yg4YXv_` zZtoQW>oLr9=LIiJUOta|#;iy_Mew@halu=Xp8`kw>n!!4pmJV!fZ^or1b=}%D)=&f zfH3$8I^A(L!ILlZsh2OnpLDp2KY{P%$F@RXI^F$^a9!a47JLOAwNg($>fW9rZ^4s= zOT+NCTxciscTj)uaB%gye(HP4^Y8%&oBqvI-J&n2#uUfBF_`5Ts8=dP;7%`~2B|Hm0Y<-Ny-V(4ABr;Y zzvQ89(EpD7krz?n_4YCJcC!dga|G(cLn81uiaU!3o4{;LicVErb;i(c1Zcv0FufJm z&joGdTl402`~o#wQRqy|XgriQ5AdfXu@ImCu z1)o5^L-0A|Nx_$sU)KCu{#98vP~ge$PTkk!KEV%?FAzLM9vA%9mdLbK;JSY&eo+cS z*#x?y-bcPj@HFzZg108$D|jz*&mGqTYyYEKa{u2<2&U0sn&7XK?+|>o383DZ%l@~S zyq(~?$rlt9`~Q;^91sTokbBj)V6y)ecmgTyBe<75Q}7z(XAC#(|0o5%JKX^~laCa9 zFnN~XHu+`2Um^Dwa{IU6qF{;;WRY(d{2TK8h24%0kyjS{cXGerIa@iIQ_uek!QBv8 zg9X2ze45~+GjKOMas~6m!)%}NAAv`I12-2iwL0*ob&d~|rpo_qG#J+r>$=AgSXMRi zsr=kdfV?32ph?gVTt$Gopy&pk^(Yd9gCS{}W+~jKMthP^q)n96(9U!=^3x zV^yIe;D2!E^NQwbLlL_SK7h;ei@cc~{}cREUUXLHBcH(+KSBRD*M4d07fbc}J?2IC zdOv}`WE#EzN9HzttsGpAS%H68yEKG;tVyMw|J!S3U?lmmn~|bn+H? z@E!-12}oW`wPZ>)UuyF*EKVKO^`l@;XI|oBj_^|1dx@9|GLP@#+g8aDai$Ez?Pg z>%g6qqwIefMxPZh&jp>Ke(JhD#{U%>Sa%@s4{XaeZ4fv}M~^bfyNc_;mG5!~{+Rm7 zg79OGbc;R-{r*C~@{=|MQ-q*C4I+Z?P&X=^?KY>_IV{kQ3~QL4%d_nVEAGs6ZUbwT)>k$2mVo{g*6dgM zi4_Jn2apZsz`yq%aMO9$Ib1#e6JUyrp!6#+2o#5b8Gf_Lt-HYgWI>M@emA&>yw+U! ziLs#jS1m8v8Qt%WrVR_;I7S1beGx+{*q$C8U z33|MWHjc1BW)WIO9u)kr3Vfr?6{fzYEd1wVhH8_0%i0i_JDOK+;;2*yq_mHySvB&I z;7!P*f_ETaYq%MIBYI-D>Me%?nVZCY_wtr0YtVo-c!%6ajz!tBs_cV)ROk;SPYP}i zoQGa29Su|^y-`X}s?_P;n|=nXpINjjD?fU;?iIszsl)SHbKi!3XI9`P__wd}zpwq1 zd6U4~n7ZvIb+p(=zFY7U<|$WZ^fl_Aarrm-SHjynqKz*JNAI#}f|b!UCe>?tp~+GV zU{<-Wcs>}c2>ss}_$fZj8mk2UkmfpmjQe?)K=IQ&IP{cP7tnh>6(E*9)ym@$-PsktUSYO>oB22H z)%U1AaidXCi+v?`G55^aoV=LeoyjW;KFGdFfEQ^{Qy45DPZxY8c~`+dRb1CNUIk5K z?iHOQx5HH-Sk5Ns(Fvnquy8b-e3jrC>~#JI;Ky{jr}S?`s=yJBn$`4wSU>%$n*jQ@ zW!kviPzZc<R}Z05ZBkB z;(B|2USwi8dCB6}Mh(W_6bb^@1x_92k!K2?Nq#`^kI6mvTnpg%`Ifwn;DGvj#lEwtSLDCLewVo@@dAvYY~Qdna1X_GN~ei}E?J}=B2#@O*%|t$*}JN~0q*GlzKusU6>Fexd7cEf|E6G= z3h@7jhh@!Wfvnyz=*^=3L>?kH?~0UriknRGa@7Bk!_w0SembFIw&h)@N~FfCrxyfY z(_j*LlH43D98z3wK)Qd9g}5^Hy|1BHdtP!~U|78r*ZyNHkhzTi$^QzzL!cN9Z{pHk83H_7gal!9jgbKW<6x0mkNvdgN6FdEHxf1BkwL^5Sp3mc`G&BHBlb5}Bnc;oGudtJ@ zzd-<Gp{lKSPk^8Me?vk*M2wbkFEt|-uDQJ~f2o)Yfy9ar3$V#mPGFu1Yu zcLPt-zu5!!UFlPo8YQjN_coqGGrQP#lt4QQv827|C`Ilcg#bU1*INaB?`Uv*RNAs8 zDxS+KWcj)Hm}Lk3O=2N_1@1bszD5}QCC0> zKZ}8N!|K1Bi=9qtTbs9(1);&CO5oHui~zYfLA|01bfX%tWqb%1kgoU-B^dz2pnXqvR~V^)3A$$nIaqpZYY;?PD~k zKu52B0B*g4z|YXrT^I2QMbA9&a?IQ$@+dR$3;DEN=yZ{3&<}9Y>Nuo2_Wzy;1jZou zHneeaHn=HJST~Jo%ft)dX5!jTZZWWVFu}6~`Vn%IiMyj{;^eE`|C<1#wLk@s28UJZ zZq)YwF{M^X_k3{c72F~5&qqObaaAlBlz!O$Rg^%tadHU^%CQNiE3P|{M+8_z{YV1( zrtJ?tZLADSk%436fqpyOJC2dH10y!jK< zXF<)krN)xmo;TpA8^`ya)-Z_Bk!j1#y}?7w&|n5Q+aKH;g`Y_*>8gF;f#u-l{=({$ z;7RzmEuCQf*Z!PKaE-skKH*^ilZoBzMAq8~5aE$Y@ulcoaaO>5(s4351Jl21{|h%1 zs9~v^;6|Npnc})nj1g_Tj!hQ&0R{TVsg`B^OZ^O?U!a%rqu>9{5`xl7pgW^)HyoM6 zsrKZ4!Do;M$W4Yek_QFFV)BjCxEYTZ*!!$6wC3%GW4%Tcuc~tP#jk)s~@YG>& zbCmM%Q1Bot@D>9s4S{?92mP}2^T=!90T#&aL4)VGuE$wp^DNgl4|82-f!b4l4A=X> z&j?^n$*VMge)0r(ZFZtz4Z#zvfX<`(v#mqjAc!$_chaCo7+lu45f>HfM+7LqiEFaq z9Daikz#8!;cEbzyW1nHJ7uGu5R^Moxi37`@v}~GeT8(_o49e= znVFcQIclp~9dOz-_zaovgLy^4!S(}^yV7p?(r z=7XU(X@VJw>rr6+j)InBXZ!`3R`(-yYXX$^C-Ru!d0UoudUfD3GQsN$tML=y$-lvS zGNZ>%;Cp}G|G@h*8TIUw5X9-IBL%a`BjjcRx#tx0gXEQ{KZHEO05!&U~mfMY3AKVJ7c^eyPymT}aR zf&?9zz#GUTf*1G$jyw!tD$tueVIi>TTN}ue)X(FrDXRSo{s~7>3QX$ylBaHkqsz?D zr{oEy+B89-^Y9bDid5&|qBW2_Om6)DFj@V8fj<8aQeaYa{}lYPfnV@`tFS*vacHq0;)G>xR|GRc5N*D5TY82dP!YMES z!*z!k9St%OAej$=$1xKV$%6&JJ?8oUFDM9kAecsjJnzDhRS5i6*5C>%Y&OIBj=NcDuRcY(bMGdhrsQc zOkD-1bLF+#2HorWq?@E}DKlhw-8-cZ$%_g81$lWlSHJ&v6o<@KEtJSCqaXdnRVxkL zyz%ht1#o{;H$OriByWKhuwE&H*Ycwc-TGM%Yp$OEiBoWyDH@v&gSa0CqnV+)eaks* z>}5e8V-pk~2p+2o{hibga*YU)r?Eh+pOx^qk!Tmyi9%nS~;JMu)Er`2W~6BNW%0+uM%XWgXY%?$tU+ zpuSQihF{zF;V8z=Rh|Jd$b+pAU>5`YNbYF|zL9&kqH2cKQ+2XAcq4QEzd#Gr1R`sE z+?kTqMXD%Jr4KMqWC=dN;p%(9{oKQNCAs{)0Q)Qja?YQs+VVzI>C0`<1fkBTfw>Ak z#tn;~+*}D=WD|JFOR*{6hX4Qn{Ld>Fu#84%Fqo(FtwEbv#7Hdowg4` zz@@;tZ5~cQA~a~p0==RNqNI6BL60E;dKZQ69(D6VfwO+I3CvaMZpHQfV1ejFC#WBK8ckN5HMn;$ z{6zYJo1b>+K<@7YUXdl8Wh;RW5EB8SWPTVc7VGgP$h%4dAF5 z0zQHKsSvo2d;xjyVdTT0f7s!w{mb2f+ianp5SSV2z*Bh4E-*B^fn^n6%j^4)o1gnw z-@;YLcN~7^!sGr;;8}u~Sg$&}t@e68A?T_EdXez3K%H5G&DuZ>%Qfun=Jwky8#FI$ zb)p|H^_!B{$#BmHFDS14N0fi3|Dzu2W78A_*aT)c70-e}klY0Bqqq({MpPh1{Rs8V z8u2fAjQmb>{oni}1V~&LICYpy?&Yvi$4JiK5po~7IT@+GQTb7;sAmAGRDv}aNbVa5 zUYdOQMjHl!K@b#WfI~D0kvAtV_A&J1v8`D*Dd`HuwLyReW=hU81QSu3 zC}>IYmV#F!?<#l`hpYF0#|S}t8q5^DKY6C$$2;J#IyecL=*b#?k;KFmeir-=_R=or zz!O?u=iju!f9jA~ParXlS2KasOvB6-W+u#&P({ZC?LQI_*_s^>)xKXcOz^2(Nnq~$0dBHc4mn?6)m(g!2=vv;* zljLIr|3mQ`6{yHibl%hyRLo?qE4k+da?|#2Q{XcKraDC)5WL<_w0%hMab5A`Ltruj zn8T@Nx8jFRd{e=npnrR0Jv>a}V@b{UUYrIV6a3!>;32{DHUbX_Ufd6!nvTH6f0HH- zx2=Q_SWRIN5svO_2A&W+e-)BuDGoqIt%>pspC2~1MF7<9l)yK9tCIV$g>;; zQpV0--Qft3Xusb1@7p+k#K^-75O@RBtv(~5ABe6+|DQ?0G75Yn5a25LS@L8Qd?b1G zk<8pk@Rcmkc=BL36lehT|5996%yX?`h;QW{1xLZxP*U@RLo4!-;2Gp$!S|C#$juwl zHAln0=NS~#%m))}3gYe7Ib}4x_gnJFVif36)}X|*aFmz_N9D=GitCz{zg9B{=2AaN zKgYNTogueFbo3Y<1;!viY&HUz#pX@Lb$~h|z&h$D-b6ufV-w_j4t|o$z{3pOR&m|u zF5y8(+bmkvM>I&hk4#Krfr^Yp;K3qrCB^lq3BH2>0~p{V^3YcB3+#-S$Wt4@n>m-+ zs{NZjj{p%7po8K%KwiT4jDcH!xg9fmQ`dN^aHuT@2&>@F68m~$ml^Vd3 z^Z%bCz$;AMo#Wxi^DGRovr`2nw?06C4Ro|XaosfAMFmz;-^Uumn`K?4e%FfP{og_p z5ZM123N(=^?Li*A4S`b(yqY{=gTKKF93hXhpsT50n@`*Lr$B$Z`ToB-h99F!l>KiU z4f<|Ff&OX$=~s&DSE^%trP|M7Q!$JR_?lqc4`JI+B#*v^9Nf-={uO3`_)r+U%A=0Q zCNdMxf)D2nzQyFhk>H0Iz%vQ@fm7(bkLE%_gXGb3;9V<#FCzEa>=YhWd;AM@^bXs; z90YN4-!$+g)L-}_^pg|8%>~J$Q^}`*ccp%wY3M79m}$;`mQ|91nw8y6P)%_?3M>}1 zG#$++k7c4}O~`kU`^q3gOPQfkFTqb_EA-nHaSUv$0|kLY5S(PH7mz2*!O>u*=x6fK z1k~(L2A(n<0Ya0(|04I#0FT??X84_OxH|t&-Gu=AxcuEW69$2CFz7``+sS>4!T%<2 zK8t}Fz%;=b^5`V!e@Xq!m!TilO{Vj2+NRZPv`xBbf}V=&CI~!?VKb1ObP;*-9q^YJ zU@v)M76O}-lnN2}iE`r7`v9l?$5Y^42S+RD=zGQW#1g#E-6xJyKh+ZYTiC|M=Rkjz z(66evu7IZz^e1unJw1od|0IRM7&=M`K7%~}{q6!SW&mq7`p_m;;G_xsI0ElsK})=X z0)-}W<}&wc+be;tu~!7>PXkYLIJ(3Ds|`JtS$PTooIzv(B?&h5vpoB>B+VUVV{ZnIE(7&K*#Cm7C&WdM2F ztMHR4`~=7og7*Qpty4lUMhSG_U`GV5!2p?bWL0su{U+*%x2AH)LHTmXGfcj%k_|NDyT9nRl;m4oH6epOt*6Jl<~ zI`f$xf1?+|QDQ6{nfiUCxNhTOqQ*PPs|tRYe*8V)rv`g_rPtsmP3YHG+U6lK3MRzit8H3#C61PitDC~-j9i>6#Z9y9m{uW)u+z27xXeIe&!9OGSR5gu- zlK#K|o)`k3V+HPh0~yK`8ER!y5Td|zmbv8pg~0*xpwPd6F>2;}3xQX##-kM1P18yE z*+P9gI2#5-xV)BF0)sKaAV3}#`~`=Xuzc^~8j@?1wU+wDg#PVOi~|0Skox`~Q?yJ8 zbQ6>pDczvB?h}c=D5$v-Iz;_GLjMoyhbKXQ6H{7lDg1|B`l|ocrXa&5u&fq}>%i7b zII2TO3(1oof}7p#Ir>>H{M_;;n}$0mbFn)}an=9wSet}_tpvKw$}@Gm?yx?fBR_lZ zBg|aoWeDJZ9=&=Q`3A+EPA&X@Ltgm-vH$;>f;1(_{`V&XM24frgW1RrEN9?Z;NLPs zv&nrTL&p@?1xml}ALIWL1)=K#Cw~675Ww?30(`|%H7ED42LFb9rs6ul6yYaI{lK%( zH+?AimW=>W3QVdSy$v1{e6iyC!lMp*yE!r0qqu&eF_Q)H^52s0(Ek_&{+j$L#dSfm zY*EsoN}vPy8NiH=wR9AE4vzkyqlyQmTkRA!5Fu|dQEXX3cMTzW@bE0 z{S2Z1m*RT3dPXDgURI#e3h>BURNzJOaf++)m&eK!jv_Qj(UH0Q{@gK8Z^;V%J>*Hj ze<9CV%~fOT3VCJCujOBrrO-;YStd%lh+CE?$o)^?LZt|6@SftjEt`n|o2l>N)Lw`B zc~`-IfLuSL=EQHR1Ul8}Vy=Ff+$Z=^@;ZXoc@KX4g3nT1H;r#Pn#SyuMy%%kKPYN2 zbu|nUOOT1~ye9mf-2W=}`Hyk@d1J^#T==O;eoXLma*t1(|94darxUG0;JcW*S>!(Q zf?QrV(@`CtyN!P&4+wsmypQ3g{r{t2rV%jkogbiPQNb&auNAy5`F6pdAU`0u-IIcp z5R4+vS>0W;m&kpBzoEF!Txt_CH=0ehTX8+11vsIZVO(~N!)>dL5R7yLC9P@fM8;qf z46Jry>itJ?9r&dR=v-r&xn>_CbLpa>ofOylq0elz0|L3hwkXa)*eTl>-Ne{vlhWeG?BlBWbOxE=*ce2G*y%cnhA zRy*?GQUqAZPWl>o7>f+}Z!fd4qummR5%iC{XT)+-*Nlah*Ev_Xzwk_W@s! zN4PQ3*7~nu7W{;TpC`#TJtThrt1kr!VK7#49XPoMfq#a7>pXeN zDe8Z(xNfpD*Zk}JtG^R8@b818;#_yTY=ooOZ{V%fBMbU(8F`ACI|*#v{W0`IIg#ow z*#un`*E8%(qEr83(;#>T0p4e4yl)d6r4GZ92{4~LcpCZ^*N6h2P=6ux)wb37n?N3U z6}%PsVRAe9G6eN0sQxKZzc1pk!$nBd=&7kk*<_9w{e*h26R1uX@?V;kGD z8fs=A3Y5i)z3?r+{}X=+g8mc?+y#Re z+j1CrqXY`tM+9iAxDJq*3qPh$yhr`G(BDk%ttAgi?!0l)dF{J@Kmdz(wW`qIRmHWV-1Xd)4bp@`;UD3srQnswI|*K2aosdN&L8IRc@ue}y;f+5{Ka@PHwhbqsjea5!j55?=;uX|5&^tG2?R35!9fa zsDZ7xPF<3Y)b`o=+eq%=)NA-(_x}g!=;31sJW>RHTyY&Z!G}+d zQ@`SII+~7}nL8oXPry%x@bd`y+Up$aUuO#9*9A_9XUGo-K2dR9Ab$n|n+hbUe@W<{ zCohub9^3#fs)BKbxM zbngudgP&;-=N9UH7BqGm`ca|3m3)=pd&#rNk$>gvj1uTf1ZJQ>#TekqFW@oqdE~Xu zP=6-$CzB653+@|^YeMxKZ_eLN@+9@Srr1`2-xz>TtC+xD6xW&9D{3%=`d;pQjQ(fj z3Be1c;OCg|Q&Dke{~wxz8Z2iGY)7Dm*+Ou$`laY7B^>4a9To7t0)5km+W!e2A#cFN z>3#C#b1FkR|0YHG&ZDHB2JT*3T5+e7vbUQ8jko~)szQIN;#%L!GoOL1*h%UKvgteR z|1S-aG?+<)9v9&#z5q3gkbgrSV1~?EQ2!DN)HPcGZPJ>&zu>(u@%%p`1kchSQ}7w& zYXx7TxUO-6&-;GFRG0mmnRpu&NU;KA$UX1ynXLvCd`v;03l0iq(UI>TI0_8{Z_Ja= zKIExC5MU|&WGSvY?{-np9mdbs&~IzTU%`J_0}2k_0Z&hor}knvwc~0tLvbCTSwnYU zSwj8TJ_JbPk<1Zts|YG^oE5VxUuMl-fxtY&*^N9A27isK$4YV^Yy25&d{uF0;t~Za z{2%-$kDx$Ub}j2MaN9~zzU2+dO6J+ft_mUewg{~m5j~q{ss#9|E zl*3j2ac*f@^C*ZNLtw-Al826i8%OtCWq=dlx3Z*N$^9q6S2072$y4M{Ykl4R$0-P& zhQVl7p{m7?N}mCLlx_c<;yTqak?L90j~75+S(6Kqw^2VX^nX&^Isf@3XG@z2h_jZP@MmNL4$~e0LI`d4Lpt9y}j@) zC}?@XE0Na`ygqr$Yn7Wn&7{XFK}@c{|W^Omq6W) zzm1)%u{(7Y$;Sv@k9?-!t;nN-_fp*1|HsFp2{v%tZ`T4n%qD_2Cx0*(cw!3pr{u4a zN2Y;aA-`<+Oz;pp>EPShlylbM`nNU(2b4g!#one++(X^MTQa^TScNGz`qDHA-<^ z1L$q<6cG}tcqeDY(0uOvS&_-EvvX094rKahJhzdrw|=Kv`134?#h`v_j}4rDGQ zcscSZg4ZUGWaCc!78GpCCeZz*2l;lvN06rkpGscj5qFJWSKL`G`C3k8cE*c$6w~qZ zSc8Q@zJf4FHAClWMuP#0YyFu*e**b-!ROLXv<3XsqMzT%eJyPWIJ~Xy9t8Hcbn{OY z*MZNA06&lydDLCwQ{~JJSccI#kHS!C-@1lV#}d#TOnca5e+<@VX%M( z4;Dt?u+VR+xDF7bzS)>$Q9ncI?<8OAaFc%(WIJ(lcx*bg1nvJLGu2Bk5XJ$z%y_?^52G=%nxZWMHp-+ zUnTfKI*N}&&2n-hQ=}LwkQDkWTQKkpT*S37^Y0H@pgyk=q@Wv9_aAwjoEI?am(ii0 zAb*GY?KM|53(rJ=3ar=*F^%7 z^%1U@&BG_Jkb8RL+RxOu#A@ir?{~O;?Ps_jW=6 z>e3TAUjnAc^(-5dGgAJ|DXu0_#ZxXw5b*S{2;e27DVG zji?Fks|9|5ji1T{5Aj;jWG-J$e6%8~7xcYm|10E=5>H%!Bm&t?Z?Uo6=nLKP)MJjUA-~t7KcHryS1T}jhfUgR;xtBAQJh&Bs z|D~UTp+(9*<{(lqkl}z7V&>w|@+SYxOAn;E^4boYI_T-V5z`rJ+NbY6L1~I^|N zZ=M+`H5vXRZ==QwsNdD$>iyruBQP*+^AZih^}%1}=5XgMIEvQ;-#|y!%itDYt6fN* zngbpi2>m7GXBUGf^-C>!{i{g9CripXGne@wiHH1R6b9Z>NZljM#Hgj*qHrK)jSm)?r(=;H z>*7;RK|V7+l-wTG76Koi;WXp*EAj~6kgi9A>g}NKWz9yA&$|wXd2YwD%omIT9Z;YsuN9k6{}XcQ|022NEZ-{skJI3xjyJB^;G6Ib zDxll{TVo(URYByTB=~mSO6jCHK@u zMwhXZPVW8y_Wwz-wNgLM>h#_SJJ;=WRGmCYZu&%*p3o1F*QS2{0@a+=(&B1qwqlJH zcUH?D>(Kv8(qJ(KVYM^Sf91))CXaBvH~NQ1!%?6lM$KmGXN>_5&VU~?B_Agb^8w^M zX8&LGIT*w@!r*^&)Q{ZD-R-MP-Pv)__x6MSHu8JMgQxu9k8-A~{R(*WZWQz|{qMEk zguu_`)l4|GegL<6q0PRcqpnxM<&J1ge|(fO#FLK74AB1_@DlvKkeR|4liP9v8IT2o zXaIp#13G^dH-aag1pk9`{?)I+{f~e*93FQ zb6RcS$h7^UA>>S{IY5{@A3X6iQf>JCo58*Lk!rI`4w3uV_Smbc{KVhu2O6 zKZhg#LR@Oy%S<%h!oV!(K2~5gd8$7OltulY$bBoZK${&`x2?*L-v7snx;w>mEl@mA z9Q=2tdJDPbx`I)kZu|oJ(E`w)PyP4FtyT#92Mc=pm#l#56VCYihk`y7q*l30nrZl3 z;8E(IB=;9W;Ij-|avK8pxXCm%eu_NX#D(#{go5}Aci>jr;V3K$^a^=Yq;wCt^%n|M zmrZcjSFG_RH}CZozyBGkg*N++H7or!45FgbwKKdU^tZ9b-;)P{ zAo?*3%niqdlY0cuBKMK^rk|7KN$vwmlQ-S1KG~{HSQhA2QTKn-#sif=r*tw;G~QIfk9GCEEmZ;^mnKF!T&+u z$IEro+Xs?wCa=W`EGAF%gP#{!f!+U8-~ZI9NQe!>(0vFHZHStgAE`)?M;d_N!2s3w zv&OvWe47F0kcTfK@MF|ZkVpUI^FN&_DEJc``7gl0Odzeu10^sz0z93XLmq4D=DUrb zYTz$W|Lz0upQsDITit(h{<=^QtpLI69#q^?4E>vjQfDQSfFpnlTRUVVe&?Yq3@v|EW4JK1#VkD zo>o6hgK9@$5X1(-GN)qilP8`=fLE#iz)|Rj`huJJMut&D85mM0)()cak*_!|xe#IV?XQm-~RfZo=!HVnM}f zIbLz+{9l%IGY#ZE;I`9nB$wmIZo+4g%c=J}a&>L#%s-a7kho8s+u!JOx=$#sXU61f zXk&9B5m8+K;#t}~<(w3A5Llb3Z@muv0qiSx71x&P?U-x#1rXn=qy#!Zhz7H0kU@iD zj}<4uKW~$J1WBdUlBWxP$33WV zQ1IKiH?*xqD3RHQmr({c3fxF>ogwdH=)ccgclkxHW+kkUc-#GT#kGEb{&!J-s@p&F zuWFsi05zfrU@jv6Qe3y$7+Hf7D9{}0*I?$FE3Wl3gno?k#JQ#LKhP6n(Oy}<3jKT4R#0~BR?Sc7V(0G6gKD8$c~J0L7(_pLMVe-9#XON!}Jd@l~_Y1TC zZ6YtC`L+BjjRXaig~8Enm~h_TfQcxL-cE2&_xD32>K7L2cJa!Zscpp^<}>k z|0HL$)eOK1&}w-Gj(#QA7YzC@i+tsW2rw7e%6S(04OyU%$=i^3S_b_wyckoP)=0Drv;eh;sB?BBo_egIyb`di5xzXiUSd{PSfL)Y;6pGPV9 znu4Ec@CCX3I}Db;4M)?+8~p+PwFo?gyy`p9H^2Au+@H{YG824}Y5!^GAvi~Y`9krM zzrYKwf-kRM0>u(7DWev<$tnNSHwbsDE z@bTp9$S*JxUy{o{ROMgzk(oHAI=fme|NrlQeM{a<#v<80$s$kPkq#+$kDxYY~& zS|6jJS6HCO$!lx^H@9FWl6QBw%Kw`*_>2PU6BsNZze2u*d?dNQ3<4Ma6#Dy_(lO*` zKLejY{Wau+;^5AXOSk_y3N}*kb1qmsP!<6y?}vf8?-wFp_doD+CIESfBj6p#FOe_Y z240^>w6)9e`JZ3{f{_gTtP<#9IpSyVH|S_1dE^ZEQP%h(`R+a7hpAt;Jp2^+6?`)F zN0ZM!&F6n6Q1BrIna5%9J00by07tubfY0PVXK zdziiX6~=LLBOJ9iO~dQ{0}OB*3+lZL{k7!gJRn5=A_{6-Mvz6ph;s-~I3FUMCik+9 zM>BA({}ABt73dep3Bg?Q3zxywA)E8JjeH?9g!>C>{1vwlQ8+(eQDGShlz2f=@$x2$M)Tx`Ee=NPx(tpF0K#%(f3pAGVK^x`hMgeMn zgvW5a41knc)_C#&x$!^z|NC*`Td%UDQ|q9l<_(7L$QRZGKgZslzY1#hcnxr~nw91q zlKu>QggdV|tQ0M{p@iqnTN*+>NU+|=HkBR&% zG?{{QvH6@w-bwIx$@>ewiF}ISyT~)#+_sJ=f$nsE*5DPEw911h=_lJq5r&CZqn?Se1Q{;ZZhmiLdd?NW2!86EL3I0ws_58nX z`}pJNrKQ;RNoAmUswKD?1x5peJlPu9wENNyK&jThOMF4Yzdh|o^0C_X&4_l1q z{vw>XijYT^fQJNchKJE?D}#>AgGVKQ#=~W?RtP+uj&6Ues?#UJoYBlPASZI;i3kq^ zm0pYIGh8B+P5!2qxGIe-Y8z;wpF-1+#JA+!G<$vc{1HbHqd*@PTe zQ)Gc|x#b32xBoY)6WwUBIjOiF1)h7eoFbNETh^}*o@k2p%Dq_y6&B5SSa0qm@7hPLP}H{!hu(2SS~YrZeWQ0evsI*(p6q?h||wxxd2(^#69O z!3heYH0VoSy(R*rIw5dfZcN6KCwhRdW)pl#9-9x|g_+A$3x4AL=qCrqUoQ%*0T7sr z$j=NP2!5IcD)}%Rg+_vZP2QT^Kg!J~k$XnF`8u0|q!64Uk39ar;?CZu^AbAO!*PySS|`SBEto2S+)`2at!u;CFIIw1zx78N3YnzvTW`9Bx~t z?VHp^0MBbM7{@l7LLPY^{3ANrV)#1n_H6rG>cNliJ@6p?bR|!%2gk?iRr^ON2z&^^ z!!$TU9{T}&A_G*ZkDE^0tCe$FJyscw|BT{#)Wr5ce<}61QU5>>=u_Rwm8SgI>h4v$ zAOz-4=VMx+cusONEN77CC(qALx0AdWxtV$kHh`b1>NiAj9UxK#6W9Nd_TB+eTv9V z?@D@1HTsLg#Qkry7x&wi=Ey`rFH31BF4)u!k4fS}RyF$ASV@;(V7otfilE1|s@l)e zX@YJSA?T`{i8C_=JtIkMQa%2sbb+`Ky-QrUARlP6P|%Zi3c9VMS(2W$L(o5!_aBn< zjL!t!COfvSkp0MkN=IjkUH4Vuf`5P*X@u;^`+Y%=le~Jkq-T6C=+Sa>xk`H2etCa_ zc(K2vKmWC$r!^7%{~?d%^=}v*@jw18#D#P6f#HR+Bl&_(lHUB1phqW*7bHn~$|FHH z$uA3)^xqss`c3r@_`pNZQ+wdOO#Up84>rWo6>Dd#S5xWb%mr?zkk7-azMkx3)1by zo4>KqKM?e;a^~Jn6Ze;mN)Z=qo9Lpv;QvoSXD$-zbfd5B=epis~M&}8-SsteZ zNk1-AtnB3;vYq>LO@$i1UGjq-Qva|E2oV?TMvE8NIN%IPH|-X5Tg20TNspN?=r$$R zRiRin4+EBeo<##d52wuuXI^1SwxU$8;ai{271I3?*;NzdFU=p!Y)-d)kppYjD^ zlHSo#{!sBIaesuQ?-q3Y{!f~?V2j%+l@FNZ1GeLo{*nNj%yL&Rl^s2pCv(KsihgYO zulrKa?S!IXXY&bVNqX7q?0(GuN3x@jkIENFWzt{L1AIhMS&^SOmJKAmaFL*=y&+z_ z)^;ox3%dUXK_4&gpSDEMQ{`#mr-QA3j=bP6kCW}#oL?q8+9NuOsv~-8yF$?8v)zdd$m$ZaW42 zQ$;^n)#&3_33|~sssC@6Q@7$naUn+P`5AKRu6hfjGg;~ZUXuRiG(k_RwlouDT3=ej zs!KNBL;Qwx3}e0c5A{z)PXk+v3#rwPhfkuUOOwi9+-}$Ru%Kteh>mQV?q8DbKT6PT zibndE;{Ig$Vu{?^JxGxkOg*bU5H~-7>wsk~h029L_ylk!b8Sku-f^NeD9(EJ>fky{H7kB{H|C3yCAzBKL=jDLDY$vi>$_vDRj!5Nm z%=3a?BvmV$wVORc(5o}F8!}zT-&4FeQTFo*%ckM+|B}-^CtrM3rrG$f7caIskNs?E zHk@?DlfEpZQ2UP}Ewy zI8z!PzE=d@Ect{D3u@g+I4}aGc(nCZs^>QjOA#0BCW;rt$}jHvv7pOc zs&CSFB)v?oy_dXy?x*7ZBB=xZDd|5*dUb8M`DfyObIM3DqIcy3;}mfr?rTAxF6mb# zy-3nWN%}RJu4C#gK46VRM*4m&`myUJ=$++^-b@y0IYr$BJ>|0OXsJvXNS0IAMA9o{ z?6zH`c)%i6t8wRrx634@nN8SyE$Nw3OSaK{WaxIBwEgOdep2kV$*7c!N#X@*a-^$e z{BD_KIJVu}SHf#$)z)}~gx9JcA@u-fxq02}85{@wKkmGk>PPa+Ch`k#NSqP$ zsd7N?O1kMsL7y*qY?-9TT^95matS)u5qMwPeL-I*dG#Vmj~X8ZpYxvNX%g;c3H z*nGa8bwx*+Qbn`B7}eQXzwiVL=% z%S@AW^ACbIN#mP2$uAmo4Mdk~~P!|8+!0xMYEqNCv zxi*cFF-1NQUQfIrL(271Idd=D=u!{pA_t^Mx><@{n;*fmzUZgSFGak-_P}&` zAyWbowg)sxPm@9@TE3t~1KE)@UTyT*k{(x${*9z(*yw`)+1WWXlv5`ShGy~w&r7;V zeu0htv7|>!vFj;kqERE!Pj#vIvZR+ug~i6`QqIZ?<>SRnm}E!28jFsK#tFKwJOv+1 zy8Z=npubCc_2cK(w{~#52k5|#QtaZYfk(rh@xYR2(04t9?&%B;h>|YmIPn3CI(OqtAQ>ed{ymN1s8T`6ASIwltH! z67z4BQ+Mkb54a7$7vKTA1Tod}cDv4!ZmLEf^o;vw*0^7;fA{ww7Aw8Lrar&zgi}xp zeSM9N#E{;V^i~N~2l~Y`?zf~oI@-8``>hyE6A9J-A|19Z!tI;1z zdP?;N+y{!OuKqwPIUw8pHpAmnIiTwF_OhRtYA^04>4}2=^!yEf#sgEUK44pVyE`n= z5Hn78|C>t#XGnTlq@Z_{{k$pZS)7g?YWuS9<%J^ofK5lgD(U5tZu_#vgT#RB zqQncfN;N7}(ldGpdMo+jL`g4_bUxG5aPbX!L5%3>fEo=IFUZXQkaqzN&Hrm7=~>n2 zk&<3ijXn@=5?8(fCJwi?hD@-vjxMpaQs1_#HT~K4#MbtmcNQnM(V9edMin9&C*+c>8-k`0VAGu(_8*}tBu~8t+$rwt(AIfjowN? zDHzdT1!}N})+iJ+5v>V&D_(C+*ITpo)-HxAoS2z4e#gst-vj-r=mbn(M6&dMik8_0U`W^wtY{D@JdP(OdC)>r=h;rQZ5Z zZ&~$Lk={C|w@UTaCkUnyV?Lm_zSLXa>aAmXD_d_B>a8<+>$2YZQE%PRTle+WW4+a& zfo%jndaI+}>Z!Me>#ZqzYnk5Kq_;lSTR-Tn%X;gf-g0eddv6!LRTt%G#B6w>0F7w< zvDDUDjoL7RwlCW(TOWKFEL)3E7e!pP^bV1&b??|(8}wEaL?em&>RD_pf4x->9YnrY zZ;e8nlAw9z*;+&NRygn-akYou>Zi8`>8(k6Yk}U{uea)Qa zT3mY9{g+Ow&|9uhWW=+iw=(qBr+VvKv_vnz>9jxfR$atjiC#>4%MUG~Nwm^wfqJW} z-WsL1rt7WQdTS#}Oo;c|7u)(X=`BCK)kkk7q9w+%L~oJa`buw|)LVD-R(%wr5YKw* zt>JoWjNY1{x2EW=S$b=M-de7=Ue#MUDE%PbaZzu5h3XE1mZ!Ha=&co{wyS;s;>3MD z^wu!FHAQbN&|4jmIV+y%qql}YCls_;z4fx*TBNsD>8;mg%iT9{_M8Ptfm3HM44k}h z`pb!(rzhG4CN7yhf5|Mm@XDQL;q1z^`1#WWb-_HlzcswO#FY^`~~wwOZ?w1VcvrI3l>h95}05Y8#`)9 z-`K&=j~o>nOMBnW_oV%A=YLNX`T1^S$|`6|F+Fk|spwtRg`%HWJgJLGtC#*}o&&l3 zWob_3zg=HPJ{1-hLkQjL@pAx`TZ$Lb&lQ&M452jF{&)Z-@3t_bO~T?(YX8d@6D_Vqb# zWHwt`QLoO~uJpv9deF%k*)Pyy6Gl<=gToSI;UdZWPNPKBhp(bPhV zH{H0N-IOv1aE5sO~g(zUnX5CUuB)Jne3+xsZ9S z>h5S4JAP<*cq~N+XE&$r3$lAqi*=aBv^)5woI4gbdf~3cgLVdL?bfX~T9oxh^->$6 z183c+=)j2(8fS0mLk=C()np1+>nnHLtK;fWzo?Th(!6=9tHDeGt54tqyIe8R#9(!# z@=c(+%AV%W!(_RnqLVINuDGx(Nqn%ubhY$cB>g)WBN&D4X$%gj)&Zr2;2L}05UQkw zsJ|NMumhX8aAif9`jSC(-RaWlrc~sv)}iJd)K=*|u#HW(vptmOB2;f9pF_;c{Z?Zg{4mw+f5CA%`Xt+p(&l8lP+AXlF`1LIJJFOL7}1D8 z&DDX;We`SuTXj=#y^(=Ri;CT-{JoQ%X=6|I9Xi^r5Pv>@*?~4LIq6DW?w)j{H)ddd zt$$wdqq2YHcy7(o8d1h#?E2&l76&D{m)g(3H*vktNZx%YZ90j0!&PvEj%sIooI4dw z2M37it=?eA$z%)*rs934yeX`YT0w?Y#hu8!3a4V}CTtdVAgEto)ssefqP0oW+>Bx2 z6o2r{_Y@Gvj`wbB8_MXbb|z2Z+9Mc{D1^;2J@J^j?9wD(kDFZyEu4pa0a z@E`VslF?u7W1yDHw6>JlFs~QIeU>|fMr~#HY|r&4(*;X?ik_a+nKGB>45D4>_-MA{ z>9+xDTWpi~cdU_A_S=QVVyIi$tNC8{9;muwv3v)rt&HJe6!pjwM}hc*HvMgBLn8)a zWt6|MO|Pn&8|D3tZta_2@T3(3)wX;xJR;3Cj$vdFna)|-(y-~5+^IB7Z9vH|9!rsO-V#mQ z?6JDp?4QZ+Ft)rQ&x7_3Q*-!)+XsOO1*GJ=VN!SG75G!p+_RD3xY-TJIY14?Xa8byGoeJ}GQRI+F7UHJsl{9oW@3 zOvk}+ZQFY72=yEHnyZ0tTh$m-YjuF|I#wU8la6Rbk5uQ;&9KX0U^h!#>5H4UooPgS zs~4rV0mF};ThKr`J5pV3;4^JRC%q4zkEFLo<1q5!J#xeV4qht=r?aE6U0T*t+tI2z zScXvAF|?>P#q=y1KuIs+Cgb_s2s(MzGN`hIe3<`K?D|lTGnnDzOI9a}J(?d*ajVYM zqc&r3@*D=|;NV`gd_-9T3S22BBIh|8cgNDg7!*oD3(rK*zH_%iDTCe0N0ppj45<wp=dx3s~)#mzn_ zA|m}8bQZTXXCQT41y+*1G-oRH9E2h9liatl+KGM`0y$$&J>HPaV=Z13osUhC_7Ddp zd7?U;uKWS^X}da+Od~BLsMiFnxTy|U^t^GFPE=Z)-HYZ-&1*{4H9 z9*d_ri~7|G`|HVVOmAjx8TR{>i;fg^99-ndDhT(~SamPG)&Eu}%G!UZ?ha8M$?X-(Ofl9dNUmMSU!xPb7hSlDNl%>B5r!zn zy+5F>U7#PlVgezIjtxyb-wOk2!r zT3vM}*~b;PuB5+~u3-#nR_8Q&dkUjSc~QiT?ASe`idgM?7X&=TA1rffhTf1k<*}SF7)#< zO9Y=QW3X9hvKf=X;<=zLcEvs%aU7B%^P1&3GOsutOocyNxN1g!vWxrQx9n%Sk9{zh z>%OF%om7y3Eyhk1Na5t1SjP3)-V~jv#!|)V66~DHTCrTG7u?idRPim&an>)#o6?Cy zbtT0oVYM@T)YjyG%>s2fx2z?FIjNnMiAm~Ud-+u%AvAoVr8}8M6orw`bae>r%mYuy z)|(>CkTY&L*Vi^%j*5>AiL6CqZea+f9ZXA#^MKOTdr=Nli0P^#w$MTk46S%K)Y_P_ z*&E4WCeAva9n}LpH=n7V5ce58!S*|NLT>#!Q~iaKJhAi4C08)v>tU6cwm<<-9t<_2 zGXaC~M5K}L#gkk`jr7=Yh zvmBBW8y-aW9u*YR-dU32QhP7(35dQY*}cgPzhryR zxmOrBpQly`Wx>fC+rjnzx#nzrU1_5aY>AKwD*w}yio7jv+6PAjGfjRgxq9Q>kSniR z0@C-uI!YM@b?2o8P!8g})nVki5Hp$S4WZL^q3TSrJHT#qQ-$p|`oSAh|N0bc%$NmG z0Pn+nv~XXn z(!S4r#zvFewGQWx%I>9Vq=Dx8svW3wnRnGDa7Z470?jF zXw^y#to};X%Rp27@a6s~xb_y?lLJ$*AwKd`+pzUzs*P#-o_;PxO(EZAczSdy<}$DudYqAp7eTdd4(iHO432BiG0jzz@+c~|sXcx7 zDux{rpt=~tBIw>%R{wNAHI!2BUvi|q_bxk9m)F#0RBHOkjnmVdO5JH=U+`z=zUccsI)%zx zs-H1~E{Ddp!N^|wHqWFyT&s>W*3czGLnCNzJ8K6@UUA8n_8GF9D0|kca~)}4!y6lD zr-q^2ou1u{p5LUls$s(i(Wbk3o#>rSYPs9Koui`65uw2m@d=ZY zCPz+5+`0*a1kT_xZN>0&cQ~BiMbts!Xk=65@Yx;5sSg>X< zx@-Qq8Tq7Ru-rxsp}+!5BrPd`bUFCr4RRyAL8ma&4I=laz@aP@30ABh|Q6U_-EK8HI0T1$oHX`ce9(PJ3?eDcOb?N zc;L3@?^;^Y_I!&QKUuL007_kg{g)nBlVH)4O1R44Zju~yZoo65k2|{<`UC#DfyAbQ!(tx?qwjqJ!(s4&Uw&}DzFJya;=qKd(`jj z`H~tV&6N7sG6*Ml)t*ybDQ*|mrT=H@E1a3-J%-)~L(PerjR2eF_BK-xm|izv5IEz3 zwYk0M(P#MTeOqo1rdwWM-yJIO5G*%0>REx+sbrzD7S3 z<+;LgYh!@mz`>^S8y1*kU#PE(P3d4z+k*#zH%luvxtR(Tcs5`twrP##a5D9{*@EKQ z6$DfHFeos)*yf#K09%3a*OJ}}f&R)(xQ0#C@wCDK_PoR%M)5Z}O^^yOu1)D8) z(E%dcQXkXwTl-sHz|+c1%7K0A9%+tX6<|rx3-wg5y1+cbqNw+r^UY}aex?$0^CdKr z_SVO-<8t^&14y=48>6>6jqv*48)5u@jnzfe%>>mfn3&oK^(vUFYV@irCgn5s&nZ`Y z-s(@!cA;NVE<4eq{dkV=8?HGyAAkYHP8o%}sqJaL8*ZL^K%FRPx7~2Fo4e}fi3sHy zM?N%&hQD-j5{>l3NLKM zzwlK%)!?|;WlX7V;1Bi03}E%@LYjUE8>YEGb{w!KCKsM#vf>@q>KA~o-oO~kvNf1} zuo&#GHMn}1(e6WjKm=c9Qls8l{Ij!w!vLJX2)T#w<$-JQy{T*Q)OSD#v3c;% z>TdzlLZEn3=sNtFybf2d9KvFLz7Dh>4`Ujq9aitt*Xz~G94!>KHn=xl)}+P)gqsDJ z6&y=fx1VTAUthWsu9SSKHZ{7uEB380UjZoYU2NRHG-`CjzZ(lhQfB?lkB_K`Y> zvRb3%P?DWM{=?8AKOXswFe{N1Us~i&%@3dPrky#s#Bg~SgRmxEy9!%12cHf2(Zz@* z-I1$4M-jQIDxlyBXUug3rz(B&)aCWXw*0|OT~=d_h3>3CcODBA2%4*XaJZQ(mTVU$ zQbwTGfwFh!I8ozon6>^43mp4{OO3Le+_4lo0YU^46#j+${3SGTBFtsRGjQC3US$4< zKBaZ3?CYG-I=eV`|;NtqJ55-#%H=H;FuUK5CQ1GTYL9d>+jHB?Amdr}<&%Ul!$&P`jnHh$fNQ2MALfxJK zcZ`l`0qJW(MQPdXX`SzN7dp5idqO20^21?}-nLOVkw>c9h322J9HA|)rEqPWV^-m- z*Ben$Z_FCsbR3_87_rX@pp4(n_|uX7IrYgu<9vOZeJUrM?k7PsG6oAV#E>#Dq<9+}dpp3cu3Z!oKTv*y61GqaeSoJw?Q4H&Z^CsdcNXeA8b$ZJ?tA z3Se%=SnH8#F!mD$0jzYg)q%bkteN?aW+SPIGi*-GZNcpJsg*oRHI;&9w0Ac^M%?E` zlg8yVrnm5Zt{^iNY#!4-Zsfd8Pv+v)T%8JK>Qq~r7Z1DkDW-604Nyi7A~2r=O<~Gb z!qSV+lm9(SFlQxjn0V5zLvR`d{YSvSg`JN7h7)k(oT*071Ou1}08ND(3fv#X_t}QE z@a{SOVrhX#xlaa{zO7Z^Gg zwE@r0eBW|_eWejX4FCep=GVCm$@F{n2#U=BfOT<+)`g2rV`%XI0w>Jti0KxvgX9s8 z)U)x0`LsS-YXJ_4a|7nlkQVK*e#x}X_B47Tblhj+2i$RTceCXHcao5$;q7YfwicMH zO^3O_yqXBqYt5rlo^4Kf3#I&J)TE#fNf(VN73`#Cx|` zz7nquqoUnFU8Bt5xi5py)xoS8D*Ra2J$URQ$ zSF)NG8hI$6DE_@B`VX5=vtVDZ^kXhcIWu%|PeW&Ein zO-4>+`*-nM;>=0VrL$zul?CjL13@RPG9T0aFGyTTjZn30W(66mDqC#FEe*O0$( z=DvOr-PO&Fq>Y1Mmwfmn-;v7Zt1W0ab3cVubN2Gn77o~_=2~+a$)s&A zb4$T+F)4#yQQtJs-M_(I-`JZIW+2B6kULy|-SpVf^{J1^J-mi~Bn+3xsy-$U>Rf@& zD_JVipQJGx!izRHf;zI&P@7thgTxf}b4KhX4!#5dI(4~!t~YIb<)#Zcer0vB4+@G< zc5K%g0oZAh-@Gy^)0b*BG(73#W8mF<=Qiq9XrkyMAh1#C@L~a|t5(cclVcs3(M*@OcUC|K)|E*RS#phS^0dwc2lT?MtnQ>IKdhzrPcj! zMe5LepPKLtuu8bTn95is{{Y0*5leopIX-45pbBm_(ec;tc7~^6a%}d}6oI!)W3drH z)LiXD%}~|@we}RCS>0S}97y3`-T`}+t+acmnige^M}ot+jRPM@e2;8z>eV90NpU}| z8nFqP)yY+WK8JabME9BJ+fv-is*f`Ith&iSMnn_PK@S)f46I|}LL3@MO9VjccV126 zr$9MA+aMdE0q)jN$_l^etgO4h+}k`hqwm_X_bIMU_H&e4 zky}@J?UHIR3RiOQ_FU->OkSDeN={>MjDv5)>Y#*_sJH6so_~LWVdl!BmYj58-is;* zS?;8N@e?FVWqKsVtvOy#dG)#)BE_be(gq+Vz<-kFNgI0?yHmvtYzSB3G!U(*=bpB*B+P=A{etLhXNc$h+$Z!CYfmrUrHP$jb zgeo3la)mezqrr~=w)KQ;5Mcy95G z^IyttNZZN~1=aaaHJ#2ZhvTLeA3+WI7a2;!H=XsMbN z=%v&FC$O)}{yBU5P3mEUE%V|U^wXm*6uQ6as-aNy+$c5*3v$Ori2_~td~u+8cLuV7An&0EX~^v2Tq+C?#_FwEwof&dmW z;X{L?tPQAi#JQ%r>m@~e@89(?El1Mwa+SG_w7NJo4Z+#N=YDM2tld0s? zO%wciGIq>92x^{-6TG2uU6|3fBnN>+lTS9LY$xrAfD4xacr!wI+W-1lHZ5%^%~c!5 zoS>cx3tx1k(M|B)SDdf|T;9nmHISzdoIz|(n2Z7Di;s>hbEfrs!C1ca0gvJ`9hX@A z#yN&~Kp)*)JYGzTn+YHyqSl)8b&U?Sy3;IQttmI5W}5cJPtH6@jmEojsD}B81@73=jblG^Tf@u2PJI2~kRZm( z!8Z(k*g40VYTd+J<2|6qT=Y;&YQi@EkAl4uZHTkPD-}((B73^|4|NLmeR0+$AAT+r zb}o!uG#W#oN{z&bx7WMakl5rZZCh%c4dP-bK!kQM8D>vFpi0*B;N+>Tw6Ex=N5IJU zF29B_qXE}DQf5o&M<1_;5j73&EGRKGU0aTHIK=8p$?dSi<63KD=-fT2@p&V`UnCVnx4(k<<1lccj8)5-Ws(7_S=rd1@1H~%UYKL z8((TdzqH4WV4ToC1gwyQn(wy)&pBCg5iz?Rv}r>6{?H0Ow!*bI5726ce|7bVq|Ez zd2)DA7;Rdvq6h-4P=j-EcXH~4lfs#4XjrHqy~IciOvDGwjV|sRJ|t=+Z06g?0@;bGLHASZ-o zjg@;4?22ha_+L<5ZWtXLtBvJcoyNe`1_sRne4WD+q9Vc)!|*?IxH${b=p#@M5%Y*2xSF#pxD zz=52X6^xIs9+P z_kPMqz%G0ito_@@Tf;@(z%yZS=e8`c?-{`q2xf#0B!}otM|WHaqfBQonsG_+JlF>N zKLO+{Tp8UVUb!n)wJ7OwXC5a_h?5SXozY;_EU*Z7Fth2uf#~#8eQY`IZwZ1JD}Ej) zD6=O5ZZ7muXWBplV|eg?ht;8YR zJKvsnYdS^W12)0)Ao?|ig0{0q9`wapBJ=pB-qIMVX0Hd}L$+wP+G6sg+zg8R4`@5L z5EeP%jUyIA+pCJT(*Y;7Ju`;>pTTxG_kuXaEtZJ~K&HDM7~UxBs9v}YEJ@GMlF zYuAYQ^kTOoU!*3qPCZ@F84E9Bah@&=H20;l z9U*iqIvaR=JAPw&lDMxvonHp^lj}t+P!u;<#Q>o|4c~Y@Q05H$Rj`cST@Go+PByJ# zApt8VLmMspi$(nE0DswXZ7WyS5lDb|_L}%TkKe2W;PbhFP0JB{{^2KGc@RgJk}K{0 zk0FN$K=7hwi?J!51>+-@Gg1KkKt0;SXNaAedFFID#T1`J#=r{*nEq%L7(Ta@=OUB= zs!ug!A3>WgRMrYHKP()C{$2&v!mJbfV1#gPvm&k>4vQ@?e$GSruNIAXaybjc*Q1-O zgde&XLx3k}Ic;gq9BU(rn~YR|W3OVuxfUH90^Ox5*v>F{u~H%7)vs|Np0N&$DuUiB zzXqjbk~WTh9dR;=-d+p7!sk5%{@hw%`ctN#81Nj=Z=$a5Sn$%fAzApGy_IpC=(TmS z3tBWCo1obtKoE$Mszcwb(?l34llh3ld7BV+I+aH3fRmz1=%ambXw;X7P8tpL`g(|; zUcD@f`In}9s&y2@p_2v!ZF`;ZKR&ex!{7V5<}I=e?1RICzuc1@&7+lCPz-wlagpyC zpnxeW_vZAejPWn_#6kJ(D41FS*j?mtm*< z-SlD*#Vym|AWqZD*_1#ZR*r7cdIR;~GaMeQRJ_gpH@L9t2<)|t^(75y?_s##roO8!O!omGs{_`` zrFXRpGE?hci`14%>ww&BgR*WL`+hO)QCy*IOK-F*tWTvM;;`_qn&^vz0USuniKd?0 z^^b`H{O^U}@_D{6YY=SeOwI3~^Q6+RkZR=5t~IRb<>=>b zuIY%W4IXbvEA8Pv1((f1o<}+mAxQMR$|xu+AepDk=lQ*wKN7J z2OvdtQ-*x5Z2_FiOz%m|Bwg`VzmwUFm#IkP;h2F%gbn%`s$iBMLB-`-=S+bp}G|i|~7~KLW0Ght(kTz4ih%06xP|N}z+!Ud}>EE7c zN59f37+egFMSzSajADitAomJd&M+|lnB~w`dsz^_V>yh~ge-6|h6gFn$6rM-!iBHc z0y8b-%4^usLuX$GiqFiTreAA^#mK`$m0zNA+gFafg<@6owe}jl>d&OufA#G!D4zLU zIKW`@2Dm>Bp+Zc}s{XgQDD)>JFm*B|BqhctgoPnPCL}R9VG7RCH}F_KjjxIn@l{Qk ze;&w#J6T$(UF}1If+%*{{v1&WMJ)UNLkN5HPruNSzCT*x zNamio_2}(y(F=1VV7cbHl|<3yZ^5>C08=R7Y><2@Zsw)#G~heXxyPaS(B;{5x-)!% zp_oR)5eTaC@3e_DED(1LJ)*_aVrH%GJ)#|=YYajFqTo)`;In5C4TD4gEVQTPiGT+g zx#NP+g6vLat=B>1=?3UM^rE+Y-Q zgT%rr$hg6*G%M1~_FRdCY@fT|3WxJw$Yx0X6%OLHr?fAHjKQ_47zkAyfcd-Agz01m zWld)S@Q&dvFLk1Q=W(L`zME@O)}7&;6pS8gAJg(uXL0SVv$)}}vl`Dn0WYca7{4_3 z9KN3MajfRk9=|Nlby2=Nr#%w9nTjXf*+$8JC+AYxG!!0rvr}_Q8LT49R{+$UduAr&=SS{ zy7r?{aUQ1*a1*@-hoLM5AsU9-`W z2OPC;X*)8#eHyCKEzppbFO8r%d#;+OYb-3=Qi4+`&64NDZjL3(EiFx;RWk;GqwvgA zZUNVpLza14dk#6cH{PU_L4bC<#9`xCN$T|xTs5Wwkq#_OoT5KH6-h&9!Qza)`ja;~ zJw$Nzh@Y>Hp^YtzTxxE(sBmr(*P6hVTs19^XR%?M^L(=glwnlEjZyG&m*Kl>OKyW# zfSJX$q^NbIq9Lj)4+T1U2_fdq?jQ=ETenw~ zqb)L0m@5Mk%%O-M!h)dlb`*UdzLssjvJKBs26MQw|5t6Wa1OB;43uHu7VW#In^WfR zSp1>o0G#8FTR!Bj6@*y8pksJc)od_fS^m=i#bwfB%{_hi@g`L6db$yrt+}IVTYVHH z5L|&}mBxP{h6AToPr4DU(&|Vd($#c(_enL;~u{-(a!+45I!eSv- zuUdv#Ao$KI)14O8$|}&W_V~ok1F(f{ilU`8v_m&s(#IqBazGaVC8j?4{^>@fHy?di*qZh~ zf-|gY+7{m=%(&^@>JsMMDZ2?hc?7$F@fQlK2gMkE{;S8$G}ylg*-{e_S{9bRsyK=J z;uv53L3ejy5MIG!jVGDA(Aj!w1O*=du`~HD zN2&utX`(q^#)7KhFH+um_iV0V>k#+Xyqtx8Dz-{X`lm-zyFCvomuSHz~TiUR{TzO=P9J_)*5VCiLket8VGwT2o9r~)i-uB2&q#| zKV~-^(-54{%P#aoXCSYCu2d026$NI*Ah+6*MD94NJz%}yI&d-OxMU-Q&hSN>>za`o zm@ti8-9`FtCkpOzYY>?x!D%%n3{h;cKVNM_S(72aCz-5mgtY~irxzUTj^r$QVejaxXESdNO}J><{ww^YgG>jHQrq((Ae zUr?bT-)7dr286d@6FAbGNl3FVGg;e<*yQpx$aO+4vzMNB4e7?*I?p2~#28{$j!r)H zkv(O&TY17JunrNbg)+;<4%YKQ1@u*@ofT&NnrGBTDl0Y|Z=1$GcIO}6w8ce>pQM>=>d zbRSz@#|ZkU8Qj7taC}k`OZXVm278FZc`!mcu;dPuA(F`*?a1da3ngoY$*z*-fyk4N zQ0)7hK(Uvq1H1O3ASiTOvw@j=QEe``Mj zIlQiJ;J!&?INYJIDAM78q!`!|u(pQdZ%8}*uPZY&dNJ1%aO})WV2ED@So_hsCAXc( z$xo|?3^ttY&i>j??kA@Qx34(UY?nK3<5QjUlZ4Ngc1j*pC|-l>>%2i4k?z6=3BvpLrL zE7#gt)9O%p8|@A??{hqcES<6KMz)2^)>iPMx^YA>jslb$ovlIk+@s3s0*NqpJ*|*c zyWmd!z9%5Jc#5H}g45B9U@UQ_ z{DPEy_Jk8vOvz59b-~tkA{L8Biu$q?IpnIji~1mU9k5GTq^J?{^lwLuAfg_w*`jsY zF)=n(5B%)QH7=K*z;uc_sPRH1z*W#5Y}h5`#8?hZkktuc0KmK&hgf%uTM)V8LETM= z!bDE~cw`762;w~FD}XhFXp;3tEGw_kfbL|eUbaYCXc+au7H@@GgSnXE_#pL}gtSR+ z%x3^DqgPVaImRuY@uW zeUZmAeay+2-rnIi!gaF?iR*~6V5!BuP9g9wq^q@ZH8NXHCi1VnG4KCkId$NSEbb%u zRPGSxaI<+b5~4!Grz9pNm=kFDDV8pX1*;}x`G6pRhYv>PH47!Pg&eh~%&ykaf(;{I zy*+2DnBAw6n1N+R7!q9k$1J(ko|3=8^1gT!sU$YsuswaV90HJIe=*_59Vq6+31`Y! zT@*sWh#+MmcK8?Yn(%ULncX0zvFwnL$eCu6w_269*BYvQ$-gtE|NCw@a$Geal7-;6x|KjRO^-q5e`j0--?Vqt!~P+ z?$#3qfsZjqX)kLN8hRGFzKK1p10@-GZN03ml)|1?M0=lRKz9h-oQy_~qp^GVC-d-~ zg{`ssC-%0^qlCk!hLOuZur`tE_5YR8f_Xqa<)JveUuO}EE_b?CVzUQAtf=QEV~a-9 zi)|oZZNlgg(_mEy)wJ6^<}9Te{n?XR0q96TPiv0V+#rVg-n0HVvPq*d9%0YW20WZW2-FR19|N9Fx;U!pe8TYsn&*Xy(z_!_JCmOdD= zyyV|SSxyJOy!9e zu&K9P@=^{CwjSbEtt%b#L7kMdtx&Y)#1H7pR!wjp-QDqX7fS7bS}i*p-gr;B?r6y{ zQuH)fo<;vet&pO+P%6LhK(#DWV@n6*1B}F0H=oQ|PZyiz4Wqhk;Iy=*0WPUg7KRWj zm{uRbGI4j2OVYa`63N&$WtIG3*&yq0-1U*lk)hU6j!NAmOLGGQSnf5w)}FFH{~5Vz zlP=b!TMv z_Vqwy6we>eT3XzjVyxM9$g5GYiB@;RF8NR1aF0E^Cs_>iV;!VvLecC^VOf?@G;#)f zOxy?7V5(L7{}G~12+{U?1_I$qmZ{cs@ohYRaH9Lg8A5y(5DsTBeK*-MiTo2S`^ncS z59I<_3C85*NcRVA0(}&38Ktyv&#PyoTu>g`rRsu^lebla`i`sqdXj;E=McjftGS z^7@JBnup$&7ir5zlqf;IUoQmiqMlSnF_I$F8bF%1ceMm42V5;)MrFEh-cAFp_eS4$ z<56V~oyi(1Pm2ZxPhjl1a$>0qS7Hfjjwjv!8;;Ys9i<}}uo+SV_XYAY0hUON0lC1> zPq$8_zdM~ACM>U!Rx2Wjz!dtSM%T^hV4ysf{Md>zfZ8P`fi0&*Mn*)2M+Hquh>DsV z64bv&d^t4Sw^8xH5c;1>Y<>AR4v`G6;vw5<=X0MY_tnVwWYCTgb}cd|~WN)=7Cxz8iKpDIM`hM5(MU|>eU3rW; zA6dJOyRtwPZ}LA@=1Lhy02Dn+v5a9R46k?kbS-_`7uz_|;sPJ5@@lHYUFwH^**8 z9R=*Zq8ZkAD0L9lcTQKv@@zHds%7Z1l_FH-YelK{2#Q6iq?W88A@X`BqHtm9Olu21 zEyk$IiM4PqBFh#GymDnk0irT66EQv^$yZGzQkI7|6HCU?Q&o%!jfyD z5e;DJZ9IVQ@u}XFT#jVwjVCQ*sQLRv6ItX>Guq}_ilNoWYGy@1H+_>|Edl#EChAyx zXO#+HZ+p}h6#5kVd`8A?-)9xp8r{T(%rSjVrahFDM~qdQ?|!K|EoW-NWo2FDhDt<6N~!EeqS=K{LE30FWF9 zwSlqSSarQn`u>J|6*R^wwH52qg5NO%d{38so;!j%N1{+jcrVK;&g6}V&?qZq0dW%C zg%VkTJ+ZMAYhJSCgd_d?y6q#7Xz_oGnQ<{PTM}-|C#b92KhD)$_7qKvSw!MHg{$U#Y-e_5qg@J>QCLQ!mm6{UbdGK0@4p&rF> zV2xMjTHhCyyLfOJEG1!$^1`7XGT^bcda=K<3#&tb+CD8&gFvuWR9JBt;a?5&n$Wrd z03EpnW~<}!k}K?IWMtG*6Ndw0-@76`1b}n@+6r(1`a`j<#mG~sP(v^c5ca1QK+oZC zz+qx~GpcAM!XB5omv`Kdn~5=^(9KB8(5e*|!^NDTzy>N*Hd9BUlqam%PnxMjTS^L8 z$PoYnca+9NNR}%-Ek26^btp#X0aL;gg>cs|Y-$an^kF}`kV6aArG9WkC{HMfq?flA`_itKY7}kh zU1CaarM^phz46xnpNXCw9AL$Sn`0@i!$n_uch9Zv#AV+Glve{RqX(l@$?D`aVc{nS zuedk<5@hwX)6K}tvJ2i@h<(Sc!saZP1X&l%oqm{EqKLFTaHv&xwk0kruQww-yh2I7dWs;7PE$ScTK6cw;+Ls0w|S%(^gVaVSL=YLzu zx(E#7raj~zPiD6jI~s!H^o-yD4|=HOEL474Y;7m}^{j|U&5(dT7)3x+?HjkaFx}b)Ydl?G}=F)&e~#St=)u0qQInwYE$LUY%$v zE0*!wGE8WzW!6Hmery5_LCU>lRz!ud6$O{UA7RvPg|(2m>Wv{G%Gov6B1c7AW4-T4 z3y&bH5Yi>O^_{j}jTqR^8%Ps?jTSGHjM!EJE!iaSVyKiKwUxYBy7H5l;)*a=2N!}BT-(NQPIQ=dEV zb=lONDt1AqlcS%yJ(SRcmKankc}96{#UaCj$~wIsz;5P>)rCVSJbQmNa@1{o%L4OL zrl6cJzvc0M%ZsqwQOg@n$xqID(an?ByD=jN^$l2!IBrUAG{6&G5&g3}y|fs%8)&Vl zOY7@i^!-lM+eG?>D~;<5%;>+yIm12;1ed^@QL*bH5SxjOuQVhj9ga;t>YA~}-N-o* zW{&NNrqqJ09hr?DPj_cs=NE({g5ZeorEUbNU@Hs+gdj1O*Ijv9p9K!<8Wm?3(Gaq3 zrpyz$K4fN!1mLKZq&9#E#&Pqd#_w3;#d&xdT8c{Al?vyw%oLRNeq5=}(&&3A7Q*V> zDxbe=ZHRi?lTc`XV>f(w#)53H;ZByil=i;WRq=V>`kG7_26#BplBay~fz=rgoGN^d zRUiMq=O7a|aQ{`OP;LWmKHtBJEX4m*Glyr<{NEC2ikAcBeL5$$a9eme>#;3(z_Jl& z7R<>o@((*ThsJzpO`vaIheeF#5YhLm?f(%(tFcYUo!2mK1cgBR9UH(gd|IbJR=PU6&Jf>8&@fIgG}VAMP_&x zU<-d-g#!KP7JxnT&rZC`Vhz>@Lz<^OC+xINs+{)BQxz`SLr3JfsyqHjt@^v2#O4fN8;Y(_^3o;nk%K&K{rTbMtL}7GuIeGr5bv;%@MbqV&yG<>+v(J z1l!MmAnON3?^zNH5H%R0U!C_%-))T%Ql~{dVAM?XFi_#?uZ3`HU=q6qJ=d8kX26`T z?RP_}D6}jew?&m7@@T_UTd(RC;$N)T-_c*ScZ9->pu)NA$3ASv;c}J-bM^5ly%-N_ zggrzBKMo!TA)c`6HKd$QroVo~Jjq0us%9QVvl4*Qc`U$jKyuOf_(6f8v+~T;Y7Y}` zEa($q04SZzGCFGhVhB=O0Q0k7`ml|!HaMZB5#9-e%RH?hEq?QZ7a-i4aiIl|CPHB$ z2bLn+fTE2j6KK`PP}#Ue6%ny@#|2SdH)FrGd-^BX;7ox>C3F<^Wrdcw<7C!PWi2SM zAI{)Gb_ZXimsw5>l0;O;CT$|*8D5=c?dl!!zG zi9)!uB8V&GM+I4kADOrqQfKd1)|O&WX`fmzia{N8!k_|1!Kx`A zkHF}-RXKB&hM!vz&CbVsiCvyMk=2@bA1rv|+Kb~U?FLl-qYVq|IY)(t1x17eg+!s= za$;hzI0(pvNuop(jOHC%z>awpd6bPvrh|K}9y~aerE_GwS^p*8f`k$;I`(gD z)2#bQH7NfSF@cz$MHIIm1L2`8h%SHB8whURX3+Wy~t|YdWw>*3nO^3(+KRgfiERfrzd(WS*~)n-6BMdT>Nr zYRO_D2BDZV9bX0=k{6ifp%Dn}Z}0XWBlw}}GQ)>?Cu^1h2xfJ1LRozqpRcU5g|h7X zkp^WCrMr2Vg7U35{AlA(W%X#->-g=bvahg++$O40{-y(~c7vbz`N}$#UxlX3jTTn) z2DZtu4{yJW2z5NlSSQ7_LhcGLb(8CdV2x{ETVE4>GAoMd!u&Tnc=X{)`@&9i;Tt^3 z_#;!vx$)`ztgd?CiXz!ahy7T#C?BKWjr8cf<;xBpj-#zm|=pSuGF?W-33?p7|Sds0)i8 z`6r7R>DLCWA6Z0+UV55EwD)9jB;7FOS6N`V_hBr5elwU({7=*htrSGk06`?o9Ik4w zt~_F$Oo$-)ggSn2T}_KvtoaW|vsH;p+8u6 z8$5#}Yk>D*!N654)|G}Dq3vOz!OA4fiXV%qgA5=0u&^LnIqc?gi;9QnN&ula&%pzwptRA-FnQJ{SlZ8eVSYoJkzO}95ecbw+fd{VATg;=; zA|H`E85yYCv$6m_ubu_g>#eI7F2c_WRVRg^hFUgY=FJ)+VOZ7%Pa0>aK_T``H2d8t zn>2WWCFitY%Cz^dxdQX{>=u2UOnj3sfeo)TBmaF$Yqm((q^Gp zcb`-Eq%VgsReHR2BTdahcKXrpkti`>g0-FSu5LYy;PvEFaCY;0d$tqqd}>Ay!5L+VWw z?V0r6by#M-^Xkyl^N3H1H;xjrTTeUq0^`4DkcRe+oxq9~y$3~`Ati96GW zH!rx;;#@!r&kAWrxHeEE_$L(nRL^pbC%DoWxI>hGUA7{TfI~M=&9W+{stcVWYghax z9Aas*N&)zPHwm)M_R~Op$b1$*z;d=7Jg;T5)YHN%1Jr(x2t%~}?hhii9>UF_yZWE? z!$GLx$};$Z%#liJi8aPv)ZfLAOyD=d8sxe|;PM}vi>2gM7)3^lYX2gnsI7;=1Kv@^rNOVlr{InQ&D)5Waz}wY zmKV{B3b){g=kRMnB{U%p;pAtpS^IK>fIeaxJEC&k=|Lkkfz@MYhDrKQ*om>RSL%}a z69f?*EzE6AyMAOMiWdzEqG6#hak!%}@CIOwqoy04)a<%7f)CyZU6_aNKfQrNEk|uP z5Ms5wXvD2Ek%Y%*i}-aQ-&mO0_(_P`eu%}U%XSp7Jx|v*C89{j|Eh1}*L3oqnf}Zb z(N%}9k7oz5G58+%4fmrOSz7e5zmP<09*DKWZ}#v#-Ih#^itEv5F%b1aS4H_77Msq$ zc-T$rCJuVBtm@YE%T4P!ahDB3ALt4-ht)%8Dhm`$08+fdlgTCb9a{dgb-2(ofuwsW z1wUIuWm4r$R}|)6%W{%8F(<=bRvsPj`2R=ScgIy#|NlR@2#AVoa3bOWH+!fEYVL)a znxzH`m}agr_sTR^&g7M8iI&-?;YvNGsp!3zbM6Hc+!JxHoTZjo{+_S*x%YA}_u{9| z=kxvjQ*y_-XS~O2JO`A@{jguB`$Mch*B_)ZQPf_71)d*2L(K>wAL_IwaGX8_UT<8J zqn%JHr@0_s+JaF3Q#CU&jo?%g+DMm3w?4RnyyrpgBhGfb zDdJ)74srnk4|O2?yD51+%AK#?YqL`Zn!C@?tk#M*I8+phIvZ{t2CJe+K`6}_1mrop z9AL%^PmJUzxq;H*UvuZHSJ)&E(LgIxD{KVDne}*MOgas_5S1Zn5A}CG> zZZTh`6utTNbCg%>=x)uV9)IHd==KLtzogUAwDn790B+&eL}?l{SR;J)b^|QN?t11W zas`{CV#Nbm)Y>rtg`80TDEl)om2ns_zCHpG$_qZeSY2R_(1?29K9NA3pXaU+ixSu% zs0py%p4VTwe`#1T$b+uGTGEY%yrFNy3N|KXw_dCuiCi~;&U4;ejyf6vlJ80%-Ye-P zJS8zZFF9e)z3+X(b!SsK(TVo8#mSfvd2dQ1oMdcom*-=$1K8|o3wBN}U-s)3dnSbX z;g)P*h8+51nQFTWE=&-}55O96S&#OQKl>o{4HW%6(OHNGMiYsR*#n^!>mK^jZEjpy zFzt;J>;_0=LWG0Ygk-5T(tQi3c*ARA?Gu?36iHcF&T-F*9TbERDRMwR8dMAafgw<+ zIqRBS8%Ke*DDQUSU{DnGCnF4ku%tp(w3Usk58Im%41G*GqEG7Jv*j8sG!b}e^E!fq zm+F!QU|O497Q!(8#{QW94r!O*;9NkWgY|WXO;y3y)e z5X=8u{=@>z;oBw3nD!-3A!2S{yo|Q$Dm8yq{dr-{!|Cs}bKjKm^TdMA_hlvQ$Cj-H zM67wHVYpZ9(C}e#!@?tDd4Wz~anC9W#})Q2$RVtg8r)HLl%oUuKblHp6wL2s8s38T zH=bGgPte;&xLJ-0yML^sO@sEIKvN4ymIabW75R{p2>L~V$z%c6o>?I|e=0(Q1qkN= ztUuYWX<>tqE2DJU5tB$147md$b=#zygSeh8wM-$itxpd0#O?+XZpRX+ zv@GD06D2-`AZf=T^;4>HRA;Fnnx<{RiHoKDo-1l{!a53KwElD?QZ_XpN@di0llOH{ zr_42q2z5jcu8816prsBkfPwJ&5hypTS_b+1g;Dr%kE9PVms4mM6d#dTQjDm3l=NX0Xujg5*y})-Q>f?=WEe}arq6h9_IT> zGos~T&gx`_mXsTHTz#>+6x=XB*h#9LAaB>GoQ4&@!u|KbWH73O>qB}Mkep0H&H}He z^b0`0w~~8t5`?+e{0vNkTgz#bh`Kcfj!0N#TbNIa`ZLyYT0{@0}NjWK{GAi4&H>>8h#jKu^LmI zM7gz^+z1Gw?~mAwd>F+tHc>{^+v878V3U`?%|v#0&=?sb58Hi~pGRz^)0&+w&Vycx8}`&UF@n8H8K;2GYM>x9RLNTKNe;|6Y=?JfG< zNTu=n&clyl+bI`}ZbehA%8#bC(!fK@Flw30V7U{LHiRXes^*cZJ&Rr@bd zW+=m|huA!Qqm(4J3LAU6`vqKzkpuCp^CkkL(_ly;OFSmOawK zR3Ut-Ucg|JR3oBSS7{@y;6G*R%u(wM<|g+D&^kds=tf^=VcwMI5o|Yk;-Vy2+l1hb zJ4T|d5H)_rTi(yOVFLN!q2^Hg+1j@#IUBVg@aCJ+)P7g0(u00lA8BAWd7*}q))_X^ zp{{stZ+>9_UKjU6|cV5ow9qQn(=GK4S}_bATi)Ro`4vC%VceLyCya!d{$8(sxF`C zNqzdrehxl>$&T6ZGZb$R^^q~{kAOP2bsk{AYg@w_^~M!MO(`>rL#3g8LED3kl@tISv%429tZRkd*&;zqNn*Dtjw32f*is2(Coj|8?X>`_V`cf<^Z{`6KzSx(8Axs9lId~4;Go7 zm2OsA4jdr6DV~VGPt~Vgr zayqw)H1CMk-_3y|o!a}5j-J%s1-mXvI(S<9+=(i7LF}=&_@Ra}WFpDfm98)St9As_q2Wvk?cuIhr!Vs)SBlTa1FdQ1f@hno@*+uPY zm23RRpf2t^G4Ib2yU9N3e!11(IAE&4ezKVTiR1>3OMT05mgqGW79P4Xzm$)&LcppR zB^5x~RZ-6qrc8pef!+@UKqu+<{8uJ>-h^6hBUO|Zg>K>a?VSa!Z;#T zSEJO|7R?-JW7srv928yXUp~yWu&DI{#-e=6B5b&$gEb--Lcfb=RQ_;qfT_z_x zanhf`E*B5e3@Y-YQ@+6Yn z0MBClySn9+5rBFu($2>A7%AZr+{ZBt$~xUN0kuHVw9|_9o`BJ7aS&#IuYacv1Cy^% zM1gQ}NzA%@b~NRDeHu=rKvmO_Ve$+WTZFD%m=!+izwrP=Heu_o2D+s;I3o_K@eLhY zf(3{o45STUjbQCJ=c9>?WxKiB8m^d>B|yDmuHQSb3e!MW%aKJlSBF^@gf&o6J}Na4 z15Jh9gGBP&JP3FCXdNtH;H88}kG|5UgNe^N4Uq7)a+oW%5Hoy;Z$u;K=FEycmWA8$ zhrt*MLQlm;G&I0UD;1v?T@m&vvGgDtVNTif9fdw<3QiC5i3uz5VQaz96BN5f~DlJ3?D%f4|#m3MndCZb)sMR1= z{1n1M)a5=_uCl#qjD~G~1&Q?8mK!KI!5z+#u4`|GFF@yHZ|}Sgw0oAkKz(kmT#1Lx ziN9SCj~;ZwGoYfv$DR%&O?$F%dF5PLm2Bq{IYqU-0&Lzb*^A~L z0px6Wk1I`R>@B$p6+2&YrP{w}TTAul$scPh2&Zn$!7-uFEO9v@E)SPFEs!&uRRC0l z*+nVzvEOBH$>U@B+Y0;`8JsBeN-WVoA^IO6^;#iAZcyj~Lc=MLHY|r^K=$`W7wOze zxf@bSRPF(Qf|;!E^+pst3V5FPRzabNUuR;T8P?Rq4pkX}y13}I`)A4M{!IJ*qRA+x z;FA(J6}*JrWqo=u3_X| z<-qc5?lY!SyU+Lw$T~2*1)Rz%Q%KcKqYM20sum3P0-D!M<`_wn*Wh)Y!kQRdEBkhD z$_KP=jr^LL+`#k&$<0UvEoO>GfAtL;XH%fB-FakH)sA4N?RVAEy~Wpr^M(d=|@Iit~TZH{NsXB@(~t2Ms5NmTe(37GU6K-eXg%W&)x%Ybj2=t(yEV+_mlt`ujvHzIc$%`o-_qOj#5Ymb(oIG zO1Q#8p&tIf!;e{-Lm*U2@=d-IqIZv2t{QEucC&_*x?6^60^a}%3dWZP1?&3Q#$jq$ zhS|6{RXdb@^fH~Ki$8JuRNNorS>gX{RpWMCxP1Ho# zata&D<{^4lX-HlDhfbt@7bPu=*B*-qnzXH=p;_#;7gMj}!joQQ1+HwQ0ZR?{pbuoN zeAR(o2?yx@a07iHeYY1y1+Zfg$xR3TJ?LlXNI(=Ymsb9a=w?7D2noxAA#ViF#KD4M z6OGl-fuo-DPTZK?L4Y=wk#4l8HWn4bf$y(&xo=YNJ`5`MwR02gEhwuA$6B^WCC^uK z`-uAurN{Vk&GzWaomdwmq=e$*Zd5RiTIR@W)aA(MN3A`5 zj!DhTEeIKU0joE6F{&O!G^PT&g>9;Ez$|P7TyW|k8I`Dm2vh_XAzrF;NM7Wu7U&x+ zVV}%rFo_W*+w2ayF;d@LImJo+YyxeNfgs5(fSM%7PK4M=omtq?SN#Ntq??m2oeH{R zka6=E;bBDED_C)C_teUYth4N)?Npj;4FirOdZ-rLZ0wOJ_gi;mRv6^(s6wIkK5aE( z1)k@cZ;~T{hDaakbgUS?fi{IG;a9ojMHTa~A|)Ty&Zo1Ba8(bUD$NNu02uB0vO6tG zM;YzAjz`_;=R8?USqqd}j0kT=uYW8zp{lcsI*Kiuuw}z-!Ac-DiN1Qu{=*Zh=dXlCa@{fj!cM@@8ah16EJ9 z0u_|Wz?V@bMMd&~ml97+4$Du(?ZYi^yW=LXvfk(ny?zAOB0BqMdI!>%Jqtkw^HJau zenf8Ts>ZXJ3EW`B{wy#~_+BkK;;)2C^H0iA?keq-H6>`-8E~cV-$RsJvBVr6nDv=^ z`<>08mcO6zrq@5h{qm}(Eepp^9S5v>c)NU0k73aXk#TYH@v*~VV~5i67NECyRK(t7 z4g>-zYQl+nxWNIG6sROg-7d?on&@_8vx;zKx1i!I-U+-aS5?D&tXxI0r+^u|g;fae zwP87`5ZZrTUQOUmFGVhdM_>-=F9WJ!f75gxN z-u|Rz>1Rk?ffRXE4wNG9$rYT{9Udla<-~DdYCKsA1&QuI-S$?Wr^$ycj_H-A;c?+1 zI+tJf#IMI#ex0bA(oTx~Ro-K&Hy(g)v_(&)5d$XtSQ6To;pG{e$Jy70EiveDunHU& zh+}Eva&_*)Fprs+SFc<})KmAIhZOQyKBnGqMyy|YbaoJ>Je3<#v$p|?O5O>1Vx&2c zVVR4{@PnsFIX6F*RS|ER#YYle??OI$*dVk;vQMMXmGe8Q_!9#!!_we7pb0-*#}@ML z0Yg0+`v-!zHy>)@fozjN5fUg5I`RkT3+4`NIJJK!Uvb#E;z(br{-?ZJ^@^ZH94T%8 zTh22L9MCxZxX9_xVNgp1HG=WnohJT%(L?o1G>5?_)EEPmRTd^&m8(28g$e+8w;ci| zf3xu?y{VfoT;VOjXJtO_+6m< ztl$*?&bJ=kW~};Rb{?oeTU?Z;YSL?lkJ=g9A6Sn<;LjNfo`}hVBZxj`Kj<0#^SmLf zue76SuHexMmc~CYzK6xVwP9LMN_N9VilFDW>8PwCK%9Y5?mh#z6ZAl9xJQ`^*AmW& z0a#@-W0>z`(B+tXkdoY#MjW!C*r^t>aPJ@>)R{`$_$)abN)FO_Nq@U3ZPa=eU8w_^ zTQ!Cxq1pq9pCB4o1A>hV-hkpKRF)kEm~|-Cqp$-lsidfJbVm-f#xm;UQ?7rR<)&4a z98L^Sz3a}6V0c#DC~_xFWd)fiawzKx7*0h{88MDPGRl=J(Yl#u>(Q@_hW~+Wa#qYk zz`|TYTw2<8D0;rAe7Fi7sf_F6@yO}bUU1^TENn`bDl5?M*n$0dd;?uinq5UnrKCM_ zs#iulG@R0g!I~#JJR&0^Dl6?+9m=_8tU}kDlmt?CF$C1}oS?yQ@bB{gMLfCER-6I+ zZh+ddaZ@fM6U{o%UDeXU2a7QGPTg^1@1A;`{-**RXmk?el#FV zm-UZ{4QAoy$@EySybmQKC7Z4WT!!nEwarelicKEY^+bIN?f@EN4Vfm)U zx>ZzT3eXRL15H&Qb|j72l$XFUnQ&-hbf=KCPf}Hk;MrT9hUS7e!pgh6W7fgIgvK?L zL8sEK% zoLrwf@zUBx$`g@?!bbV}X`m-v&s8I@lsnMFX`&nvIUm8$w+?lFLpOxJoudsDoa33V z>O$#__jI4os%A=o8Ww>>+~9Hy*lbDwUC2UsbF{hQrvW#w2tc{dj@G6%TW)w!ACJPm zJcom5>Wx#rS$~7m|5rFrwSpYjv=b`efVHA`!G*G~o?~c;9{qz)vGmQ2zy#(=Cj=#- zv}NJ_Ri$4dl)82#(s+9$80>OT#B56?n{^)2>ygSx4ULVuZ3@O8^Z|Zi;T5E&4N@UF zss`xoQLaAQu?VJlm$ZxNLJTJUroUiEvAy5zx9Hf2ll5ulXG%kgk5yXOmr%neoM=c% zD=#*nEwP{|iXF_1NJWLT;i(36pd}V4mpG*bmZCCX86oQfc3^WW{$JzqC&4qdr0GOw+3wWV^6 zHa5_EA-`e6B>(zgj8N#c2x?Blkmi%Y_ zSxmClG%{a3Zy&5@aEX6UEe3CMMz8N#N9Z6Rp7$Y-6kQdn^i=mIbqc@eEzRwuG;?y8 zO#iB!0Gz@9bYuFZGlq5l9&~PZN*!~K}>dJ`t2P>socX|0TxUy;`SS zr7yZFwbT$jz#&~If~G&n8%`sN5uShXslJw&au;SJs1%3gR0c<^k<}Af$+})jh!oyK z*@(NXCM-Sm*JqLoa;_oJIImr3x9=s zPS8z^6S6gPb(J97Y9np4Cd0I>(_l6-fj-TT>hS#o0@}RhG`LMH-~0Xub4@vX^>M)PvSn9-G)FT^dt0f_ zcV5LKtXPg=XafZ54n$0uBh?WTE-gyu2uRGfk0J-Teu`&2AUyi(W0s6$G)x{ z?VHtuY5-4mY&bnA24%1M81tipD|^sWh3}~^FEG>S>=@jA(L-S0*s_W_>&D_;5JI^R ztxDJM49Xg(Ofx-Jw73LuILBGT_cL?u9(VOoX}zc9i9fNb@Bhw#0>o6MhNPRIye?|u97)xlq?D*1iKXY0l*{V3mj*(` zZoexqUNGpYL}SJSvsm)zOil7i(>2bTqlfFsE(3td4Uc=$_9@B|^;-KM}?AMJJUEQJ16AMYnYm*}?nb@&wQ%zaKBKEz!W1vLgr zAU_b=Wj1HxM$fCBYL+z@z*8}78&1GD@XSD118nNw0!Hp)(Gd&^FR>Q1o zHd!Zxi|SL(mVBrw1RQHZODBW>lKheKg=q@d3egbUYrW{j++#^%6`&B9&LYtPAVW|X z{pelRrYR)@peALqq-so|8&TZFg}^r(KD74iPpkSqWuREjeK28CVJ_K&!=h@~n2P7M z@MJ|UD_ki=H)PgWSl7I$sjuo49}n_vWcbjy^oY!%QE6~I0!0$3D98!^v|@+;HM+9^ zL5IkBy@WU326u{)8rXPk02?5R&%<30 zpNFSx!xqo5Rl26-bV zx4VOuM>6$i`>k?}k$hC!B-j=C($$>Yj<&`~Wx5}JW}rp;GDb+`)D+q~qX(U+$f|4s zH2C$V5=X~6JxF}GN781wvWR;mZ(6z~pourc^*FGW74AvM%cCiL)h#5{ zi*%_Ju?n5{k~dDc@P=a2diwZKZUQ-fc?x1LGcPvIT7j5J1DdeZW`)w#iN0!y+#tNc zMHhlboHwIPY2GK85!VCQ*NS^mwhb9ZJ+vKs9ywsz33pmM;nD!9$|_|M1c3I*v&j3c0@E|s z<3ArPhA0o&Pr$0I>Q|ap@kc`z^AELZN6(63Aro&l) zCie@|efkee0`WYB!A<6Awt}Ufc7bz?NhC@eYw(V(lqOd5hnhS?AnGLBAC$kbKvkbiv_zdPxy4u)4Wzsi|v76mr zcixqdUWZB9l;251JKEt%ng>fIYSlugr}S5#?~$E`^?K`<5O!GhJhuX6hwHjhiwnp6 z*fzBdg;zwUW?!ljK`TGYZ%Z&C8?Lgi<55ok;0Ojsiwj;fI1*Uaj%)HA*$F#sI}=Y! z@E*r5n)q00S(L7}6P;X>?+>#`-M198Hs78<2~f#4ceZd|n-6==4aU!;D{J$MO)Z3Q z@}7n4_1L=nQ6k@A7lPhNs5;=4jzrn{;SL&KLMkWBRR}L2LvC;pf}*KV?hUR~T#4L@ zjBTkeXI5gci#P6M=l@GYH2x8eWc!IFXmIB-O8e@@(e;?~))jMPX@OR^`($6;02=*i zuBx<#$C8w_0oO0$CD1Rc(ba87W2xH)3=Pg}sqK%a<7wrF{MXfTi>1*4Esu&cQr4o@9H6-D=denmtS zr}(t$4K0FDX^)Fx(zCDf`)=Js`#OJ^RpuwWj0J<=QN9(;b-NXnYSfVAe)?*v0`?fZC*QWeNP9oMm%UPi%l^|q*O(^6r zN=Bghm>gs+X#s)e36aqaVBa{(0@!2{o4ZNqX7fW%$}%y}27i;kL5=FZSN~q%WR|)|()_1f?OO;W!0Aj40at0$)qndK21R{Vo9*-t%llDS5vU zfC1zY$*L^?FgR|My7y>9H915IQLV0_t|;PRj)u_QPxDcJ3OwIRYVm!3cSP?DGD0c< zu=m@tnkLi70XX@oKjc@}n4*3&Fe51t#c>u|bV`tFX6mMC$a6cUf(WF#qDO;RMZ}3< z6?SE-qjWV@5=!!+6R_HSu|waT!#%M2rd&&-@ioDku&FP>)3PRxSPCKs)mZFeUR0Nb zf1tS7uv7ww7Zm&8E1u`84{2-YpoluH;4Rwuu{n(FgqRccZMd7MVdOt)g_P1?LxOSG zVD3Nwd^?O5v)0Dcxj@(Ko{N8>%VRCQ0hReTjt-&7DoP3=csf9jmm=m=f^+-RilE#E zs`=&59KMyKTqtZXp(VlvVPY{3VMNxJ&Bx${>F)?oK}&Z63j|>aHe3`q+22^99whUUmS5;8=qZUu1UGmhG4fRVLym6A!uqsE2YA(%<+zX3@pW--t} zF|1&6hfW+buB7*V%pXB-?8slw*jRhTQ4oi@gEe_624xgYTZ&aF;<1rs5 zq!2mFH80X)O;#j%qw=|FX?s6Hk0#_Mh5Kf`YZld{_(*+QdSxPOvzzEUf`l=K(xdd@ zQqea`RW}I|2`Nre@fOA1OWig+TreTs)*khs@c7Gv>F}z;6#62WBT;T<{+Qy!%De%~Q z*baQAEH^hUU+F=Q@)Y4V1eFr#8t0=kfk*3I9zK`EUiGLWrqTwEh+R72UjXO&I=~Yn zsDma{19U$V3-F^{YGN5@E^pHA0xTyS67Za{7Zkr`SBggr=AhB7LF|+=N=E(6WZXs> zPf({8og8e8;w`iJTmoB;K`rJ8%59LGQPmT1a2zo6>37=aXgjNS2 zNnL@t6{3Z=qVPr5C*c-KbAGonl|kGVhIFB8I=QooO2~PFRBluuN@L0E z45gGr6H&Ca8;%EU_L>|NjnTMi;xMJ^BD~tC@9Mm3-d?DkAj>Mx{7fs{7H2^l0g=WEJzFLETTWQ0eX zMB+=jW6`Tqf~i-i9BD^eA0I^zWja=*+mTnH<#s`N;Sg?x;Ex;NTQbgPt8IEv2bhxA z7=Zk%c#tCa-Q=Uf&QliMLI|1CcrizMliCG0WYUC=I-$ysL`yP|h9H=1V#O!(!>|eV(g!b= zE(Ou~xd^CB4X{v;1xwkZu%mz}s6Tn%nFF0Y`N_;K_my;am0*NfSU~9Q3J6kdXoF*D z%6(io);ySSVb4l50u{F5%6wsI$VIkouNXr3%G=Pa0cSwaUWrXDc)%F|SuSfQ(Zq+A zyM}_7BNU4mStzWFWeTydo3!gSyHWGs_{8|M(E$Z^~QLe=b%&6UNP|Co~a@_VUG0FD{MUax^z!Ez`UhP!D#510f!rmfO zMVLKz$DnV%$uO2ue^)xIuyR1Y>e1#;kduq^o3%y%0loGI)-Hg~!^$eY2R*|Z92tX( zDpa5#ozBl7<(rGI(z^G~yU^`t*qImy$mu_1qL3pnsW13#eFZ9+rk?{HK-2BRA!7Lx ziZ~A>7BDIg9*S7>!Jt#x1iCmO5c-*9%@bl&cumNdBvusM@GfRM`y%G4~tIEfMgy! zNYr9%S&2Kq{Wx+z{!Sli>})w+0^NOEm#^kHqIYP)q6zx|l<0w7vF2octhN}TmI}_m z?%X>3Zgo06^>8DaR>6=VmQ{QeJd~#_MsH~p9C1A?mJcEF??(Gw%%{Nl;j@Aw%62us z0#Gn0n>WOL;r$OnNCbjy6PCL_3->k4=OFB%S3+sb7}PUUhXUu5QxRS>VxpllUWRJ9 z^+Pxy8{5E?WuRF{2 zZ&S{ECdWJ92D0x7w%L`HaahrEKpV4Y1@HH!PxVxv;D=Rk(!4X`IFU52=|%Ag@i;)v z=Mg6!^dt{_Of(gKWDTQ*9){W(Br`ZSyXOJvD#|tD*N_;E6AaiQL#* z7jLD7QS44w+-xT`9sLW;V>|JNNGlGpz`CJo;!Ry@ zL-|D9^a=h*pT6)%{yTgB<+} zoq6e!lUUtBm57s&n_oBO;G%=J!6}$(|u0{HW6>m7{~29z?TcoI@5&qA1HRC@HU1T{3T}q z8)=+xaRPnN2J0$kL)iZ>Edewp_4K)lw6zT+HHEv{EcRg7Jm*Ap`en!YcGNiuH-O*3 zPWZ!|6E*1FBouhsHN@<)H*eTL=5j|EeaYIv{|yzl-eMiA;xQH1-$8;M86$m@WXN-( zr#bpeN^5IaNZb8!^}p&s_BqoQs}lEF=&!bzM29{?`Q+ph#oI2$gR-Ji4$|6&?GQ)} zR#09V)())b@rpi$7U5q`@ltj>L!cAJ-B;}m9!~Vuy1c3c>!%rZE0GBUV=ghgo8=5O zpyX|ke1Eg}7W|G5E4RcpWt&reu9|?qG-0Gm1t;f{g++*ZiUk|@KP8M0=E=<|RmRq~ z|2TwF1*+YgKc>?6nMmhK75le(9rdFwC(w8j8fImHxRL7&%`N&j|9i4YgQ`PN_5RaK zn9nOw`27EnUwRRwvR&wL;!QATv_*o73ACuoCG>?8uOnQ1am(Asu8M=C&5UTm>@7FX zZg} z&w+;f2MHx56#y_hz7_zmHrZlb@=PtNP6v9OL!IMog*XHdC z6>f3oO|r88B#q?tmA6&cRrj#VAt&((mXkv=(p_v6hhdI_B~K)TwuvHRAspq20%ReC zkB8(T!{tnokSVTMwFQEGB}0!PK>HeI!fSzlPW=_w9#N%3BaI8+kPiNwQ$v{Ou@G39 z7L>iQo+m{<=4amqcwkHSsofsbCG=Cp* zEpUsxXvZCGBY}5*37?;9g}{zvTCuCj$s|!$M9if{n9t^6RvDgI*=CV+{~HBT2hr_O z)Zl&A1e;Q5@dTqMb(^6-Xv*}eU?jiz3{OQUY&7E;)S8ya7?mPywb z^fAhbTlqA^kAJ^GFVZM)8uAg^igk7?W7OU_>|N}&4dRgKaE2!iY}UC^6D<3U6H$uo zXC38Qm-e8}Dd6GUTgS##UXH^O$Gz9%VF9vtkwk{`({pXZ@)H?V*m&_~1@dP<`x#>G zP7rJ)2rG0W_b#{@dC-^lvp4sOkE4#=kXwmztXX&1pPIb@ZoHn+=)G#Ac=87e;Ro;& z8v4LV2MRhT8>Td|`$^Qw%8LJr26idc=IWGu4xk`q(}&kwUy_{>5Lz1wU@0j23)4qD zzA8z;ekK5e zl5D`jH{H;#LQ|W~nr$R}8c@my=E%DXRLw9e?ILoBmn92JbZ#(1W8i>}J+iGB7^v*o z>ykkr%|zwPwq?)x(LNvDBdm*Nd8s9Kv6q?!N>Gw|&BR~qKPT<)!xi}{i? z6+O*T1G)c3Ajt}cw|!#1kByx+TtZCV1Y&Qnaf$Q8RQhk5p)(P~TPGf9xJ|~GWKf)y z@Ak-9NN7x%2(*p@RI86tbAwWaqe{&0`o9nq#;B-!%MjtfgbyVP_D96?cj#7K7rZiQ z`zwZ%LQw?XcB))It2F?blhfu@Q|gs{)tfd{zP5nAbuaQ(d1J!ltlDA}YPT*bX(9!8 zHPk_4+&W$uFC}$1?DDjm=m5-{{j5paKFF{Q4R_?}m@5`nYYI-~X@Vu6)oFl*$w0k5 z6R0jcxrkK5a)w=WqQ{aBw$0liPwMpvlzPW@N4)r=8z>vmY52CwP6N(&=ERFWw0SIVF{)oqmUuKGy%eR zwM~Ic24t349P}7OS1qwATKnO)@rsMejE#-S3{Q_9HWYZ)Oi@48fUfY;$bHo#tcD?} zIJK9>=NdK@g^3lnv#bSK;3xX;;&uk+I-R^Nx&fW(!C$xQse~m_#ry}2AseR&A?(7X z44bZx0~3isR4>E4bZ>ORz;qCpQ$2=9wRju!e{&}IDrc>X?H18F|C_{G#n7z(py3l& zwhx7t!og@n8{tQl-xEgf|2wkB6i%6Y;VN`{g{Hc=w9EhTxwA1HG10BXlL9LI-{cIUc?5Wt#fXGpL=qP|zxH#DYeBYDPh(+|Q;^~v=FYtS;`-Q4zXZE7c@>t=6C z@}b&45UsaiQ_d#;XBY!Vbsi>MqcaAC=&z?lv%-h&7eUwQ-c?K^+aA7nY+Ms%(+k*t zm)CdF0FYan_6RL02s=O{=z{XM!zTBm$|5Qk{Uq^m#EpHZj6$cQY(#W^E>=NsT1KU# zoIDa#ein=!H&Px=$%8O^ut3>0XWsU}0_CvZLhDyzvo+gxvuY<;H=L`eqZ826COthiE-gMi zGhFTDfw2}rr3n_-H}DeRh3sisZVoJ3L(slO2k6&Rz18MKtgo&wd&7XGsU9T?mGbhM zDKJG$V$+zG8c~WzYf3nw1yBl{5hVnbsb&l&79sCThfT(g4w@ZY@qoPDvBTX6nnP;m zi%xUHstp^c*^9;^>RP@7yBP-I?dBl3@ipEnsX5(b($b zvmIPzQMZG}Mj|e9>~>K0#S3o)5WCm zx1f^>EL4V^$YQBXoPrtkR2A1*g6i5!v?~(nvNqR;{?I`f6+{MPbyRhw0mw(x(;V4V zgKpud*1nCsb*2;`ebQdJ*oXr2a=oSFD-Bnj>b9`&D>^f*sSL zJ#Ol&FwmxD&mkiUFzO~eVrWAE|K^`pi)v>XMzB;seVnQN3@Jy2ep|oWBUt`(vZ})g z^-gP3yxc59s8~c8n&wG=WEpOW#S#M%RD$}HvZOG8>Kw!wHvJTzWGtG9g%LVf8~0k2 zqUg{iJc<6F8h%~12X&bb+7^CJ*H;@_i!GKe*FBy{#h)3xXw+wh{ic`;DkxX;Lda_a zx^&Cd7`|6GjqoV?;oH+&q}yu^P}da3RV;KSrG8-;qUNxinh3||)ZK=PRHrq>3jEgt zxN-lTtB5?i>jDDH{!|HFT14fpb{}T`;2tbylppTpYvqf22J}(7;|gv$&2__>JMa3hXU` z+Ta;@JS1COF92p#gHHll&XbnBR|p)$23%^Z&4%6_>TyzpqurAxZ!t92s5fhclc;M5 z0LndQaBdrRI#ZiXDd_1oGg$#KehtcPa9Mr5_K$`}w0FDVa}!t%75<2O+Rp46Uzz+`qvFkNWCmgZ!5mNdI}Hi+ z{=V~`wr(pO#6c;z)0ujddh|#j3eSet(u7@x2Br<%5xqZ@JlU8_Aj2G)tw2c$ApBtv zNfP0Hsp63>|ajJ>Hq-9TxoQsAeY1wXr8$`aKR6?u4C&Ajbd^M_;sjFd- zk-9(Mo&0|`L{sxr1Un)$&9+E!v}dmB33dYeM6U-Z3qfk#$Je?_a1+J@@3g z(w_GK$`I+vO?L#j!Xg3qu(?!t6&s=m@obd80?GT7_6=1YLcH6Iu~TDnU;_Zu2HkwvOjoEU~B1o%oPZh&;? zfFVUggQBrEnZ*jy$ZI+<-T2dwAcBxif4_#dy7=?eJ!}m>82clv+0hkVW$Y;B9WtD8 zrsT&!LGt6EiXMo$G>1@i*s8;fX)*f(1a{_}Y78_GqOMRGn}~R9kPU#6VAiLGnlwQ+ zG@-0tm2cJHDFTR%wKA4~{x^;_r5%fJ0Mdz-Mp~*EMmbUD2AJ2|W0nObtYp&pRupM8 zToyl}L1>CsT2hZZEK%lYQ{+WCck^mVYw`?;7R5;;(oAH9kNOl|qqrsgb<{EB^A?F|gxt-SmYoPHy{O!{Ew)q$$(x8Ny@093Hd*L?spL~$A^MTTAKnVzZ!%69aqp{M$hQr&>ZtAwWxWPvB=z!1SSLIO~#GvMi96F+^te zy^=lz>DM^&dT^u>HK+&1j$51DshQCi4rW5F~(^T%mmVE$toZ|oZ?uSeB>@$XKyzc?>d)44BjXh(y z>S-6Jgu}l6FvNVTqf_m*^|m{O57E2QZB5}ws&d;f-tO}V7>v*r`tG*+WW360oO5NI zdK}W$p(Xw}ABar3(B=aDhcrE3|I8~sHZwdXJUt=;lWTD45g=45$s4HuaIh_k=VCaOL79X0F$jcd z9MxRnPE%*_3LikP+Q+=5n~w|$>b?!JgH6Ft3_vU*6T?&xpV{}+aE6w-0^|dX^a^V6 zdw~kIpc}s%ei5NF*Y^)y%%(Lyr;sE*Gnn85NN7L0i2eVOVIsZuCl;jPAA;F3e>CK# zwtiGpU%K|Ep|OUt69B6c*#G24*L-R7F93#k{f#I}oC8G24qe$*Pm&C=bqXZ}8?;^Tphv9II@u{lrYq~6*v$3Vz56TGkb(;rjtG4P-V zyBNEuZ$-nL{@lN)r>pU#+D5&l$ z#vXLB0d8{1oUI^_fyw>jtp zG^D>-{mhYz=jlM>6iOPzyO?!pE=cNA&6wvbwg6TbUAJ3X!iJlk^n*VpotKC9o>V8u z*wBr}{|#or90T&NOF7sm@f(ArgAI&s?sRd=wKxiHhI_uhRjwOVIAO3y52B&fdnsBN zsOwiJ$~#<-mhHIao%Oo5B1NEY-dcretX^hl$>%3*pxtEee|!-swzVhp3p zk^D8L1aH$^!udoQ2Z|%Fx`2>~)48lzV}jH>+W5>AxAk|@g=x@f61ol7A6*Tn2M4h{ zLk%jBw#FL6)#wg+m8&`eVvVkJFU}YyCB_*yR!~zZU?8A7)ymjOgSc~j*sC3MR{gEM@tW5)2<0M54i9%h`vcvUh%<7X>rO#R$-&N%XG^o}ILgPCX5XGBO z44{E?rV#us62k{sXicXl8BeQc1&)3o{po_}?S2Siw&2OA>bx@&NQw88aeG8q3U9YS z`l2_0q1V$6Ct_K`oV2CL6Lg@P*gzhjkA_0WjZ@vIQCs61>TyCqeNp*O?8~5%U>ea@ zZrzICImFZ$1i9WNjVLwaqze@;&#NmPZEH*vYc2CoAb__Vdm~#{5UeXg)NmpKMQ`yf zcCL^Hx92Yiu13=;x~Vj5=otjYuNdDEA7-VngVRfbXlu{>W;Cw@?k6`PP)yiXHy=^c zs*^DuneiF%u^G`r!{ahA-g_?vyCDJvH&*VY)*VgXV8(?%mR8X)p0x(@#rr?F8A5s0 z5n(9&A#qLcE%T-Kxr%!pBnhhEtpgGP{mOuIF|=RbTZKH1ikZ6J;AgkKi%FfsxJaMt#0rJXnAp3FJekZ6SGT_@uL zHbzHNggp{M{qP%HcU8S9Fo$c>G8g<1W-ofu-<*Op=zT1u`p)PSmB>seM=T6-?$7 zqs~<@3eECT*`kD6#v=iFg)mA0fe560o6G^bv-b`x4&jeLZQ1jYejmklGatQPHC%0l z_mGDl`CWgKnszt8(XARnZn#kgP`e(+-O`ip##dE@zG@)_E#_qEvmPa?QgjtxD%3)< zb{rMEtZA#OoMP;wJ_|tg1642jtyQ5i{`WI|F}>d#oJj_eTh($IlrNAl?8C+Vfl_Fo z5T>w)7CI>IB1Pzf+H>}T;>xsnC-_)qHgqpFvOfg5E4$Db)lpXTh0qnAiYNu~x7BpUR)MOTw5YeSzpI+IL}L+Td{-G1 zmPlaWH0F;)q}+Ca_z>5aF~!VwWRNb<>j4~!4L5TZP&ubM!GgRxE*MLit<4xWd0ATr z2v9cY6aQuz1gCJRWPlL`3GRLHhk%$9nUU}wW2Q&lX`IFRUF=8A1{p(~*$G1kT%k1b z9&`~g^x9VfwimXl*j%Jot*y&_SZUsa#(mNTKY}RJp z`EtQ4O_akjw}dixBeS8{Fhs2|6ALAzXRSFi>qS58hwQ@Q=17dnxQIbrC|ypb#3U@P z*t?q2tP?ol{W@&v0~cX7y}|`>voBb~Mv-=KaL0yVu>>QFSt5kipe%S$x$q7h7=*Zs z>(RKkDEvimOht&PDpQM=SKXy@A~;HNbF4v*-};j)amuGy;0k=C_P9)SVBbfMoPGD!t0hM(xg9d=54$$;JAoM+Wu59m5z=wnkwgrMhbsIdrj#1r#?pk zvQi0@3dc{yx*t3a0s8RK#!g~i_J<5?Su?gs6haH|NtAnDql?vG2eWSAWj_iVW4tTA zLm7+%-+J|=iZ0($Gp`xFISzZ;tamQgCTXm(y_(rzF=c>(xRd4&&EQk^7Hb_bQk;`V zdl0Xcqgo*OUDpF&cIq_L!g@ecAa1;ICoe+~Kw5sO26?T|ZA>lRH3rZoJv2_r1X7|v zVlR_0fsMLRvHA@h$zC;YSEiWB;ByINc%5E|mH|YoOcU4VTEV;7D&Ah@s7}_L;s8~% z=t8m)2HkB=`IK%RLQi`cw7;n9eF2)=cDW#)Ci2OS`zklZ%C@Wc39#d>os`)k-|&yM zx9E$7=%Bq|gX;N0WgNPoYHe>S17P&HG^7VM9%XLyd1u2&Zd8M;z}6O#N!VdwTkS>< zx$L0|(q_Ty{_#Ddz}`1gv5cD3 zqJ|b;Lnh@vM>GSiGEcg&v1D&q82iQNIJ3{I%6qBb`-mBiBL?D_y*&5<*MCb984MnD zjGZ3X4fbF**lAyC^Fmu!>iWL!ZAbLeP%LC7Fts;QlWKHy%k4N?)*7_+``e1Gp~Wsv zXc}DJfVzuilja~4LZV$PtVx!IGb5?F)ni#A?Xl13wg`?po{k6QBwqHWuil5qskjkV z3J0F__sXKyG;tzuI_^y!X4H}Cmr(Wnr(?Zzl_;$1APe(XfzE3nrH z${}Zg?cG!WbET%8z^KEfDroyn=+GCpr_t{djkCEUY|F=2u~C_yo&d)>O7@mEPcp)8 zNGxL~+0Ko7D2%917Da5P{fI6WES&*aXDgHuI15%gS>F+)GpD`!4r-nTQ1xYNn5>=lRJ8;in(3^;>ZZ&FyO zLoHHq$TBS{Je{fP(vOhlQmew+bo(PrEYDD2P+>h}5*@GH1@&2hl}+AVGKeP4$E+#% z3+2_perKCg@)=ZpvY+0rLAT}`tJ$3mDjw{N;m9_FSX7>essM19OqPPE#tU?xBP{~p zrWRpB6oHe_0MRPsYr0!Gw1^e&`CqzVsqq5iXiZiDh9U9=R~qPqu9IM?Mqnf2ibhr? zePs$S1mt;ZAQFn4w4>E1`EP7NExhyG}*kU=X%rA_#dn42K}>Q~`s;`Etuf_h(I?ukE=DdiOU`WP^f zK3)xNuG634qabAM8DcfjuszPy zVYMCK{TpHtk7ge5`5n5&suEk#mlvzk&+q5P2=_Xt zC~5s#)4={(jQ|Y3ZP8K_Bd^UQ4v~Ke}9HQZG}!t31;O>no={!4AB55Kt#Y) z^5b;D--eO2&{>xuHVq6D^OogLO_oY;!!BH7!2)pluN*IkrTQC9Q=WbT8jJjz1FO|=KN8f- z3-OF#bM40osxJjG?rKRoj7^1!H6A4XP0Q^I{Y}P9s>_;uDzRSb_l>a@VhmtAoMRZ+l2e#K z|N58lTY>WOkGH$-7$hcwSqW%Ys0KJ-q1yz&LVZeohGcfN0c&dNcg6;E{ab9SDLtVY zD>5lKqqQKf&2TTCbr`+O=GStq3=Q@_li#8(6_IS?NS*onar{Uj(j%&;O(^`q%?ea| zDzMzwzcYR#QY7aXbbz_EDxtL6$_e+&QJpm=7PLvYBGI`YjID9e2sM1Az|F?4PIRML zuAh{)#kjDdDuG&iw{atF9HJdeO4#jadb%6y=Cz>QA>{go{y-T+3~BxoZIF}H=O-gH zPI&M+$711c`xqe3V|$EsonsMQmy>eP^<;oHHrzv7^uEt=532tj^zMaTaY$Q0L%OyF z+6a;cBWTAOZ8(K{=LXT3`-mvBJ6sQ?LOtMOV^?Co$Bp`gvV&0o!@t64tPbr*ag_0V zfGuqyUGNVw4yw4<*i_YDjoxd72O%mB(yG12ZO)QM(YaYpbY&05?SKQuEH&T%<$&=q ztb%m!2ce75s4^ADU-8lzwFtir@sgllD#5n;KGFWsqrm@q{)u1g-D5Gv#fE}@n z4sxkLG88y(sP*R8ijbXbm{Cx>T>c|I&s~4Tyg0%)z0perx&3Kn6UbJJuW7F0Yb`cm zIgNP;VbCQ0leb*p` z`p9P}o?PrbcjZ1#-X_F5P1rk+T~>ho}17iKI5y za3Nwx8w}{2lyc1&rY_M8rE5$l+;PQUwYr($nU;_lAD14V7N0pRJPOuMZD&9nnu)b2 zfu;^UlR$r5$B}@LYb{m2VGI(uc5hY>YeWM*a1cu$3lDr-=+OiiiW=9ex!gnqlz5bF z|ITeit!^8Kh*vSh53aw8f$~&aiJJZit|D5KZj^J|I8W?JjL~XDaEkV4*m@{6<}kBv z@bP5&@Q%@+trb*x2^%>hfX_n(`PMC*?;W<3OHOD)-uFJ?y0fW_w%FA>d=YVZu&~_& z%x;O3tkCuOKn00z4f0L6lGe~wrwL)8#n?=>5aEJBOKO(Z{b62#UVklgrnqH5&=qbX zd?{2xVGC-B>M$zYj7+i>>H%NYpPeK^U!vB7BCl9)OcFgzP-P3mR;v5qz`D5kqAZUp zd?;n_zyb5;qH|{L6``$q=F@Q3`L3mo`f zVhl9oh8t0{o%pjK|0y(w#T#$2rtsJ%D1%!}ob55=t;vXDI<@C0h0DQy5%$_U5TFex z09cMq1(HJGnUZ-2^7at^??f|B7t|!*2M}kc?I(e|*?uI720Clo(p4928+x!Szr#!6 zLj&mk`kTpCMBR}LLi$U>#gxjD2ZN&Ys_ zppMNLu=@7(XuA;3N^6Abc7h~jwhv0?ul$a{t8>>96~jY^e9#Ci1qU5yg_7@sF0edU zI{7FT-TOz~h@ECtC2)cAF@sH10Y*@Uk(U4b5dCSd`i9XAF=>)@7x3*~?#5awTWr=Z zN~$W)2*6R_^57`rRn=lTa2hGJaEZ34^OTQJt5fHy|Ed(M3BkUo)cnAzq{&<`7k*Ii zv2&xs)ySGHg^;YpXn6##hUV?8{NtNwuP+9|;b=@0a8qsZDc^8}_^H6L5O6FW3=m4V0e% zJ@)!d?gMjB;C0SU*4L(4d-8**cpBgrHgcnlS@^gMC2ufPl&9bl4vW2HcF`6rx!(C_Ko z4)kI_qI@Cq{_rgH|KT~FNuM6TYu)byotB!1&d7tgDEeo=ce*MICl7bP!E8W}C*MYh zmI-X-s2{ccEDX(d6y6OUy^9a#r>WvU_z1k!ngEQS9D~aSPeCk&?^5a^{N##s6g*!4 z4M%|sCYI5UPbJZ%L-}9Z62;RfI~^cCp;Rqv^9NAJ#R{|o9LrjVWL<_=UAZdMC%tae zQjb)sd7U&0Ld7=9)TqNzE`*y+6p|qI&y>nI`J9W|5c+@Iy?2~c<=H--UAn-syED6V zSYRu43tK>t1(l8zgBlFI7)83V#ey13ECDodze!#djm9Kz62UeS#l|*w_AnH&fl}-e zX^9#Q>i4?u=aiX!o-;cT-|z4D`Tj$hIdjf)o^sdgzHVv4`N$r$j$YPh&p5ih3gYPG zYgn$B650{e>XQg~R)*D%pwFrrUhrqmHdVxqdKB>oxgTnoXAqdU`_fNput~GD6`4XvRHgxR-L%&e5ugZTov_ z+Y6~(%$-|r_$NrS&_W#r4vX+h;j6y7zTv2_E5U+6KQE-k+<55&zlJ&Ymsj6tMSs2P z%~X2tLO>hkH>(#PXhGY<4JfK(j&?+8H=nn6E{&L4J&&Gb#MMJnfrh#AU;9&H`;<%5 zzF?W2oJYsNyj>MEyaBCEuKU;i*6L>np4ZWV2J~_{c`ib;45yOZF#LBHEhVBwvT0&^ z7 z?}=hCW^PBh%mEQbQ3MmNMYDz%(b*-2L5-$lBc1!Zry#l!j~GrTx+7X3Bwl$q3vLTd zx_&jzk0h27r|xnK(A~zD+``8P7`R|y!@%mkdUgEGUn5h9&QFBS5`rs# z0TLMVUqD$ICvd1&H9|Fm7S>MX>iK+Hy|9*7sAwU81`ecfD0Dva8|UjW7BjL?-E{x9 znqb1k_mZt?UyT6iI3CcVHBf9)Q2Co$pd!C(kHU~6f2rpN;hYequu<>?$e5fPcbN``M^v{3P51wd56`iz>!&TYw{_B0zFRFiC)s3dy zSlge*e+DBE8Su2RT6m&d`$W$|6&dh|3T6Vza^?)U#M(AgosNWna!489iom?=P6@a< zT&8oPNJ(EkiP$uF0?N~MB1xL^)$R=1bOe)e`)BoY2)t&QR5oHy2lZL{k$Sy#BMK8Q z*@ui5|7bEUP-Z{MK3dZHqp0b)8=q;$B`Rvy9YxCKRsMlMb%FN(YPWrxmPhfaunFAT zj~QM0)@So)5*7zyKz_TLKVj{PC6*ArT(?!O;}U#?lDOvZ#0Xy{J^k0T=!Q>Z4ROyg>c0@~dQ#66yYW!F>WaZ?ediSPx@ zeABwB703p5KuMmp13dPf8b|g{~%A!dFst2HTx9s z0=S`#Um%#-kK3OXf3fXN%DN5xAn*MLu$z46;U1Ta*BM3$b&eSfB6ax<)tb2FF&t;UQ83N z-&s2wBtdckD96yvd=1Dt#5gD%qI!?Sd#+fC zWh)W>u{UC1mDz~&IjWSg^~c5^{Ao(@q9G-Pg+&$f7L=o?h91fRHA-jnk2Z5;;;w@E z7R<`BESU5xQShk%>>Zd2?|2b1Pjm9&AGadMVuR?TRpaAPk$?1w2E*5FRSW3m=df3L z+>Y_0v!I|@fbEEm_k-n@+Y4UGk$-cPKa-mOY@fZ$j~)kj>*&AgTZaPws&A7_dj`}< zYq%EhG@JjesynBZvqQ+~ZQ2A^uXk59L}Y0<*1)A*;uu+?S^maN3Z{N_$Kv*@FreEqra(74?U6;-kzjR8pssC zRu^zn)bKUwNc&pYx1ro8!JGN*@Q=}B*M0;=T83|8=N((j+~f}E zZjO^{a#i8BhtjmWfVV}^CPWPgpp?Eq>Q3e05YX!TQyKRs<}7#2{$v z+d!f0&qPjMe7wrrQRcj*b$G05sF3t0OHBq`zAzvS$?u`p8UJhD;cY``=Vd?)N+l=0 zU99@=J(&UX4(y@u(Vv!jFH8V<8QX*_sUqpUPW1R0VZ{W>)Yva?c@GU}xD*r@^bDo9 z4KEP5O_~&l5FkalUgtbvsy4UJLr>&9PAlI`U$hJ(In_Qq8hS#oK!5r6V|4O*uD%~_ zNe7JP+dw#z@&||iM`oyxrnhx;yaFA`PQHs-eUOLhL>XV~pU-_d(l~veLC>B9?gJUz z-+zOO+W&;SnS&7jZs-*#)FVT*^C2eRtO8Qv$k+8#X!7B`x5*H&Z+2!P8`5a~>>~rp;k%%wS`dY+twi_?Jf~zw+nwRTU!NHq?0yKEW1%X=3LZ@ zCbY*65!6)rlh_EO(x5e-S1GU2F5Loi4}Z$22SJskS(mAo00K;Y z^hz4O79M=yiTN)5()nHZJyA-FPkuz})2%cGE$Kf7+bp5}?iuAnG`Z!#M_Bk^h$evm zEI7(0{{-8YRgWjoqXk0W?;zoBm;j*h_AT!r>K`qdTQO~5E}Kb6Vc1_popsbkJmith zbKwI^GTONZNo8I>2;_sWHx$!(X~#Z9R%8XZvfCgw zMRB5>iWz=9xw7@0hQ2iAorW?ccS_Xv&MYjJPpQ(vDF)k5|5$aGO+9DAyotHlW$He_ zEX8O*7QVZ=%kChW_b%-7M|Z=Icb*b8*BpImQ3T~XusP>ncrmj2zgEE*a^~t*Jd(CS z(3ZD(3#I@{q3>3ry=^gSsalmu$YTioru?-Mnv!LuhMs@7A(W(aIIO~3LRTJWcpzCI zl?L)V;AH}w?Rfe9hI2y~z1Q$cvfAfJ3w_iuEwuQ<2INY(EMC{J2F=FYe>1c#ZK#RT zu1Va@ZbBjoIDx)P>-wdwn9hwB@ZlAX2m{SGwhC|X8K#U;Y^%q5@}AHSx` zFX1u&mA~f`K-pY+@;i_NQa$jGL8C-~IZ|P+g5skYEYxEHKn`-1hdi~gS-3sjbqri- zeUCL1D15FrCgWtvR`xCG5{K{ZO>0&(^xSZ~ z;ci=%NbC`{gaO+biEZbS&V9*qZOyGrDph#R5I_hbrfx{rHj|wwl3WV2g?m_)09?4Z zZ2s67tG*9wBRY1&6#QJ8<(M5!K=1!@yx~or9Nrn3)OAc%A0KVPaZy=*{qSIBE@a>Q z<+sO^*E#$7dX!E6xg)#^2+lNi`B7!EI-F0(PBh%A0?a44hnw_Ck*x!X)0JNBgI_>7 z`jKZ+aeGKBDZ%YbmxMtDBj|UD-bl@DCt4J)>#cfn3)5cXl_8YS_M)$rzF9z9|Isj3 zWNJ{4>Dm4h2kK|5MQW-D)sC&jgwmL4z=riTy6fZyDDSHmU+UYT$dF@o`5FR{&v5{iKA z7Vatz)qT?d_B2+x?5c8X)46oT`U|Z)Tt`(}zwP_7Ht2l)mD($4^0tr`1zszqi<7N| zZWv}d4R2vpZfFL7Kpb^|&)QPM^#|aiOlcTMKW+xMK>VX8dNpLyj!6xJ=^4Jb_w5k0 zJ3reuA+@Bav}nkJviaqu3kDa?FG8K#VeHCL{XZR#@?QL!9ej3~M)v=70@Zn+pvIC3 zc6zt4^hiA@X5`E3@uhnd(2!I`azqnN{bbL2>eCY6%L5R^nfoM)f3rF?+>J9FNuyDJ zKrBfTI9OJ|u)y@eEBerp?Nta(;djz*_rz$#I&r$bsNO-;8p9RZm`XEJoWL1E=f6NL?|S}#-8(|$r!&3Rrn-ujc0j<7V;eXI(vfb|(|Aki z;>oon>>e@$26JKX`~4d*ICi^rYoj=HXKJ`uIXXxrL>`I^q)*cDmQoROs0t}L@phL5 z!foiYnm60g?W1wy3(_$r=`s>!%h2X;5p(yhe6a?B_l=7YD*^rI&uMrd{H3bNesFSi z3%a!g#0j1|f^f?7Dx~8IgILQ)!~(cgvzT_e9Zk&$&$PF_1SYfShM5RP8zNJLAdDNk zcA^TM=!3p>-FdM62<)i~mBc{U`*sK)Ax}s;3Pv77)K-dUnkY@wkO~zN-f&iY+e)TerGTQ4eD| zTe6W$4H zc;h302eK{jOFFC`DsW0LAX4assh0cs05G8YKQM?U@-Rx~Pw03gH?_FZ;QU&Eyzc83`4aMO})l9GTNS{8Kewu#|(?>bwO)xAzEl z&=s>Ddn=;*Yj&bh^W>_OP`GFKHoMA2ifS+D6@F6i-uh_=LsAMDAiwF2&BCHizoLwe z*4BJ#6mO#2eXQ%$fL~%cj%mn_7iRCK3($6340b5Jv<*u?ObO*=hrehp;a`U5kIa3o zh;G~u2>sLo#9!>#$jE--iJ|8U!oySs#tzda?EiSCs3aA9E+ZuO(NiJS#mImExYN}m_y?UYC_S{1ZR4d{=hA~65+C8%_5zq)oh9SK4)Gi(#b z;aCbL$}_s;2cy5=piHh0aDo+&pGn5g4u}kOQty}4B)R)BVEVpqTC=2v{xwBK1uwgicpRx z)&iy%6W7&vwE65BLn>}`Ut(DqMS4gG@4lJy&U|mWy#xALF&iD$HTI|YASN;+E`cFD z<3E$K>YRSl*YZD^pQb!wzeSHD2@NKX3P+v#OY1Qp295~l-PsWssXlO>3aUE{X(Btj)UwBktqg4 zQ1rP^{7Hgu}+0 ztfNHOTmIKY$*H%x#yRUkk93G+^==$x(DR=aL2el28Io*vaST42&_y6UIm(ku zBeXS+&2^l^D3QBt98!JR$ZoG7Ux*+Z4Kg$1MdT-3`;sjiMvn5w>!t%BWoUqH_IJ6Ow-F32FpX z3{W0CAHH9@z6WJ5U@-i(81C4P?b9P&#_A8!KS@~d$}JT@OKeZuA;p8bX~$N747E#- zbj?XhmG&k{GUREWSpiUHMducosxo)HvF>40{k?skiw31$`4@}U^JN?KR0yqYh zf_G01M0#q+!*6Ts3ITh|VdOMz2nzRin)tD(%s7FmI6WR-LPUOy*%vSXIHNRy?IlS} z9eaDC3ap=ECftvN4kP6#4$b8BorG}iI|+Uamh;H7gMFt0M+tM>y-e49hP|jyD@QMM zMWTPA2Y}_I2K0wSD}79MhF~dkwI>(r5(B28yo&yG{aXDRQS0%e40*am116!yHW$*x zJdAApV*O>C-j>`&wQ@C9@2RUAz(cE4rcqn+&dbpT<2yc4imG$#_hui&pT1~u2SLS? z6wpOOl>OxUnkKJ+ZztN@P~sFdg?6MTseD5a*9)d5;n$C=LY1P45*4tP(VC8V#FK)N z9@1txTi|kw(@)<@4Df*$UVFlvIB82mrK>%>yTZ2A`H>a;@h4RMoE{G zMKE^#kS)9+X6P1zeh77SqRR{YKBpaz^$#;74VD+?JrwU?8nz54Mw^hOa@T1L=VxEU zMl|3w>((MKX}Y#n74#2WEyj~U#j;j0{l*nv?%AVYMr4HkP;MiQ^_`XxIp?Cr zf-I3mO6YX)RGo&s7JIOT$;k3r z)te)jh^%Ks`Y6|fO

d*f!O7NxZQeYt++_gcmYtaQV=nHNg5EtF8r5z_88Pn^4yoW3v(Tp57mHF8Tqf z{Y2_ck?KADIF)PnOjsnzk@@S>r@X+8wN$-|S^FJDzJ&_${*5rU#3}bUUUy)&d@^ zFvR@SV!lpPhB`ok6NCk^T%R65S5@(4RXcxFp^{T#_Q3?OvdVkm5%Wdavq#6<*ud^Y zzoz8&^+>U?LyK;*zmCX7>RiaHb)Kx2#^`#OBnzxoq2Ez`9}Pq2Jn%&4Ea;NPHD0Wl zztQ!7kSbzuNR>W`&7*N3%I z|I!&E+K1Iqug1rJK5T$`X(t08P>E%#1MqRT5^JHJijVNhEI@VqDQ{MpwE=-zBPypd zYmd)=I%2}A%-Xql!0bQ}MLpT25^wFx*7WpB0RxXfe}PNek9~(E^{I76&nTpTB#GOd z#h$?)6cS=gQl+v;wGEO9k5Gxl4}&DJgJ4rQTcAqrNP#gIOkGBd&6jk~Aa*x4g(Z-v z|BGewLN_?A! zWvEXl8+dJh7KAbL+(2F6(*YN={aJ7mh$j(I)LvjRy)#LX0a6;bM4Vidqz_9hoN)q8 za4xC~B35q?<<6h^XYTk?u1;t+F*WJ()`DzK_;yatTOk$XJDANOZp4bT21KCQ6LWNO z?lE}cJ13@G*Dk2P46*c*SdEclW72KOl2W)qM%}20Bo7;@^!3r?RsrabI9(ba6~L1G zk>7^1*>R`LjBJTpWRCAdj_-8_zB7>ZQ74TwaNi)dAlT^2+S#b= zozsd$CcQkD4-N595X<)N(-x_iuf?2y>l5B3m_?~SZ3Dg!WGC2^URe!$*M33RBd3 zkgW=1)qE?`oo)zuDMvg%zYRIkok5O7w30KZcPJ_`o2Arx+6tQ*j5X?b{HcZXq?;5? zdQuJz)LiTxCl42`H5Y+TiN;x?V0 zS!5u$b@4uZvk)dM7^-8b2W`Bw^F)f=nd^oUBwVJ+I4d68%(N3(YFX_x7&RAt1djJ{ zsHDBD~XeJ9cM9#Fzb^cH#qEl+bM9|tCpf<7ODx_tgWN*Es+ zj)}WfAHFf1eb(k+U6Ju7JQ-UvjwbR}p+TM(pD$CtElKT4sZKI=PDk2w@o5QXp;cK# zwOe$O;28|F8CaI>gSCS$Z=skGtw%Pak#RFJX8tNN{tbH-WHi2;F|sB0xdsb`pC&kx zUr94JS{XEck}UqEEWW*^tcNmL>oK=L@v3s;EKIch9L3n*eDx=GIe;j*AT`D-7={+j z^LX51sm6x8Y`8YUiC?b9!sG65!B!PqLm$JWV~zon;nSv^n?~S{GHhCMkBMW6$EKh_ zZ2oX$f+bHJj&!vwJal#3J7aS$q98&{-c-vNEelZ(NA9`Etxm$nHZ7~+b)z#V+y|=- zY<(imq-9kj{%j`8rCl9CXxNtQUbMW6M9X1l01c&n1Y;exAgei3h^k{cBaVr2aA~^f z5A=Eq^yUdrHoSkLgaoK}7R@-BU~l4gOF55VHKS&Cm-0uf;pYZHSfJ7+f|a*x^YP!* zhk$ey(7l`CusQ;Iz{fefe08Q%h2-#V)mbg|IA{Y|)mgjDZ?mzpchl@dDrN4mZQ_j> z+AJ`=`Cd*}q8WzzjOTWnyi8E`B*?bPHHNEJ~1UC3 z3Wyy4#z3pt0iDostHb4g1ci3K0%@x`qfD7&F??xl7Mpn%XcM#aqE$i@(?B00S$ePN zn? zh#km!`m~xhr&H@NZ9rfjoCV+|ac2+>-IwBd6RKADNPT*Zp)+VvRbJ|*I|T~ZC@<}M91@8)v!`R zKb3mE>kUJA2zXUqIOTKRZ$m28ThaDSu^h$lo2Gw zRl3`z5qcgG#UjI@O;EHr3P|^a1CD7&sYbFNrAH63Y}7}wK>tq2gme5eB`0yCE`WFk zD|XPTf3KIu|ESoZUgp#KARfF02ptLDU%-p;D>2W*yh#-Io(@+U7IRBV!JR~5!qr(I z6<_d+piDC24r&BtR$xdL1tH%$nbfu4xO7^d}z zgybf)!;nfhOai@+Rxd%)9U@Wr5iLl?dh(5`u4QzJs7oBUUFc|Mv=HTu~J^7xea(n5W*FDrDfzO4e4bs%79` zH)7GMIZOEYM$lZpt%-fKMy#tUESq;~%z_*HLA@_J1ZJxNhR5L5Vnz|m6N{!d_#Fvb zkBfwAlpqyT_d0No(3mNjBhXNZhI@_@iZPJ_MSi|9n^rz#47|xhOb7C_?k)WJ=q9YP zdTb2?pWcLps#9wizU<=SJG5C6%4Z)PE{0>C>jqLRaS|E`Nm=7Ac9rlQ1`MiZ3R8{k zLhlr&8q>fXAf0%e1S1859&Rbn5<=#a0z&3NbvwOySX1U7F%|gROk-cbga&4%9S{X> zzbXuBJe$&@w{KGxq}D|m__(IDXA}{K71=jU*)r$byk#@iFCr1!5;~(ArzTFBDsSQ6 z{_GK|PZwdY57#Z4v2UGU@S$<6s>;uU&x&I$Yh0{|=M+kp%s)&egS90kF~Jnav4hS( z@XgIxRp(RuLUWeTX%@8iGDSZ)L`8q8ilXv53A*m-J#>`OkFFs&{f1A6YY5{V>fnRo z*@(=27zl!VR#jW6=*heDJP$p6fSp zgayor^IXGkNF;zzyfQ%`@qkjUz&3XbxkM7H1g z8DH0m9ZYVtj%a+%Oj8a>QhZtr(q6EnJc!j2Dr2Zj80}9Mc9*vqO)5pIB0^D0>!;sg zEgZxX|81mE0bXc73ZR=y~#t0P^88RpAb8<4n-hf&# zUGL%`ki_g+vU7%#jdC-Q+CIy%Yw1W~5yR%U*?jVLo7 zIczfouJilxZ*;7UT8%mEp^hDJe#+M;vkmGeb<=pS_AEv?pXI(K_y8|HI)(ME zw$%@cN`I_J)1l^WMBo5a1!)+FMGK5#{NT1F1-jEbUzkpGgpev4!DBkIpQ8gna$=6r zRx84BC~VP;K_!Qp5D4hW2#-Km?D(&B<*Syr)9}`vSTA35W#pm>!kX(|Wth))Vg)Yi z|Hl4QMrZa-(wA6{n4`rC2Ua&-20tM;F#N{Lg93Ifu# zsWhCcL{v7oq*z-j_6qbt1F8(%c0aHS;|wE%A{KWH$ZE%ct|?W^=x%X4{BL^hhlAHu|t#$ zdZ5%dC{@%~Zs8ECz|z|bG09}V878Bp@(@DN4PbDFzBm7f{X~Z{)iiHCk*Xm}u2O{_ zAlkbkymAEMwoP~FWpgXiDeME2_d4ihW4bd%75akD?ao3}suz4?cNV4!^W}48EaBKBwAwh=Hp(FD9n4V3Cbww%QzGZ>`^vubr<8+HOC%X&K zro$+db2FnNU3dDYJgmNZvS8f@Ye&e3CUsc+>Y!1UmyK_Uc$+Y?{ukcOgxPNP!-Sz= zrcco?q`+1~Uj7N7sSki4vwE`j)&F@$+Zv`{20f({1UN&0w=^`uailM*0Clk^>!`kk zq1FBa#zriBEX3CH4dlgT@45l) zL8!(m$F8}-g;sAiDX1$YB$OnyN0_Fz?mRlO8Vqzy!QOmyA6D~&Nk||jhN>#tPla%W z3(?m0zc3wI1KEyki^i^Yw7yy;(fVc;p;ZM5r8}1w_hG3Gl7Q}^V#rV{dd(4*q7jt{ zqkX7ldnp4>FW|Sw6|%k`ix0XCc#hbgp^Ab12c@yE#NYO1As@U(>U)~-JEHAP7`R6^ zVVBz8gf~CRCTR1i2`i9LrU|3_u@v7EE;gN+e(3G3YKg3GZ^}Vbv*zf6 z94-2@uBkaluB_oGo=n|*>u!7KvM3N1yU3dGl zXy*o>BFYh?kyM(_wC|t}D^bVqC6onG`@sRmoG;r2@IC`sR_3x`DI~{3NczK+n0COk zC~IE4moze;Njbm{Ie@R|iig@ji7}8Rt ze0PCiHYJ0$Sc(h>B}*~wAVJ{2P@x^i=1U}h9DQxY5qof^fJG9)`b!AG?~!CjFqID; z!u%=@t7>rSB`<;SEJS#?Uw5)aoR%@B-yC8N4`Jc;_aO!=32|FlYH?l}kV_9tt0@5l znaHWWe_qM@xX;I|YQ6O&zseMX^AaqL=1~etMT%0ZMJYUr$HFs1uKgbssVD(OZY-vX zx?3y41lO*3D%Q=evnms9Uln*)v^N+ZCFzy_Kk2nZdO}$MxcpyiZg5*7^zO=KEkEwW`xNE}${XtY9PMtzSu`i!0N+p0g6UZPZWzgeD-*lHB^mCT z2Z>b_G8BHoI=W+hEVelKn5Ll`9;L?y{r7+Ac_%$^&&7vc&%#4K{tLk2^TAiBIi&an z3XcmNkzv5paHg({k6+H=!xJBW>X}x3zgW*J8SrrkA59E^))`5?46M7_1d+elz@pqg zrWG!>S7hC949s8s+Y@WuKjDMwR+=L{?+H6CYX9NnZ?-cvJ>!?i&a+59!c2t5W3iP|q_nSVyf62@WdI)(%qQES*6T z$M;WB2_JniJ&gN&#$448u&xOFjD6w(_7H0W%XF*_=6}W_egEeSJN}wE+Vh|#+42`S zr}5LDv9Dc??4CEyO2%Q+U>&-3?l{)V`D1QE7^88&3G~Aei?|l?BOIXOXr&3VhmMC% zx74KPEygqEQwh?DZZttn@~m+bqpQU%7V0ru7&{{>$SI949uGSQw0Vt9r1U*qgKe5aTJ;vy|lJb{S6AF0FPQhRw*DN+z{k)DFACZMpSIb#T)kRE$X{?zlsu91P z$%4Gxn%j%b0<$lg#u}&=HQ;P23vgEW*3X$gOckFZ<;^q}6x|rcn1nseDPr;mZEnPt z!v6fipKW+tN5{7PoJCe%JckYg1igHroSRSK*@S7Zhd353Dso9#Y$Xuts%EQeSme8P zRVZDTQ%POrQI~%=WNpxAbyElWYjXcI7QSKb_60IUnG~*=&XL z3O+Z7HTLS62>Z`5;>hTQ={moZ0|xx(hMudZ<5=fseAJ!JVlqz;sesXkBRLF4ReJe# z&KbAN#L(V5ajY_vE}R)%6K*;Tqnk)X+#AftWvm9biWJY^Xr{K_V)92xQV1ZrsnBte z)I=UPrvP>?yu7n=KD(-xjPyBAF#IsmBh(B29>LiRSUdyQ{xeuh^%g8hR?c84!DH$I z9OhJLT7)6KMnlzmJ>N?A{zlgeH1f+Z=H)2r+U{s-p68Rhc1F2MqxI5_tZrQ2MeTMCt5>IqcN=;bZzvZ$Q;T~AwV{iz%5t$JQlw5s96(xAplP+3*p zkH{#1+UCrCrnBHg?G?S#%zo%oqpKO8_G#ysU`e)#)_OZjUE#&z6WOGpVBr<0NV6~* z9fUcHZ8CD1C?}%`b@F4uqVW-l0A1vcKAbMDKSO6B#n1F(OX>tDFrc{UGCwhk#k(5o zKDwmm6^v}bkY1O75R${t@1|}8DDPygHxA)RTb*|FM2Iw(u&Nk{|CP8}t;_A^Uf9~l z*?jCz!BTsml)`1zWyv0ua6Dq(CC*4(10Ic7JR5r5x&OgfayDxfxZoo2Yzz&kD2;wH z@q_CvrffcOHfz~44ylBXzgThOT$H@lLBc5L% ztcow_xpy9`u0H-Zbj&;`5%q6KCE|`AO2pPYR>k+spRg>bnWIer8AyrP^ydivTONyz zG)AcZC5*n(4gvvT*Wv*J6uAtY_jDfBPZKt-(qGl{mUA#IoWzo0#vIm3oq&(4bJ&@H zC0K5d@@j^oeStB7F)iTx=CUeHzz^q4EEZJ zu>vh;5Xl(p>WjiWcRuq|dp{V#^XIers&iN*%*Xz%7b3zJFkiJ3n6>c&7Uj}z7SxfE z3!u+j$9ieb0!$}A;^V*q_MOY?DM-s)$ZA&Dg9!(Boqm0)=gYrj!_~cm+<3W#EMDCd zF>M#JSeM@?%e=MKKZ7MUEo7esGz}!BrqCm$=~E~*<%HT1iz%?#BJ9(b3*~i}vEW{_ zvgPs}6sKcmh`m7=(?cK>>3g_s0#B<-GGU=uwV`jS<3bBf)~Ps!x`wP!Zc;%ICv$C4 z%eQ|*4pS|kRS~r$y@D42f>*khOH|acmK))vYFV6WujM+}vF&2mk`(&8@uiEwm)~K1 zb9XUISGyzT1I}VqK4E+ghr040Le4@!E)9Za2Zxr^R^!HlmY`S-XiK8lOg}e%bqR{i zt0IdH)7p#uiQb7_3VV&`!2Od_X@6_tpGleFV)v`Z55)K0r* zQ>5|(^jf2yRm-s8uSvoYOgs}rgee-V2%N`B6$QDbVqH@SeWi-FVzXoF`>>fyVvnd< z3Y+UbWw6O)rD&Wn*^bRr*m41z8eZO?+3Vf|P3y`sHZr<(p;bMCV8as%2#J-LSn>s8 zQ%08y=bYDYo&akqh`#3a`Pk)bjVhon5BQ2T@;X-&YSTok+SHZz{R({kNr9fv`U;%i z9v_>&f~9D`j{E}tWAL6SKx1q|s*G~9U8H! zNaYCkv#0>=j(~|1$rQvYYyz*zalC|vHE%bM`Ik>2&*PrT%@O>|uc0mh$BSRH71&s_vf(aa@TR}fCbf~IZVs%tYGEK zHx$|1p3?KbRT?^f#RXFD zN^Pvi2|Gi_pM^ejj_wM9Q*~4VGShX~JC*f83f1;_{QGJ<0Vt(vI~!0^o9Vc{w)1CD z+u!15QhYz?b1<7atmlLC8Ec6T+9Z>T*)^${RTf!}B8Bv@51(M7C5Kp~x_vKmyo9D_ z(X0lL1Nk^YoW_66XCc9^0!c}1=w$!-6EdFnK7^)QX%+KRUYr(MSQ{a!bF_kstnE`I zg#2;TOgn@n5<<&MRtNzL2!gX&^aF&ufRN`3Ep8Qy2yRrma6MVLR!^L=Q}yb|(|Z15 z6{`_^8y7AeYPq5jc>eBctwntvT+n$nt2!e4fL*E59R#Uu{C}93*2wBWt1L5ltq>`4 z@`^waV*CX%jyRs&@erq1bt&QW;e+M08fsDyVPruYtwQHM45%QwVReV(~b@=t8MM3k?o*u zwJ{5AtLgu!i!bh%OaP-mi+P*Ww#Hq;B>D~1t@@zT;cu{`W!ekv=UWKGnAW`Zw@^(c zA!72kENn=xy%HILd4bje^ZTJP5Jk=C?IKkzf%EKEcATT3M3Jhsw5Qmz0Wgck6TkKy zAo^ImmJL2!<%hFWsKjfFzvfipg8NB{?z%l<0`tm!N?@u4hmwv~pbuX7j2eqEg zuocIhjRn78a|6TE{U9_90B;50SPs%j&#e(6<2B?!#%X0T203EEeb(Wmbw)ZLzK(TN z4I9LFtz!||m%{~sdoYy-fYtbiJ$P$9+C8!nU*7E!8Tf{HONi^fx?D{8sqTddK5(tY z^Q#SvjyAe>xs6>jV_3)Ozo)w=TTYw%pl8XFJGPIg0juM^WO{mTMxSlmvugAyM z%_D=j{|4so8@LmbOB8CbZLsas^FyHn7prbU0o}m#zLxFCFuWwgi|yE7-N;6Ve|1{! z9pxhpXJwQvuq4}1WHWDMHPx%J^gZ|4q^cqDVw718-?Y&;alQitVYGEn&ppOXV%)Ha z)oIfdaBSCNs8-lNP>l5ejw*mn8DfMTA{=p`xwK_m$-0k=W zZfrJ18jd0nf(LW_mSR*Mwwcw4*+e&AtWKoUz>Fz*@e>i1k{8iagzBb<46#imqc+Ds zK5;V(*IeHUHpxCZ$nL0~&fR$Gv?jG15SgtYRUZqGn{gimAS3h?sypExWr%e}2)zGv z4@9Ep7VK!ZMO&k{u!NWb2c$F-LaIcHNu;Vuq+BFY`-T9i{DIZOGdH7=?;s^xjZKDP zozYvDE1Xe}0k2{hd;z@3PdD902jgK&8xltPk}jQp`ACs}7w)J~ej1)4e|39)I_c#} zTUk`h-76*SuME^c(vFBi`-3rv(f&}8A=X(A>D?b$u@Bt1`Tf}QyIWbq7$*m?V^IcR zA)E>9MA4YKnberP*uiq32im~uJpK=`k|5qY@iLia<|y=qv`T$MpAJ^3fBax&9KNMo zNKiyJu2|VDbPbnC1CLEb6e_MN+q3RNv`098%|J=?#=D-R;WL{xY`0Fxpzbgph6_0; zQ<`1Yh$vFKpp$tPiii}ri-RXQ9U?AUBU0sYP@d=S=ST4Qs{(y9=bWXUA?I7iU9`9| zMF=eiCMa|fg;Ma+OyFJ^+c_of7OB+Pt0DG)-*|aqT)M+Q8z4IT$uRAg5C;r1>6cIiYWHyHrmOGWs-!W5aJ7W zval2r7$CJ<8qRxMo1g%pxPzh+yQY=H_uKw5t|mGZXiucBpLTQ!y7fJnFW$vk)`^E0 zBNI1JDB|^CfkFkKfOi^x6QS6A@z3*H{Np2cvCzyPMST*7C5R;)rdo0E#rGI%TziVM zXx8k0FAk;oaOY_nVy*#aP&4?@-NuJQF_TI@BwJ}gRzc^D?m~*o7zp<*@$l(CNW-oqoJR&4ZtIcj??cW{Mz}BKKS9bL;aNR zDD5@cX^FV?&LkMsFwReboU%k1(I87i9)3&1m>1X9PgyT=&_o)M_YRDC`#I+Yw@B{l%zqFTNb?$It7>`l%ZrK59)Wt9xM+ zT5W8uHO+59O{};YDiYkMdkTZ5$#}KQT#Z)!SXKuf!2D1^X{U97^SVJcXk)Kbm?&pCd`}pUnhgg-$ zZ4qU!Qhe~c0|Gx%C!?OW0|T3=JFU|5X#)e9dMY%WRRaUVtMtL7N;qGLBb-xKmIlDX z5;D?MEA;$c=Ze03W%ZB*pB0qfVtU?;@{dMR=Oe6>?@AF2LZZEXzU2r@cH8&0h~oL{ zeWJ?a8@DME2Nv*qEe)E=LlGue_nX?zcln^7m?mf#dQWsh&ttR(Nr#Vo^vE9EhoAEk zZV?t!CtB@+tgnHZx)0-jU1S03itF^ec#KzY;$v_kwW}>);|c4p^tLCSv5yS#2b#j9 z1)PS5XldyI_p34xCIVTTaMIeuDfizuFhw4!*6CJDfa zi>e7OvVt2%i7;BL@s*x0DPW;N)0+??mgNoRC$F)FFA0+wSKQsL#XR9Isx#`7a9 z_E2wLqUSFoEAA`z7Y9W-KNMb(1)s$?Ff7$*S=HhbEV%7YhbXxKqT1FDOTG(PAAs}@^n4PY5t%a`$RiDeR2OaBqVd6UA3d2{>! zWwG65m+t4TqFuXBz%F3GH+p`ZKE6iGs}qbh%|Jl_izG8sU(wf|RtmyZ8RRYD;4E;M zw3tYkfnVACsV8CY(`7Nvmrt_BO#%>)f?;T&=_Z!-RPNITg!`jKRPF(Ot)%ak@VwAD zqcV1q{{$sBHS`LunL#~BFQKH1k2`S8d%Limi*wO6YZ===IPGROFJ<4LY2-hOns%o?)z}*eHq1^JwyPwRWD>rlO)wU1XL24e&wo zzlsm2PUw!WN9g`NpU}0{=h95pxBP2seN%<-dts_BGUw0N^U$*_3fno`fKm74irv(n zh;v>L=f@8wR}AsIIgeNeQ&*q5I99rU7CX85h_b;?Z!O_x&y(=m4@Dv&bEOU;lWNUs zY!^8Fa7GGx-*hYWFDQs=!G-cIxN1NN+$mq_BUXn6Y3P?g!c-wdT^=8yrV61R4?vNk zIu^~jxtL=UYxw)u+yns#4#55eEsEnLL{G$a-IP`V9FM*=ggfWQzIGq6)ejh|YZ8vk+* zVevP9F{rbSgj4~QkIsP&-I0(XHTxslu9iCXv`re9vqaQ{LQ^1+@6*;cd3-{Ro>oAU zhohKjAt!^96gXx>6ft&Do}IA=RhRhnszvx+Kmss3-^;7EdTE}XSGj;K`O0rBeD1l5 zTL0EaJs1XwE!0VHGwwVi)3DxNG3r;d_5ADJUO_c(&qf{bL=mfPRT9}&iOdB^B3iVr z3BLL70*h(lfiFDOjCefNj9+0monmZ>ix=te2lCo9ve{o2x~P$XN968^@nngZyA+Jj zBu>M|L1+-XU6BMO8s+UwzP*!V!Wf`MgQ}XpweF!J?_HzhS7SSOFd-h2eQjbrWr<6W zY*Zp-7bF`&_ZB5`QNljtdBP>uPP6?L#I5auByMZKE7Dv&|LPKp(iFpRptLCVhse8k ziM6OS9U>iW@632^o?gH$nzDF^S3nd4E0K73gfoJoX1InoOZ1QpMq5F@nKbX<{S*8w%j-T9v+_^TG``IOsUA)M{^@>TByYC^#a8|m*6xKLF0!t`qd z0qAK5z^!p&!eVgWxKQ<2e0;slr&`4n8U%H5o-tF;!|Qnj#?POLV%Y^g z#Pw(HOL6Hc;AbMmPCNNQUiz~#-JQgAFwTf0^RFwih87SR(+|1|6T!X0)|d!xmMKV5 z#-Z0fNtM0!5K@wQt<5W(1m*88XysW4qL`rg01Et8&u~Cb@GiU{#JPWU4(^Tz*OtvcgQ5Gk@ z7>7_sF~=it6(jIo|B7Mi$q>n6dGy9JDjQOVQ+tEH6yuk;UG7JmDs5;PrDDl}eJO@L1d}7U!Ey*h)iu zn89OqC_2OE|JSmL-wC7;!a5YP!QuIxQkto<^}PA7OzS&p>ED**yv$z7d7BAG(^q+a zbKlM>k(8m5#{fTXq?ta*``c24$F(e<yF%avx+nj zbjRmZ?E_P6DB-#pAzS6v|J-LxU^BlyNGQR3J7l*F???gQg=t+C2fPn|+_r)GF`SEM zgfyt7nuakmv~6^~NB6Gr@B@%2sALdo9By)gt2^S!CCGt?;{~H!h|wJnok(+_~znhtDHVa-2)%3eq*t{ zH3Sa5mWP9evbmk5_>QtG^-;))mp&kb3G-P>-ff1n z>f4jBZulRI4_+||6;3O_B??jRah#$RePGedMS9fltW%{%NGIq!0|i?EwyAEcFnDI#&QrRasaRe%anG1u&A2x)^Z2@32tMA ztlepexPdB5`j#iONQhBQ(DRHI32o^A?E8Hh`e>-sunG2zaGK77;W{D=+Yp)e*}iHY zu0*?Fwp5~b0g;E1Km^C&D2rVW-v0rs9q5OQ)U_M^2xRr~Hjq630XS$i1kU9LtWM~s zR+$wevTYh?%VtHChe6K>Xn|<-TBN;?aama@UAXi+ z2NcADiUk{>UTr7*ixKhW*sn=~poi>+FRG3jx- zRNuhu4GXFEY`CZhgo>yuCQ$)fgkPJDl8eXf@(!%F1}z|U85m#N(IZqTLN3j?t`GKH z??Ym1ida1P4sP_Fn8zoy=%Ne#VnTOMdDY8=h-*(%=bgVh@7~nwV_)$iln?WX z=^gx9ho|VIp)_ZJmQhQNSTj7A3j0@_$m@p@<^YnoE?c8JEUeS;v*IwyfGfw{8%69c?~_c z(g?He&k?Z0OG~;0h99E79F&*rLMV5DZWF*yeC-xg_ZVolUR(45e9B(AtxWowbswP) z&3vL)8_z`@3r)e`Fp+2=e$&{26b9DVO|9>aWB45#Wz zI|Bz%Jnkv_PpN`R>lo;^boaORpYk!Hp7&JWDD?R-DdH7#4n#b}mn9`49U)#|V3&@{ z_|!%hn-&Czw>^a3I3|c&rp~`ed;G8^$-Tjbs^|iWy@K(t?f8L~8S74`by93#O4;@$ z>U;6j9j5wG4G(yxS6$xY)1T=hbnnV}`8S^vk^l_}U%LzQ?;oOGIs8oDK-oPsk3V{* z4|7{T6nU{ZI7sI|4=%FKDu}0H=gH6YSG@!Lti81FFb5HD);9_HB9M#rxlv2j{K)owZYfv>2WL9!$#pCL0rTrfR$8z~S~|LO2#amW;q( zOJ!kF^v*M(^9REKTv({C08t#r6uIz2sJ^ zeK07G`?|8)jjkXF+1~R9XMwlw#@4oHrUw@|Q34eGbSK&*IYMtmc2wz$UF&=6$CW{!pSk%*E%;=92 zR2e2$7Y@ILY9qd@G7DBN^vmOCDzolNF&rBgs&$p2aGYJJCI;5*=h*IIPSOW{^^4W8 zz}tPx`JL~Z#|IXx!PWnQAA#=a&R;23>qafXH!OEOS?=3-Vdp^6S~$^E;#57naJ?~N z9w}C9D!FhNsxb``Y@YBkfl#Jz&9OcCe~U72Y;wDpoL zaIEuUv5|8TguslvNx&~;Im5sOhh8j0nUa;qzg^LS)#!r|RNPPBuvEP~-oh)JI z9gkqQ?5Eg4^!6Q(dP+A09OKLCco-W*B50{E9=_yH?|8I;wOr_i{_guVJ1DQiQFzxw z??y6s+%bK4M89s%a;;++T(^lPAn~ksbfccA)2QM9CIIEfwZPZDFVsS-9H(5Pgx$`7 zc6k2PmKm-Y*xGuvWjOt9e5ZPF{UPwO^`?;{*d75Am8hd7maLJf=Mm9uYK4-gaZR9U;w=(Am=eH_+|Jj+B0IRdIBD@a>wS9BTR z+BJ_qThV2Qdl&FsAy&>~ro&yq%DFlEJyc>g20UBG9(Z4Vbks5>vkU{lk%6p9)CYf) zI5o{aw1}sb71RFr9`mJcF@cH^nxq=NZ=O&a_F{;rdsA(zmiGdjTi#Dl$6)TjVGVMP zr1@GWUC_x})*H1%?V4fA3^>Y?I@OJBSwYO$3Svfp#$CJz`$zl1MJ030WlGXtovE5Q zhhLi-NRvy>dI!69*6ex(yzR#v{KSE=Hs4;(zWKrIXh5aEi2bxq#J&K(#GYq{u-a}t z?xH;08k4N!i$l=qap{!DzYbwFL;mPUnIsletqo|2x&kJ1@{)Im@<~TnR48i`HU{Bf za=tJ*tc92hk~EXcLV!+xdUpwPlL6`=KpX{VsRg*+0S!qgo1n~0MfH2xJ3u*$vi9!a z@BrTCE$_WASkihaDmv>wzA{NMRg-w+aYMWyROQ)c4QHgxY{%(Fl;YA zkm8m|P%ms6zh5$9!DwwUkxPs^nF zhM|ce^YweKRp5aLi93f1>8H?CW6?vj>%yFAI}UxAbtP2q&)SDWja2>PI~kqEqILnwZ*U~3EJ7Iq z$J%?|L3O@QMuA3;GYNm~I-3b1-c0h0LlcS6@2IR%Y~CM)+tk*UTQdvYTqnEiGe>)% zI)yb_(%!*MuIv4Usz)UK0BR)4p~`~A%(j@3_{XD>t9KF}`C#>x5D+k^4dib3JwjbS zOXMdam_F)Y8;WE$b^e{?ev2>B)s}B(V~K6CI|j!?|MCcpoKGQ*lOm9tbtpIEwcMNl zx@;1zPxVd-lcB76-b@SS3p!7oozO8fNwC57HPibM8%uyqNqM|VP1Z3iM+V42fPDJ^ znFuiNzIV4UbK<|7O=b+N7zq`7{SLz+_WFGUb&_U$&Qc=hBR&;t@sD5J?H25sD9tyq zBfKojCIRTS)3S-Hc)T3%qt_w1j%I4jjQx)_Lu?OLlpFfm2u(8koFSPf5^VM8h`+V4 zcN4UnI}Klvb0X|akT0yu)Omtx700uqSZJNrAi-{EgCPK2))FEtqNr`9f|{wcQOJP! zqL)5U;~&;m<3HqA!g98?efrCySd!mjR6S`pj5HJWjMZi6txYsj^=Vk->QLJ~z<18*2n&C8IxY~*;*h~1u z6;jdc1!Y<*l$+YDX23>tRe@o~7=n6Epq+WNx~olH$c^GW zyAEon1E`(exazA0zmF~hnaIMQh<9ahk-S$0dd5{XHu$bN3ZWl=c*i3FowCB_dA#a{ zCK+LkK(_L=+LAQxJ1xd^yMx@k}hM<>GFK zYg>pTuBw5SpcxH;tC5sZ0e@h@%c9uNO;{;OUQ+@PHRX6Mm8N6C;4bOU3~-YR#D!*mWZ93F>jYb zJ5iW8%KGD|c}E=>B4ri6Q=GmVJA4}pgU!*epq-LTQj0s|^s8=i>KIvTWSVtD;R$o@ zXC4+u{Di+gUGs0eci&Na`FP3P(L$WR9es};{hz*5=Rd^T%9WuyAHOOHEWevW1J>_C z1ZWQZSPA(4(8KY&wv+#rT8{pmRLAe;)g8Z2!zAqaAFu-IowD^*b2i5%dGpz$=F&Dk zEB9i#+-JpiRliH0|F8fzpt|=?q4NR{aJ0PfDYNb!41RDijSD^WTy%3L!WK=N}4>tMc^5+RGT3K2Peb_`6 z%99hBca2dZ?gP^m97~jOd3GWT3it~2l=}y&(qj^|hxY?~^9yGu*HS9W_;rGQuPH0U z0oJI30WV8rO_ilJEmD$5iWcnvl%a5}4fn34G=*a!dEJEuHo(#F z2$W(hqLVtbK`&h{D^k1I+C+@yehImsWp6#4scy?!*9=?c4to)aF;il$S`q^jLN1R` zah^UIAe+N6E13;dPO&`xcQRAMF4o5h^!s$QSaSB6TY?YtYyeqJVZ*(f)TIEz)*2zw zk`xx=-IQqlf>sr@ttqTk(tbT?TY*|kmycSKX8y4tAgy@gOpxeNs>CI<=t zKkc@>>Dk($)1M_hpGy6MGx>g#u$g80RLyg1Sl+4*jMZ3$K#rYD9@l|oD$T+$uW$c1l6MS*D+ndlLLIhvOxdjhp>2Osaq(RlhjJiQX%wS zG^!B87YX4J1;J8@_qLE?^6-VbckydcCC~0ml|!&rg>34~yj$E4l5t){92rh7NElV< zs3qyha~bV*wJ&rN!}EAfZzOYdP#!Pt4dZD5ip!z|eaIk<-MKFbLSKAo!g+ow8xeak zkh*QOW`)itdY07rELbT!m+6RNK}vsDrLitOa}fbRQVB@yd}ko{Uh4R(FWMKax>IPyP(l^5;OQcPS-T1e@^!Vir9y7lcCBU8_#^ z-#ryIky!T;!~LIY$b|O#oD%vYz8sUdDuab7Z`6<*4U}1MG;? zZ&Dban}ICw!k1`Ek1k8__WsjP@*egX>4RU)U@0}9%(hnd_o=$aCQhmvk?Algv|WCA zc>IF(RdAw$ukOaa59#5HJbaz*8K4y_85)<{`{wcK-B~xK)CZUQb!Ue|R3C&}=^U;a zyg$oivC41WINO)WYU#sgS}SuW*>56(;)Ryi&Sh6x6!BcynAxnWnEalJd!90~1 ze7)WSvolXUv03|Bp5F5hPm+#ZlOLl$bGZkrqilkgPfw-~cnx0VOenc0Tclj^zzjoA z78Z5L1F>;L3;i}?lJ%o=LHZRTeS0CVX2TKRi$(bu5v7D0ZCs!RC!h7LcU``;7n>Wp zrn<~P_7N%Kb$nSA!Q*Qg3=EUhjyX6m!LW9%sT>PtCCnPCA=C+bRU*f ze_RDI_d=iG<`6RxRzUd>v7)NP8}I?)U4$=7;^kkS+?TcJnM9$ArzexL9}RV`=MG8% zw#Ek4zC!tn%{mn0*YBLOr#EUKQO^Z{u|qxQQ8ka>>x+zAQzegw^n*zafMZ}k)N||5 zR!}{cP^E%;?f~)>iFCl=ioD<0k2Q)qQ&}dm-#SX$8HGb)L%e9L7vDp*ly3ay1VT_JI|ZHWLvW{I+60R>tH3C7AnT!|!13Zh zmZ$VX?qz1PCOl*in({J0?mmd6=|-T|a-5-BfUGh9*f@~y8^r1=hg>j%8pH-FW8mmE znAP>@jntItFnJ5Y?7^tncEhoGFl*)A1?98kuISnxtb|jKgJB{w;7AyPXiHE?N^^0N z3xx4Q(EBel8~DK?>{aC!QV(P!m3eS%%Vxuyzwz84Dvyx2Fq?%bM@?U|LDux>GpCE_ zcTczIa@2D?{XLY0E1luUAIj9oXc79$^-v0pVdvuUJ#$Hf=%Ckt7j;pGvSywqo*As! z%gctc$ev$T687rQ9sEer9E$x|7ZJ{(@Q#)=hYhP;p`Q`Muvl^7se#vt^V}K|{nSvY z^eyM6!Ux{#hqETiDQM>0a5h;P_Qb$@k6>fkdINBpv9l%~Ti+v4RwPXm4_X~GpOU7D z2Q3co8bKk?MzG;Q>F~sCJ#Ex9Rm#P@9X8IVJ~r?vBiZ1v3y(nK7v(54r9$3SfTa-wmq~KqTM|7kOa^~>s%_N^AGNj>m=yP;!>Z|2L@h{ z!}=)8>fu7`9Lx#)32pt8!(!F2<&^A|_lf6X{E{5Ie>`~%L_QbZ7au@mKby!i_;wIU zewh0bB9GiR@D*bq(zWgweq#(oeg_b`T!?(KltfPcheVFYubnt@^6Xp|-u$BQ{tklo z&`u>Sl{@h5Ad>tnA~*hH;9ulI{7v%+{x{Si zGWEh%Dzg5k3yJHCWyCeV%)q;kXZq%4;`7vP@TIvH4gL@Kc7RWQ7Wlgm_r39e-yv!Y zA5;MNyy%4#Fu9nnq&4zE58xG11pajEZ0T#F5BNlOS@D@Xm+e zJ#}m%bMWmTlKdg?LlfwK_H{-iGUU*}yjaK9H>xMz3xQQ12FDh34;CNqD}ZE)dD zI3bBInan!4=4pJkmz3l4VTt6^bRPVOPZh+*-NtFg-J(58oei4@xoj>m%|#%a#(4IN zY@C((x2AH;KQn0{7sHRZ_<##ar?7Nag9h^U)pC5!U)A{RfgkZ{ zi`d*{D)W!5Blx@rIz|k*y{o6DNqKCc9stBog(k;o%o~?y&MeH$S0wYoA~63J%sq49 z!bW1y0rKKh*2{IQ#-~4MPC3%)iU6r^qOtjCwndS2YQkiCMJjR$$Yx!2!PBBjzV{{Y z&eeFo^mjSlqyE-%sWbdY0S9MUm{T{(R8?cX31l2(M<5Gp0AD+e1-oJ}xnmlO2^tOs zq|blf`t$;IQ%!+G`NL@#EmT>02P=#_qllP_M{Sa^d2z=@e3*5y;Az%*1NI&wXthjb zq&aOmQ-|KWOlsz1m83*B81<++9imWyv%$H6P{8+ z@I(g$B3)bFe2Su=T{2pnw4oL4me$p#K+qKhGV7{By`@93dwci_til!RTEcgCmhid( z-IaFQQh)_Z5OC;?cLQ0@n*YPg{U-k;?pj^3Vz+(`Y zt2+S4qgPmLW%UvQPZ#gZDu003zK}(`;%{ytYuIwbMN$Q(k4)EkN?TkugUrPfbS%?~ z-%8^5@dXD1I#I}K<3)yrVDzMrrDPi2I}s~!b*YQbyfHw9b03ds80hnLXJ4PM4;5#b ziypiB6m@}Dnz60V*JU^cg*bF~X=_PK#oeXo0Pb6cC8>oaUBX=-l9Jp&>v$}zi~e}=PK4MgLwp6yCA0vikuON{d686kT_VOM zGNO%rt_;<(Pzy%a^C7dHgLRd`nrNZua#6GHDVh_YurbS&p`PBASg{cip-wx8I=4uq z=tJz|E}dkFU5KQb7h`P{S6W%q{tyH#Sw2HZN;|ebgCDhY4pOU2sq-|c7*HV8Q0GvG zB(I@bD7s7#^C}_~Ws|leAZ`u|bG!5!?6LbC79QDn5p^BOPK<3*Y3E0=u9bmIB%Lg( zCrYx*;t9IQupj)LgRQ_-Kn zUb=wiR2(%mwx%_h(Gsjtd2Z7W9JXjGOAFTjA7eS8mv9TZrqCc%lNim?eR){u^7+~a z*)sMG6d!r5;a+muU2FLIZ?@`?Z#o(r+cfweD&7OpoD|2uQA{?L^f$^EE*bp#Pr4$z z!B#45#ql}tLnSv3f4I-F;K~qns?UT#xv4XGr7h1Wcaz&+I_XgTPd1oK2 zj-Qyv5@YjmcExhbVZ)^)vO&^w0-)E4ulS!};lObQf5a_^X@8?V%uJED93BCcZaLg6 zXgzZ2mc#co+RH>k5k#|A@lA_-?Q5(}XF7I5_ZCJ_(_ROXyl^gt2yt}jC*1-Xt`U;O z<8UC<*9e&Hly5<_ew-t30qvmq*xv%WWuZtw8ocB!pj7LvAy>X%fz4NP~Qf8`DbG-|cVeY@;v;tKTZk0kbJ+DE%ZPl~j$jdtW1QcFB zFCuKWM$p1%i|~-O2OMp(UV;ng`_IGZDyj`zj&B?VnSIN_=l|LSX0L;X>!_^lHKQ7><5xjN6^j zCNy@ZLXd5d>=Q&FIrSjNCV@v3gMEl(uk=1;;3<*bI=3W}lX7TMV0bMlhe=sPWdp_UC)L#xZltQ)+agsRaVT9& z)sEAeG`$GzAg#J4ZGpi-+TKN!IV+^JuTDs5%4#@57qf`)X(xoJ$!`f!<8ano6Lskq z1Mjn#)e1^L2uj5_<0xn1@g?-em%!8Yd^-^V3m-($x`_M-}#ZkM2s1vTmYH-(h9 zaDrTu;tMG;OIWSIT!bJg*T#~R5%?0>E==p}G9koECwaFt6%=C8{^SPV!04Akz^QYKUSb3CBf%~Q% zF#P1DthwuzrF`mA7VrA`QkmS+W15BhbWF35Ufbb9o^5$uAo&!h&^06xuw}fzQJnOK z^jc!`a)+0kb;Cw>TGOCy!O7YjeGX)FU&eIdncz$*I58$iT=Hgtm%knGW-en*Tt8VN zVO=?D;3t=1^gKc%tObEAS$PePrRL0_7I{Yn%rRWR%*MfV4dyS%E&;Qf^y+By+5sDV zc{x*+U~qY7Ib;40jz~yTawxZM`y!c4_ag>=VuNo`=h7bp^D8R_^K+PK)|mIOGS7D?BRdd* zRN2~*dFCoB^U5O;L@S4#yGs6@B>yBE|1V&P5_~@g{-GNGH%B>u7nRriVyT<&4{IjV z`BS){n-As4b2X;JHTX5G>>VqVX^24ZACD~0zGR_bUpX3Kv}(7fhZIm*3V4Ro^qPQ) zC-vw2;D)%JOvsR?btQ@i1pK$!r~0TkXCKnPOs>fvP9LHN=t3%==frt>dE zj6J^4*lwB>z$r|?Kl3_^b?vu6q*%Y=09ZOUII}@ z#PmKkU)UaN?{)ywRBtl9Ys2|60lD8J0gg7&7bGNL+g~}nOVz9})&uNB3hIkKs;(x^ z|7$7WKOj5bWD#)#mmvj?Y%cAWDHuAGQt&&zaMLb+MFRNVs#)QUAqZ2+NW-2(HXYZ; zH=&;@#@ttSkeBFI*Zf|??)sX*-lq+??XHC3u&uSP4-&Au{e|8QHptD|PqATp`{axb zec`wfB!~o=F-%41`?z&LOVHTE27dG{OfWZDiUc|G-nvgFs6{p{W0+iZ+O5oac{`NCZKY^=2y+I6F zbn9@5frdI5W~r`btm%ctK<&tQ1Q?ScT^>xR2jdG{Meu7u>2Y2>&fehyAqOhJ6OU zZZ&J>I(M$LlW)HTWcvbb)_n#NAWylJ!+qDVaJC*i1i)EhD4?5a#>|@R_1%Ek<-No7 ztuhd&XnIxG$#hemuj#`@!0X7hK0*-QPX`g+XnaY7S-XaX`Y!-*`^Q9Pe`nyw*04C& zA#()G$hY)cCrHX9sn5 zF`znfu7VH*b>2XN>Vhv!{|_H+ad{b`krzyb3g*jNPCzgz(>GLqM4&& zT{DdJG?*X5rUcAth-U|L*uru!ukMyGM-L#Fm+*zD^0iFw-x-MQGrjFz1NVIwy`G@i zGShn^tW)+Rg9IcKF68iU-LirU+kl6F7$n9HI`5}eh()jm(dLwfilThg^ahqH?67t* zmdpL)yCl}`FA&zl_%iGE;TJZ5jvG!W(EPSEUC|u1#sLWoX`cYn{fRWN!Gzv+x^*A< zf(6Up0e1dCx<(`Z58>@@J`Xc6CY52PwEKH3xcUxBzJET4Pk4_7ys+mYq7?0qkQ*i~ zg+%<7?VnZNsPgh=V;aIDFI_SoFXd%hr7PGG(?v(QFX{^HxspOM|E2g<>t|C+sg0S;G0gj zY**;$fgZ|cvIff$o1Qo$WY(=AlCet!$k=@_z#T z*C=*u7s)HMe~todofvMkG5mV3n08odWr(F9=*!A5S2A?wXPLPhjCd%5E%9gW;Z&cF zcT$T3j(Jrol(`ulkJutrRs}DgYE|%Ba@r}lswFUDV1}qnnW;u^6ECuzX zZH~z2>v{AVuw{Ox@F)l&b_DwF@AN&(=^O8ATNzOJG^g)Kr|&GMZ@f!siI4MA))Y@V z0S!x&+BwBB#lbKWOQzeU_~|&xUH1jTsxR&Ew3LnQsCKQhVs_!r$nev&@R(^Yl!a-& zeFRa+tEA$Qt5jpYuQ_@lJT1cMZz{b)a`3E`D8Ad;5L)8HW-Tnz>{;Nv2YmXa8k4hA zqm0QB=8N{+rGS#0=T)sjdHyF%ExcjZV-XRA+$t!hT6FP!Yp3J)J6j#UgKYkGirG9? zC^AXN7;k8C0T`AYDtOGFv65RxuR>RwOru09N!mdwju8!gEq1# zqMiJ%O@XZZ8c3qvK}fJ9{+Nr9mYO75k;LDKXw}ZmEkY5xv4vWi&r5<2>N&0N55*jo z#3ToPTO{$Tv-Tn1k;KXlLKaBk=w0@6!;>Y^i&6u_kR>KMTTbs`SSWJ*Pe~O)tvWg;i9wd2BIGtn9O{5+ zog{X0ATE-`EQch$B#H0jSdvsoranSaPl76h^pf9$9r(4C#IY3Bnw)x)nBzdyNn&#c zVkJpz?2tpHUla;;yh)O*W_kJxLHry<0q21Ho=JhMg>JJXzDz=_DtlWJbq>UNlIRDb zU^hj6Zyb%73R)~#zJ^KaU7}j~Wk}*@4#bv{IDv>(MbwhS_Z*1ck~qjA`lHPvb%`JX zPN6xvL=rYRMEzM3KXf4Ok;HREv?}5gN!;NOa-}53649EPnUd&9+OZgUVf0u@^&%=Q z!wMbsk;EPjl2Rn``%(5xVC2^kvvGB$wp^m>CsAnXx9f`NrYx^W| zB0>s`U&``e8199xv z2A-7PESz8bk_FUCMpIe(DsbV!L+c#}NXC*=Ih7jI5mE>W+JZedl@P7P7VNU_@~MFv zwy=muqdxjmj3|HFT?Yx34To_?RIvFcI^DUfGd7idwuR;SzWxc)4G-Va`DWenPYgWv zD;8Tg5L8T{h~IwVw+DX9^_um^Z2F}>9bTQyw&>TX8~z)>IO>y%%|j!J&5(DL?> z3^xz?7lsQeWXQ{^gfwj0{3Hg3+Dn8VBge4=MUax(jf9om({KL_i=So!_IF3Fmz*^(y|r8vGLymrv$C)B$r z4Y+P)usM3gN0_`S?p_rvBLv!_>o^Un8;SUqw0M7>+cbMg z>4BXe)!cig^fBuiePrO7J6Lex`y#IU2NV}6rPjA}upRuR(*N(B(w|zw(l&PfUrYb* zHGeXoQfB8rN#n2iTPIs)P`{*Te>F;^7&`N^9js2%8NgwwQ0Ab7qe4j&B>f;T!p@d3 znaCF6%PR?g#M7p6KOZ_GDwLh5DN&(xlpW?!a zlpdM6n3#4S10q#wRGWtj3to!gV6eXud5c2xUH_{dkyeOvy&r zCPF6mB7c`+H$m|KlYim=wt)YEf8qan3jZ5G;s3sh{}Vvr|ARdKF93!AFO2Lz02KZ| zvGRWhQ24)G%*@dfw_E4kP_$7+pii44R%vLPwwrFib^{Oijzu^2cn2#`)GOXiKRES; zZ(94!PM;r#>TcnBs;VwfZKlhHS7{Po(mKBtU-umgYaR#!c5Tnc9_g#5#?NU(?FG}A zRa$u4tQq-}{cGDiL2Ac-wt!Q2P4SjsVu;n*c;g0ChjI0eD7U^Ut6q z#C;8x1!W2Q4!nFk_@x;gLJR%zD$H9H5{D}_~ywVn8bDlPS3XI~^9 z7tB$M>`=W^m)c@1r+y$P|6V0({)PWqXZ{~D_`i%__&*~2zZCF4@GtzIRrJ3Kpho#T z;=Tu1XiQ0Ow1U_@9Y<$wTGC*{tZRcA=2Q%GXX1-&yg8P$vktJh`UySc{_qGipUrR6 z=4r1_J5nQ$JO9&*agbpTdb42A6n(=D2iTavDOf2cd&8Y=TLe3^ZX6b!>mOvT8u!a0 zW^ zxMNV^IJtO;HSqaq6_tVurk+j3-X&gkhy}St^+YGY<1kyN+}w?$&xcuul!M)5T9Z?e zFi%oZDvlGsOC2M)(G82=a6^b5njuBkAq}+D;C{T$z?=Vo8>L!c7=nw%X!_WUTH&DS zbYsh&DW3lWZrnYS1<`N*fKxdKb{Y7kA6Q(iFRly5tP^!mRz$6bf>O4lt{lOWw{OB(uWsQ{i5oezteGp;(5nNqS2_il}!fv@6^>6PmY+ZMht#wIC!%*I= zYcD3Yk`l#7b9|KIBG{x4#C;|6P;p|(+?)|XDLCA~k^Cz+Ny*nG{Fw{WM1ED z;CGMXq~Ob`Jmmxn(!c*(6$qFSg)EC7a#b)LFykcbnhn z8LY*jt?`B8G=zg9z{ww+_?A;F!Sz^2e)|-Q@cZJj;QiA`fqK`Q0(B&B{}Zd@yYyEZ z^v$0m=JcOftHg)r$Rwr}+nO?56pG_)bi2BEDj1Q~~~>9Z^T&D z)wIkLw;|Lr>pnp!-C0~raMOi9l9UMtZQA267eUCNZ7iR^8JG8oe+`{ z@-n_~_HnAXZ%d$^idjj7!DHkz==TABHC^L1K{gEKVF_yE7JsoPUOP4r|7OrrzR|F? z?PWH?#mgaIwr={HU3M857%za1!M#Nq(EG1QoBS287{5z^L_g~yvYiyx&-CF27m_NNf8=XT>;-pY{A*JT+-zdwl-n<2hg1pX zfzwdN7nQJPId8sbsD#G17c!z!Nij~&j>5l&KI$AIKuzv0)TR77+4+2As?qDJsP$Tj zW0FR&p%ab_=Mxd>sPIBHAx=xaSqBw#y=!O!)J1rLJ7kcGs+|e*{7dpsPqEj8;vD|`8cQl1 z0}dsBU@D&uR$j&PnK;bfST$-(X!v8{J2s zXYG`booJYlcU`DEZfupZ#YJS_PZOnvtIF()6~30VbcwS|OIJq?Ph610pWVQvak-G1 zbQ5>0Z9ok_;3i8=H@c60vz+)xurP?vfDgnce|XfC4Ai*315r&{f%Hfw{EhS z@IJU~fwC4`*A~j28$NtdF#diohZmQz##P0Ap@|a=eC#cHu?E%Pnp>=)QU~?c@mq{3 zK5&%X!T}xEd}M(K*7cBc&tJ!6;=~kPEu+`v*B#W-8=-_%OS?FLfLUd@fvM)ZRv=!@ zH8k!%kR+pfbFg&EgCLm);hHc_33JCwVJ^bg{WW)6TUy zeCT5q)3F@_lx&8I$S8(AF`JQlu$&?^PiEa}8GCNjQ&>(%cv7H~)<7?cKvMzhquZ=m zV988M=ZvUis%KNd2mNfwyM3EAz>(=K`MAB~4vU4e2+mm-L;d;aJGhTxy}^Jt_}Jj! z&IXF#Au1;gXK_2uxiMJ}J)Q!05jOZPOYkaz?$V7>QR&8UQQ16V3!dWHI}W!4-DMqJ z^7*d2xOp`b-&gPA4WZg_w7Q2J+qc5N$K7LnTypt7eD_QlizI(0E24OGKAaTUgyye} zUSaUDl*;jlL0N`teyCJd5?&Tl>Qxt}w5gN@R7pl|c^5&k|FD*d$5;b@`yX5?^n3=E z;r?NfO7-ame&Zip8hU%0q0$m+E!RU7UWpuI;QISGP%{R&4&9MjP81bD(j_#(*qE6s ztqC0HE0hMN04li zIh;Mj{b&OqDE%SRdl-{WE+LhC3PQm{mRz`gw4u@_7xX`Sm8`xivgZ{9Z~!pr7360Q zs21TH5C_kUe}KHq5@d_u&`_$C=)YOA+QOG;^@`k{v z?*oP6q>~-;Vw=KI=u|&qk!=Qy zqO_DuCkDkyt0z-~uM+ErLV^1FVCnO9dt0+PX;7*$K~%Q=z@zPBtolCZvSc?62eT5L zhRI7}+O&u;O@j}fp2U!GngI^qJZ52SD+fUd#a;(rp-zK)+)U~%tPr?& z*9Q)>?r+2wTakCwqL8`<9G#gM;k5u(uY1Dkc&a0jT=ZHVRKj9!+7mWUxjr1-+b8T5 zWfJ-ey`G}s?g+}Xr!3NIIFL3KWg!Tp_3#rUMUbuz!%>i@Xq?tg#)-CPu)33=jC#h} z_yiB5|e&rn5o;DGVb!6b@MywME{Cs zKWE(wwW+jVQ@~g5NCxitI!!|yERFS|dkkKLMElb!dHANutiaUycvvnUO^NQW=};S% z^ldX(H1~uzgb-9trU@Vgf6LBY_%i~%DqDi4U2t(`)+XsD2A#_yCLr z26}3Xx8P|X5Q5FR4M?y3PWbnS8u+JXY@};MKxXYH3$omPiY#v?_L=G?wnxs%s|7x% zOw}&ekdr3AfTh@0E_Ie?er_)H!^KuZthY2wA9Y)F(*2(j`eJxEba`pcE&RVG-S9ew z8Xb=`X5il0`S*}L>BhW%1-O`Z92Gj8pEm2>g}1ybR9viukpr$8%Qo-@)zsRqLkuhb zRHK#N7(#_^PwD3p!TlPj0ep&!8td5mUUe)b+V@o|ftV^34SElZqauS;o$slx)u=M? zhP9e?gXS4{bysz~au?n+T-6aC;Rosc#20-_;>`T^0slacCkHe_j7Ip)LST~MwcSEU zL#g9SDyvb=4-NXyL~e$+b0R+&gwmlRkppESN1{uXyCbEaYf~>i!bNTCm_WYCMUC>y zDY8%EFmzQ!68}uKOQK_es z5SR$*Bs%_u|5V8Ycsr|Pon?Iw89QLb8~aFEa|<@+izPamfX(wRI^-rp?!)~LxOU8IcWgLM+U-ke5|S}U3%g$Z7g(A z6P>0cFSU>B$F8Jij=(A$gX8PiUAF)VWC}Xu?U`vcSZZMXS@Jt;MV zx)JmXrk&SDJJjN`VwsAewXN=)h!$K_EO!#@67w=91g`n1c}grCRCiWM+A8Gp$TuPb z`Py^-ZXV&1;#*S3Qk#CQK~yEd`!@?gSdYwfQ^tR0`bl^@XZrUUTA@nU3KcpJj}^6_ z%i4b}Q!@k9SmiZn^YZ|e`3;$*rC7|5^~b=NQmi}MQl!{F)rk31(PRw4;JIs%I!yVY z8z%CC)cVS01U?_6PE)Rad7BRiM%{P-jv3_m0FKqcYG~v)blRfW>nt|(p_BC+4x`Zo zaD>*w>e3bCCZ_5Fdwi*>r;@BWW&6ta2C9veju{%%aEx>{1I1KcAV#Ww_0+(C=FUjN zF`O1i=cQ{%-$ht~^!?2m(jqtn(qV82q*GrMNLOLkACMNFcSKqxO(OO8*<22(gz1j7 z2#x-cXAkpqo~F@0&75)4Kv&@G+(pAV6cmAT#OE5$_HYQCHQ^9ATNVhMeXu+MoZazW zmAys}cG7Sj|ExUDC4OqOFGff<3;zxSBVpm~n%G(RF$}Wa41kuV*1h3%?ky)@-v(la3xHmZzdR zGX5~-Kg;+fcsrNzUs7Zl-<2%O_(}|cDO==kLSl(ZDy&XVRr0yWWw zwo+0@j6SD%Lz3xVC5hImU)%o_l>%>PQSoh2i&jP_r;QZ#&nT^LdxH;mQInl|eL_mr zHvcK*c2apMe#C5FD5ZQbQj;>_UlSzy>WTj;>0Nj`r)OoN)>luEl6sHOD&kN6 zRnn$twV_`(8dF(&>!}#s2_rugV`t<&FH=44z=tk3_(PLa3$Kg`WlC!m#DseP0*^Z z+XyVGuX}5?>gy*sMD_Ir9HRPa+C>zjPG5;)L<<@A#i(yft@;|WR!fhqL6A6mx7KjR z4z|ZxdoZRKPox9})N+OyJ4A!YTWK&iBdmbAWsL@NIUEA!L^uS@*RUHH?be54&z<|8 zBaSeGnrkrCHRWNJ)mJlIkq9z4$6GwPj_k z0TgzBsOf)N<7Rj}TjK}dECy9gq&1Elpj8<~|7wkE8>*v~-i^^`Y@{9;@WFjrL(#3p z^(?#Vh!OqE5F=KWo8f8?Y&B@C4e&v;tSSCkgx;OeGb*)i2~BXKD#rf{rm&+lY+l(& z8#eQ}IQ6_=^Eey@r@@z4f{Tm8g#(S%T1sdm1Mk>a?Hsrb!FSPa7_pN_1lkC{_Zq8h zmFW#}*>7XDd!Qc$A|^IYl@TbdiMniLL%{VBYs_-JDhmV}<{#9cVFtr&N<2K8ZUCnc z=x&P6PJyrJbJ7eira+d*!pdY?LWg-8p8EV~2^$h%UGqp=HWcqjr=;GxxFTyZ? zU&h=U1%48nXd|&BqaJx&FkL_30P5)0?09vsi{Gp8wkc*NxF2t>Mk!I%Od zb*=uGY}f+wTP@T!N>LpH|D%OE+*Lo1r?gbdTvqZXt<(gib8Xz_-%4#3;#(W@SpJxA z?bsOeH3d;QR9(cGZWr-gt_Ss%Dh1~<+VOr6#dOZ zs7$ShDx>V9efMTvAB3FWT76OZDhfAyC#X%8LO5C`s4W|Hh@u&y`*VITz~%8hW@PbR5dUB+;I8+EACJQAajHfo~sAi}`+wox0oBH-;dYP8GC zJgBW&5MMWf=9lOxPfUWo4w$CybAc5a@-@w!Az>EpB$!nYQiHU0Z(FsNi!w_!@GHq` zU8Of1HBzASAUHBp)WJ$+hTSbGG(^>7btFX%_2|39n(4eOMeT~!`XE?VayxYvRxNLb z8~A~CYG>smIDFfy^#W_$prO|V)8lQ{c#ys|v%Q+(;)hUnT6h<6KI?!{!t5~Y1n8iy zSAGpO@Yg!3yhe1G7LbN~W*tL-#+}py%E%Bjcb(KVH8zAe1o!~-PdckVx=iOUrJ@Bp z9f(!%R5eW528THn<~9Y6 z@d;fp>^K}?;5WOdgCdOj(E)}^lk1bp$(&4^u8_)iMxCLLpZf5zUDfWjhT-HzXV%+4K$9YjO0z6f20+M7>1t!8y}yBnXQ-*Mi0I>i0$z#(8QP|d z_yIDHc70}_N5pqYhMJ@-u7PW-GSmT0LJ-$kfEQ>qIolwemj6o(XyrxuM2+(&;tlGi z*7iD#+f&E}Hg5!fzNDKv$t~?Ew#!uMu69v|`(nPjyE-g*cL$VAObSe;G-uMCw)xm0 zg4XlL?&v6N^)alj_t=IGm z0b`)JO|&XvVtap~z!`n(Bz-l=k~nwa3raqUKm1vi8sXoUG*PtQet$oY>!H?n`{hRj z8PY@D>=s9^fS&3iZwJ9gw{GgGsxILxJxG^3qguk`@v0*AzOeLr2~X;wTT z7N_87zmE^(*iEayo=@T)m@+@07FRqcGFKxdf#d*n`Ci|ig+})vRLx@A9~tJ6O!=lu z>PB1kP<&~<3e9sbU$Ml~R?zT_JnDHF1C#0z2QYy1gZ4geOL1|L3#HYE?0?X3UxYh@ z^@1hHD0-G8=`DE_Zo0??_oHo@v}Ye}rs6u1ZI4ld7-JP!93Ljc=rY8vLL0;p$T6%! zb=Dw0t62fW=~znf3TtBz(==`vFdn3}A!n%TjtiqGV(moH`&q<8$~36=s!FID#1>Y8 z#qsq;P~D((M=ch3J3#cZ#<0_(fasCr0CC39e}niXY!FFW&Qb)#%Oai)qMIYc&XE?K z6vrospgKcWM~HL095PyOjbR7TtFr?<%IMv3<~onPZOOoI=o7S8Qm9+ zwZ#^@CXyC(FL!Z-xWdx`VgqXodx)PW*lUm=t{zej;_pWV#BX3wfavKAF}8Ar5J#&v zhy#QeU2&Qt#P?AqVT+dHl4Olx5Ag!FygL?`jf2ZUEIlG19)UptVt9g+78BhoggAxS zAdYPhBI8SebI9-U* zZS3p_aX;z;J1q{f#;}KYp@p*+j}0sb(L+Kkg+T#gVk;+z1CPtdIEz2#PpU<5XZSz2=OCy6D<(m5@K}6 zIyyqUjDluYFTQMzVFyvxiw-bN*Ixj}3hTvMI0uMIM`03cFA>jH=@hs~s9L?aHPi<2 z)8;~p=Q=n-yoZ8j2eH^1!x`e(c>ByYJ?;N*5Stzp5d9g9AL<+-8nH(We|leZO)L2YfFeCcx$aaep%> zh#Q_)2yq@%WP$iQ&JLisG`{KxF$#5o9mHKhmKgRBuZp<#-G~N#%RwBwUqI{%+XKX( zn>s<<`K&^S94fLvENvnnrd)A^*bH@n9mHdSmKgRB7vqS6W7VD1ryRuT`vk-RusuM$ z+{6ju(Wezc{0J(tKzt&^=(7HHgxCRffn9Mqr?bScgD6V$H*xkbP3gUXvBDBv^qqh@ zoWb~k^}3L2D=t4jkx-XQTigm2Ss;2yh(j+sLhOY)z)p)dFi?{*>>zrLZ)6Wo^cQ=T z)8bp-3TV?|w?O7b`?p2+($ZgiT%i^ZLPZvcVL}VK34b|49DzE(PK(cISSKobJBYGg zbbx6Z*Yn@BxK3WSR>WYy!0IXF+O&A@k%Jb0g^DZ?>kAROS${f0EI?ggr$sUHbcX14 zyrHueU+z&(i{I=KT6_yO4`fk|oV4hvL9_I{wT!+B6Ajuj$w-=24bxCM29 zofb1_d|b{J7uU0gM z>H<404#H@w97LhT0d?(RnvQ1tn-&!b^)Cj?0@iUtu1$-*?rB<#$PWy}`5tPGBdA@# zFtb-w71Qtx-{o(wPF3O`o0pr%)c2Wv8)+!ohvQ8bOrN!@w7jt{s7|l8m@UILxPkD~ z#_N&TzfME=!^Jdx*&ZG!m#ZGSRw!dqy6^H0xyed1$XJ{o>s@9OaUeyAh#S{NiYS1e zCZbgrDdN&X5-|WCmZFcp%PBcA<&#s?)pz-fDalGxh$@^A>wU{6>U6RcH6uxingc&g zR9c!8b=ydy#=^r+6wi!CvTB!?wY&?G70}u3<0hK!zPM?VcD`+;<&lBGF^N*xLU?Jy zvQnk6M+->UBzRcT6IEWux-{SAJIAzj`xbA(^C9(JW4&+KWZZ8fQ}lL%6!Jd&G$CVf zf`jtMPY5x>qg;wAkoIM&OwnOHD=)0!)ODM*=Sh&ZIyk1a6t)3gny?9-q_B|rl%nPE zfUs5dptV}%Q?#$MOwpxANKxAcNKvUxMj*-11;y=bC57yVpC)8}M=7N7Yb4}Tc-WEKvxnv%jSjb`*Y^u%#WOuvYU(*q892Jev7- zU|`MiDf+9U@AAY6$yOQF?PN4hkO}$&Q=wFZE|*wkeB55j$ajf~3(!loxil z0}?bbS!n?6`Mj7F>y3Dp^4h7j6n4G26n4*K6}G*d6gG4&3Hu!$cEW`A9;oGoDG)~1 z7a1$m7we697GZr_Nnua1UPCE!vk5z#B85$uL&8e0Itt4U)CG;MK$w4f-{tA~$<20A z|vujHmFzI;ZsYiewT-0prOby+%# zxQ+Zj|7W&&T1T>aqB6#9lPwDV39Xr57z2zIatqVA`3r8ve>q{4daQu!mu-MCH@VsNiXcuG)CZBN3~#Cox4@Mj2h0HUkl3zI=NKN3Bdm*2+%z@!|{$ncARheFlQ zvLoKE{9_@aubQC@xipTK^;L6Shn?Lzu%Ftcfls+1(h`)&7WZZ z{hX+lbi}MU{@M0JSfbbxb%>^>v4R`-|1tI*U{M`kyzDM02nY&G$2%w}Sg~M36s(|N z?;6F9?%E=DBN(vYN^FUvv4q%b)L5g&5_^j+8dGdh<8DZ-i6t8M{m#tY0{VaN`T4PP zr<^ut&YbCpM!#d#-@0W)0Lw*KNvYkAPe$3=rtl=_Z*tx;TWOEFwC&S7Z6P^Hog+u3 z=I06s>Tz)0pGNLeD>yuL{|yw&cl%odo`72*1C)ybY21o^RQy2XHkAfS#?@9JfMO+O zJ4LFwbuWJ&*GuWCUA}|Q@1@j@x$&#frO>TV*nO;Gn!DhDBK4bT6RAp1B2|?Wf80xH zt^M$O-l(^-OZU3P6aIH^Wkx{98+aKVuF}Twlt1zpnV--5K*@-jhT&SAbc9^Ar>&q$n|dZ^2E#z^|d>n@Ya2?oE-Db6F#o5QdxHZyO~$@RZi5= zh5c(SL^Z`#FCeJ2{^kZi=J^V&CC@L&zGkwja}!5qFaDN=l>(n zt3Kn2Xi!R0_NJeL;7iWWXy+tqJOGv)jz%_J3|qF z%Y2EVaS;9|M9b<&EiQ|dwcmUU)#gDYIkysY2(c3z`dIX0J5Xqu3>S0V+P(`XPK?&| zs_46L^~6THInlm5?oKSF$>KN8$XDPBy};?!Ww>;cgi5Uk86uR-0t5&`w2&KHbtXQp!gw#He58W0y~T zRYQrdMg5fq`Z1-XeUb}eHJ_Uo)I#;P?XNV}CT`@+KRuAI>8~W~9yRvnkNYcCgXVcS z7Z8iu=FOm#*BPM9)|J+J^CJVW_Frakks2)B&YzDSsOTH^0T&nmTfOWgeR|ziWvGEl z>tzinBd7+JTym-bet4iVSX*}(j~=9iYXjHtR)dsS-PP+xK53AGiy9IZT{QCTgRp5J z83F4cB`MbRA`}xB2{ey^=mC9-5i88{uz5{2YAB-Yl`K)L9ZD$5X;w-MQ9s%-{QkX) zVKD*%L+9@$hEH)8j4+%VX2&p1jrs;r4h$?q3DDI=BW#eNObw5j3uz2+otCUQWxY+- zDw~u9qq9Ww=Z*Le8OkzUYDG^zW~kCrH!{qVUmS|_7;9qp#0*o$X>@64jeMm6J5+oT zxMfi4>8_nI@?fJfMz{C0kA-HjK2UTb-i&_oemBpHL@l!6 zO7oz@=t^K;PKzHLyQI`QlsaX&(#&s=OdUZ#NVr)6373Z}DSjR@p{$zlF(p(Vq4ba1 zd6J}b%Uoxm6h(4=)7Qy4FFk!`?iT!dx64ESvTKAg$aUpc*n?1Rq|!R;oCcTX?RBLL zXbfE|ipJ3E=s9atf7lzlMCC1XxB@Z{o6T@l-va6k-S)TE|@Z)%GK(uUH;n$ub!kqJ`FF}5J_5KYC zIz2XU6+#hQ6eY+!UobE}q&P+6uGl!>*`t(D*P0}=FGeZlQ%qB-PsR#2`p7*N7;7=< zVRBn_j>L{F%i@|8oc!zv`Y0k6oOI45tByn9WI^aYj6vs(ywqr=%Fq`*N#p{YzHB)4 z&`!BR&eH@&rt3CM;h>Zpt0proIp=u$6zhdloC|Tsf=Nth6aV|4R`2LHMHBYU-sj5-6ksF~=ZPywl>b0&{XXGk>{sF{3inIcrG@nnP3KigHkq^a_B{%nXxC8`G1 za=v%veBuD9``iJ{>2~E8$57EYis^KpZPuJGd(X9GrqFJ4t*U9}b2 zo7Dmmj@qm~%`Vog*1!^<$yDn3cMLAplzJjXKUPuPOi^_aY%o@daJ`X)X3=M?66~6E z8qK2c*KXyqUKec@=f0El7i|)=M9sPF!AW47Jf%3%LA_U;GXKfq`F}_IE}B0}8rEo8 zAW$fclVRQcP63(U1tt>Oz7FSPi69S~w$HHVcdjq@&+PS8je<^gvgh<8YK4h+IQBRu zN~}>|J3gRe@=m_wl)UFKIoEN?3sp)Gooi?4i_xRGt-LF%F&f73lM_b%WSrs`o;*R; zb0X}-^$5!FfJP%Yi2MCvBaaxb_=TAdqlV?i;LNh>zS~=QM{yG6ppmy9uS8^BIY{H3 z7v@gAL>DJt=6wsRBm6#VlnD@=TDLXo4CYH55!R^hihb`Z@-5-5CU|6AtWohr;o`=?JAc`e~06*Lm&w8QTtuXl`vK7{H@W2yYf+KJ_y*a28U_m?I&XQ=uZcX ze8fa0#QnelBvbULAAAR6pIRyse)++-kFIdPkvF>PTODzG5gd8dH%s^Z?~nPDtG+cN zT=&zs;H16FO0k~LESrMPYyvi#o2MdM(ly`kGAH&?{aVc}yOCphcpn_DsM2&j*fazK zDwaMKzxx|$bL|v<;ADLTW6)1D+Sle!hm>+LO%BSjS~E-F5vFg9{PYwI%{n5`Z%frs zug(Ms?vj5Xc20jeF(^3H2Qj2wbGs0B4}94r#cxNIt_eDh>^1Uhn|x1oc)sWVlMYPP zqJsq@t3HGR`TKpb!_2Dx=eYQg_v06wf~Q-*bX4=hh{fz^_Wn8;;%hV8B~Lp_gMCqa zHPQ+b@X{_&BTr!knntyOn@Ne7AZ)eA$lbFPC3sCIVnRV)I}eI9rL&O1ccVR1F#Eno_2nT#xIqp=-EDA*nA~IwF&;7r^PnM=Gbd zK@1H?;BjQP>dPQ!A$DS4+9|35AkE|8uaNK$I-+tgi9obe5wxt?X)Ga$;n|nM1ACB! ziInr`Wl+VW5%^YxZjD-jXsTR$idAny6rpJ2K=Bw}JE7Ryp4hF01hh)_F-dx-+F1YG zp*Gg^kCjGQ7*D+`+0cj175fpGdyi!Mpd_Js*p5(T0IE%?a<_m zY99EShROSV_24YW>M^EM@<|?=qbM!^MbDI)zdr-_1|gqSUtUxi0x9T#!0`ld1zD)o z5=N1tT6+Fvua-mK8F_Y&5>oCDnCHTgxVr9ZAuqz)4sZ*5TlM^FBj1~&G;dxX_yCsh zQB{?}$#ml6o3`jN1>miJ+5!7R$aJ+^7~t6$q+fn`LQt)8m$w5FD8q&8(U$+vDxI@n zcJF?8ZS8g=zj{Bs1^xbcpmZJIG?G_I6jbx_^jc&5y|zKwZH4)$=}Ne6&o(2UH(d!z zTZXiQm>`iZI-#>h%|e`N)v!#0kL3Kx?%DA!nPqG(DA1~3h4?}rTLdiL=Kwh=dvYZn zHbbcrJUx{tv2L|fV#nY9xMyPQY9u6^#)u=}33$;uT6Dj_ZK4F63kT%M?&_BD@mr1j z@Nv(8VSSK@y}UU`X||=8(;8ZS|sl;g?j^P()D&=(@zcTWFW-8sa?UwL%vy_UV z7q);Ls6o5dPSXXFW?rx`2$x7zo3X{nFD(pesl~5H9?r4^QyF0o?T?i}B@*+Lits6a z-E8EBJmpZp%48xtY;#co^Y(hLAnhh8FW(wO6efDf+rFK{dk2ERGD%{veEn`(8 zi~)6u*Se$s+TR^tY8QrdKHH?!h}wjVg}9J&)k`(&$0DmQR8q~FhpabEn7FBnK$$r> zmGb8XBkwgwX{Y-ffh}{;5spCMr#VWafEpX1azQqg69>P-kX9vM2@QC={++bK^+w)1 zUkUPfj5H#28}C=5T;<5+_(Y4RtEbE<(1a5?1qebXt@_zWvg&hD@N7P6Wjq3p^OZ2~ zL=oQ*f8iVOBPGiD2L}?A{K?Gx9FH}icf&Nji@E2cw|G3hFfGLQ-a5hw^U_?_ACLVc zs6tkQ-|S6z#XB9IT@`nT0R*h>&*&N6qm!EuT}&qzBZ{nUcc7&tXwHAQz>3uLcr&W+ zCP+9}bVx}KGC3evu(u%`_I`x%?;?y=5t`T95$3B1y9k6AkYH0E^*4!+-tQU?&HZ$( zksrNSx?@G;vHM4MLnCvm#F_6|Uhy{bgX-w+uQBre^OQ<~&6*NJ->xYJpBKziM(K_r zm*0HF7|{jk#D0q;%6({cvE1j*@ooD9g0!nujn6~|@)m9X_^4~bL#%@g&;IfpqdT|? zb7?>NR@8n87w|{laNRgW^!w4b97Rm~(YJ~&8WEQ)rTqAJNY)lS=6CR0=Gsb0N7p7q z$HkRc!?^CtD7of!-|$*9kPN#NOEvbfYV!YWOj$FLV%3kpUmH#Gmmi)VRH5THzuGma zT(M3-jC^Fpt|I8~vB9+wU&IDi23;C+sZiZO1adxAsz$^i3&~F}h?)CkaWZhM=2M)a zzj+S#NPUKrjzM1<`JHy20ldo-&tTnDMECnlfumd?+d<0&;^}Y!<{>{*5~{fTqLMGX zwEom3q)Gqn_n)0plF>K30Gz6O8`-+SuWT8tdOwt-ZZH%`oP;E8*%vlj_C>LpEqLY` z8C`%_;I>6d&fge(ID)0pn5 zrpf7P)2*4+)A9#n+OFEZWk&9OqjZyy3CNIg2)2#>Wy8*8KEL9GcX!YktUg1~Y9{$Pi$;(+K{~#@LkPqSON;#ZVg{Obo zI!L=jO+B`xcq*!ZOdT>D{Wf5jAEn!B+g1aKIWbJT81b8YT?zP$RZ3#bzZTj6 zcPR$=7o-#id;xF-;47zio7Dh(eZBx3%xA4u%9N~KT^I&luv#%h1)rh0H=KT>8RTfp z7e|YTRLuWlWu6wG>zx_GW7l8-x)B0m0s09JwI}D<7oh)9KW~FHrv>Ov-7&eA@BQNR z5U~IqQku-$dl#TNTdQ>P-+qdqrqcC6L{7f93rfyht8|Z8enH|}tRfKeg!ysJx(Nhd zTo}R&%Et%xfIR{H0%US-k*Fs*Z}k+})rq!W<`pp>#UB>W1tfd*BCu$B%MZ0LAMva!f-Z&b>;_Dnl# z-J{*4Xf?WI^s^;5D@qTOn}5C}n@%4krbtwRY!GwHycX92(C^Jjpz#2ZUF&EgyBDr# zE!=>p#}tKWE*DEKNi9F&(gaLgX=_YxTJY;k8gk1V1fQLL+m9tyzAM}aE(VTKRRU}$gKf)EBm(fFua%x&rfQ>L zyV0lTppY%OqCG5vlt>J2tyoG4rabw~vZ>C|COxFQo> z!pNqHrwj(EQGbQnsT4Jai|cnQtF$pU`Dc5S>Wy)DYMRt#23=m2;M9~vm+A3DLQWc~ zT7U+vAR%D^4vu`oHG7qqtcIs0O%*mz&bv*OgvxMxmMsy0m$_HtT$}RD#?Z+u2Sd-|i!;>Y zkz{E8aFwAvJV7HFDm~&2-~J64+FM&?XgsC8!%#C70WtJ8`h5)5G&nO9L{N$|G!^)5 ztjJ#nLp}C^p@}bS3emRCyx#$3k0$HQ7lg#SYEv>| zXddb+GUg+pz8Gz+#)#1JotWe&9m zVL)S>62_|zgv@D~2%LrPg(V7I3$^P0%6PN?F*!wLEK}4R@=-^W9_#9fe^%#l-p~y)TNnIXY9P9nN5^H!-5IPB>l=$h5Z5`xwB<+>kNl-B> zFwjjpjvGEI0wN!E97L?`SA>W;qAh!`#gC-B5{eu;-ZD6g+M?K_U~)?zBSl*ujE06w z(SqsDk+GIcdZ8gdp>1F1I*w~#t7GTeMl4H!x=8KTKO}2+p4Si;b@k;67UT09VM&6w zKcO5-`tPWH9$p$L>;drEP0#nPf~1q>hK*AcblL!LeU!sx=cDd)2#H)h1Vb_E&-23< z)~9U-aW7Yqn-w<+U#PZ@i%XHAb;G-$G_1OSzyD;Vg(+CFkA!MiP$Z>6wS@ z)Nz)gK+Z8=F;=ZdbTUf`HupSE%Ak4QE(PByiK zmzqe{{xr%7%V&R{w`lr?|3`YBOvj-(2Y|e%IZZTU%fhrxLh3=eho4WuXtpRJ(Z84bu$f6BnqS@L_&~Hyni%`!|FqhcOfJ^d!~} zEiGmWh;(r73kH^Y0G_(v%sigpVcBvkLBpkil$~Ze^4;<|`$-9DY4#&W zLd70u$8JD=;k)>gOr}&9;yX$|b`GUXp3VS=xA^0ql*+9pIKw*ry^WLCsm`#xBrLxo zu*wSgeoU}NYI(n(m6(?9&cM3ZftiW`TLwjkftW)-cEZSb;yn`rX5|-uRw{Q}T-J%n z`{!+hg%*KTRl;gh1eR#k`jyiGYc5rvlK{^b@`#_5U>5BRe5@V#rZ#V^mK5kJpZ$wc zsoR}0P9#*f=NgDy4mpplD%e?1KX!J=VZ)KfT##@bL1z*I3i*6gVkc+V2hZ8q`@6L> zY&QwJdJ))?y~%)GXmAF+;Sa%EGgoKGc#u@p&6!0YFRmh}{)v9U>E-Qrc$f=*Im&HXy(M6sHR0DjZSBX$SP{2A0mZ8zNO62 zo;b&^-%@63rt$RKN{Fs!7bE}ZwlYk&Jj=M}kK4*r4a{+Wf{T`xj;8QQS!s*63HmzY z1;M|M6Gb>Hh8T0D=4z`|!fdT}HKH)DW0@-aVA?$jP@~XjJyoz10QQ8HruOJu1bpUE z<^ll|pXO`YW^cIVH>ILxD)+ssgw);Gk%+lvuKZ{))MB;x0)z6LhuMF-6pEKfoq<&9 zd(iu&-&Oi*68Pb}u(n^F;*akt1IcLK!+n>5e8xRo!u<)qbx*mG)yGfNW(t02ZNhzD z0F*9iFV!auJa)3fHL|3rZ6R42F_YWRf(|iv7gxfE+(=s$V$4S!!_e=fBmZThP)duJ zfRL~-$R?(sB$2?iyk%L}zPHhCzC5hx2OKCNPXkJQP=RSwU=1WN+t7PfSwT9-k2C4$ zH6`i$CPL}Psd_GquiJxLDx$3B??aS#L{fdEiQ1HC1e+h{D-lH$LqxM2LPkx2NRD<< zFSikkCqeO+rijfIcZmA<=0?6mf=^6tWH$Zs4<0B#HZr*_YAc=(52`DEta}OXVVKpCbSfn;9hn*$- z-W7^5PkMu$dYMp~(M52M``W-EBBe3+)W4Tdp|{u^HN zp%S9qzKEwiR4VumY(=GRneW|I)h7F)(pI}-Kfm};iPEn7mcMwYjL|N*#Ep*>Q{B?R zg3i(&l1|@!^vsn_FS^r67?V1vQ}w7Usd>*)Mqcf)avg^AxWFZ^l6#_)Rv|-FEeerU z=nQv}e&@u=dcPxHMo5^7nvnIbt1A;ui3G7u(;RbfCbwZK=wvV-g(t_Uoq!HJdR(}c zEWT+<7_LMfyO6Zwmihc`$*eSnWDg6TC87V4#EtxQ*1>Icclpl%Dr9XI4}DQX>Q_d3;js4e#?x3G8KZ>mmTzpNaRj$OaHiN5->JRpxtN z5iA^&Hirxc^vbG_x(=^>}hiAECAWr z@eor}cIAeEivKNMq!U;Iz$qT5iz6P8i~7g9!ul;-wx857OQ?n1KYl62q=ZiCVJ@#AoF=|ab5Sax+=6>1RiTxaPwwh z2^RFuXaTKhCXL?FRjTkltnUQR4c!(s`EM^5r*xZDnIGN@8cCZ~{Aq*kA=!2RiwlI! zO_9LMS>dDgj+5xqo5xX$q6;a4Xa)eY$$0b`2Mg8yAi-*-mgK#Bl%VP@SaqhVdOatq zG)pB_6E8VY_1R-~UuUhYGW!4lVz%Dew*qYQkpk=*@azosDu|Ms$|1a$pGdImB7D?D zE&Dj8;bw}#|KH6u5KO~v;~?<}BE^J@#1|AS%L}!vVvQC530#eEb{W+~oH*k;U&rR( zsfLXw>R7O@!t=+xHv(1q*1{eXnqcoP!06kd{K1K$j*o$RyEPOBQOA-rZTN3GRz-KR zrjh%)GM4zp1QPQe6+TEdHS?wGzx8-2GkNIaS!kbPy2z@ZR+B2>g<11G`JCmx7DjSUqH48jB4QZmexU>-T2o1#T=!`+5Pt z>jq*^)WELa5=_xuk!q`J8P_6v1pM8tEAgf)yOM* zunL-XysZaQ{DxGOG(I>*H1@+6HY9ln(n68-fCossQ00GthOY-UN|>T1BMZObIWi^W z|C0A`Db~c_6m_LC`m7N9p(OL!eD3GTdg%sN#+tS#Q#4cfd{0(BJOcS>r}LL5h_q0A zIm8FVvO@2~s1>>}=6@1N#iS5MOcFxyMj;Y{R++@xd9ZSRC!?hlS{)};NAQKMUEV?p zlcTZm+MD$ZDTmniYYe~WE$Zh`B_j_ijrw^}(a3L?X01>^n-Hw(!$#^GRD4fyzRibK z*Yx4Hd|0&Zd=w5T`=V-mcy(V?&CDoCRLSp%sA>4Z=*gEwXb8Mc+Va|r$<}R(OLE95Jye;qS)JQE-WFh_($6XVc4Kz)$d~jw>KT`#-=n1 z#flB`A2*_%tH)FFegI0J>D;1ceo@)ToRaTfmAY7r@Sfv+4QfjGV&X11tG+GTO+)|- zif)Fi0#Hx#SkVJVlWUWA!aUp6(=5&my+#nB|Pw+%_EM0NI z=-q*6%Rj=oajVz|hENVh+%8}Hm(QEiF(}wab}#nAzhj)gIh^>knltvZBiAQrCUjbJ!}*i7Bka3kLs#B#N08L`1^d*T=p zIZg%!(N!dPsI0Fz2oN^{szIXkl}9u6&6@*q{_4o~BslVPg*fXrhk!#^1^s#tcRE2Y zUZ}_x=Dm6gBkvKyHtE_c*jg3JVsu7it{uvnRr|dzp^STW&xV3lJ+QmIDMcS}pun3g zO;z|6-35I3Y;u|byM~+LAY>?8$9_h4my&le(P#HnK`=eaOw+;17&`0!YiiuHGK{s= zz>5ABh|?+Itd;BHKveLZw++H{6A;z694nvP2~qOC;Ar&tPP6%-^VS`rQ_`hMV;Q-A zDk+4Iq+->70uS_bIaVRq#f_--$(<&Ibs*9#l0Qx~ayNz52(Et;YUNa#sI}@Ff|fLe z4e;9uS`N{?nAmg&PLXg_VY9Va9=si6)zX$;CxY~!i61~mR`aq0j}R9(O(sotPMRi@ z2Fawp&Pjt0JmRMrYt`68ChG8G_C@|w(}74j83VEcKusA3HMQ`KMvOaa+%ak3>(=NN zY)IP(R$uo#!N~I>*y!@JuYo?>1t7TPP!9;Svaj;fNpIv~861kMM{X7N#3F{xRPWjb1txfh!0^mLE^1XQ!B=v7DowQu*G4TiKV$ za4Aq}BQF=j6y2?Hk9lGY%I-p77y>?~aZY6qJmp7XSb%OYQoo5|<+55JHN`aE*J8o8 zFL5cATshJkz0o~)moZe~7)Vo0OBq8IXw@fEOdS~`N0)Uero1zpNQ&{5F(gmSgd+xz zrHD-vylZ6^+;7VVa$F*GH`a&`_^Q{}sdJ?V#7c#E!dRzFo@%BYj!dHPGlML=6!A`d z6~9=Sg;sI*g{5<=E#X2-P{!%#aT!od7URDZ~E;kIq zlNZyr?&i5^5=BV|3Z7ntMTGg`mJhq4(_JBWLW>@BF@Npi%hRi}fC!JW5^azjEd$yT zs^_W$+OySIsQ-NrvL`sepu#YxssMC5d~x+%RaQ07e_u%#%P*unPI$Kd$NN@gL0S)A zeyb`A)g^jJfPUqR156P)19jP6YSy3Kjr>29i9Fzr>M9L$jxLm5CwJXj6142t22^BE zgUq!{;AXdK%&7Yne#fS2=uNy(_AKZg_OPVUCC?0jiCwn#?KJwjUs1n>Y4hW-WvF>= zpx3A7>=>98-U8Av3;yF+ax&Q_f zE^+nxiayor2eOJ7^Cj)w4%&s~upfg)HH8l zmyHGO!9JGEM9qFTD+MhJ&49GUi~3)(wZRtJ0WZ9P9K&A0aa$cO&;@*iVa zwDuzxuBpj->LT2XyiZM5H>5uLl9XvD++kaia}L*+jv%fAz|iQcnygDe%!h;!0;k^c zFzk(0zZ;!La4lA+dp92Ga9 zmk`F+KJ-KLf5Q2K@dw=WGDiMIEfx^gO87&V?ZoqQ)B{jIE&7L+$Z@F_t5KusXbBP% zJ#jzw6d*TWAo;>abkaTH&|dU4@*1^SXqL=3@_*%9=u1^0JXg0pqX>R8cZ`}pKO!o` z4QB;~gMAF`&5}(mQ=Fy#wvl?u4ClJh@1cnm#*21lqq#G{7UIqi{~=nDObvRJc@MOT zu8Fg1oFc#L39RV#gD~$dj*w##|3btQ|smCzDG-9$N>^G+e8y z;^vW#hS9Bu5LMOh-=~V5&>0p{#q`61^Sg<5Rh$Lwx2vKbOfsqBeD#2=}SWVs!~FIMq{^b?~%U4bU>TkIuo5T2U91C&#S@zOOEeajip9 z59+eTb+(AkFE`Q!-UBQ(6t81fj3Dyt~-quA}wYdDm|!|ECRD zMO`V3a=&c=fj;s!?z!E7b<&g$ICaLFBu);P4_dLKC!TfH9(UtQ;#p_c-X~G;Njw{^ z3E=}8vFc3?Opdvew!k2XLQuEWAd>R}vs8jSXP0G*bId zBNJN@Pu`UWo&r=e_MqsDd{rWg&}Iza-?w5Rwcc!bmzqbZU?G2VelyA;1Rk#zXHYpcaEYWx>32Sm7(pU7B8e|M;!Df{n z@sOM?@#LXft@V6!3szOrng7&+h1R@Y!@);QC`a7QR)n=PJ&)+EgBd1mleP31hxz|A z@TiuonqS!`2A4zK!_@PEVD5>54{8YmH}M0Z0b1|%{8CHi7Y=Ae<i8l4uYXdKvOxoK^(mr!7@0QGJWKq^43cp|t)g_Aber<5s;f;FFIS@(e zq|K~Ja-tyGq*dPtj*|!sKt_kLOTbr)+P=6Yohq zc|-~eFYmdAgfd4Mn&kXBk?T7lFTRCdo4mtR=mF=N*`TL=OA?0$Uw&oa)mpPK&0T({ zHE7CQ&4;xXG);dhX{sG(FZJ_v5-&={zXDBemPqQHat_0p6DuTkx>6;q8>_gcjezwK zss#R`^i6F9-1 z3-eBU1RUy9zPm61ZFa15=#NtyUzKDdtVgN}Y{Lrx^Rz4=U^#~|EGf$4zHXA-HUgkS z_Irzx+xxMUVzQSV!%z9D6w4BZQblye3MWJ;Per8Jj43Ib>@i&TDfg{Ix(_N;uVJTX?rLapp9dW5KSIai~%N|)MmT-v7g z9HoJ%<}b9tR$3}JBCp}ai{stpRg$Dz_67|)v;zwZIc`h;^Qk0RD%T05cj&-EbY<=v z_=paee|m7wz!!I5BelESxkpD99&b2fo?K7qts5URi7p8sRLN1nzXp2hEyxw z0Vqh$4%LR!zzlPmkI`K6Hj4yDv4o^Ag_plMg2o)O&%?cD4-EWCCwRSv-wfQpGpnp? zj6hOnrq@mN!W4IB790HR4kSaaYg0@m)cl3&m2jFp`O400gwA-!!2P;lT+|SO7G1D{ z6M(=_3Ov1S;Q18z9)ay$Ft_p*0+%T82?9?jFam)xT@h%DK+UeKz}55vF0M$QUfZ8r zy0XyV3AYT;p`N#kcE}x(JG>isCIa^ay*=09zuKfGMS< zJ>^ZH9cDkIIHR9P=xPUByEB%0Bo6lRI%W;jMA^vw3JorW4dMC!YOp1cWXxl#VK`pis^5=z3$1Ibr9@&0 zUatqM*m%z$C|e!Y(ot4uSRj=RuWLOJhz0P|Hz~v;aw# z8am#gCkt+Jxi;eGgDRCtX>2|vK&u3j4h}$qx+hgoV3tU#`-_2Z=*hyhyDRZi`1ODE zvwMN2vU_5eW1p|R?}a1<1B zY(hY#L~@aY3u%5b@P56SzE%LG(B(K-s*!~(G=W-#$w>rwsmN0g<<|FRwRNwq8~DxM ztgNIyiCQ1pK=i(A%&a6k%FptceGie&8qJYRi z4CC?-sCt#C4CTU@>syRFd)7QjDAHie(PX5c&fvP$l0 z$ZB48=_SA0m*vMcY61Df{Y%HZFC0h1J zX!x)FFyT@~U_w9N4uH^=pig!0k6k#sn)4g|SWw@U_6#FMhE3?DQ%<&UN275`$@$0^ z3;w;am{0u{o?-<>ZbO?p*h$)ZiBv(I{OM|k^~p*?))&YM`m^fVn@#z}{w$>VQ(-P6UT`K-;6zW7Zx;n<~+WgATEp`id~&IE=#t7d@K$ z+gM9Rd72}@?m+L5M1p{EUMhOiq+M>7N$3{$wWt0UJho3I)p(w2iraDt$<}KQCX9~^ z{O&+jPj~tEmpptBtE26e$PZ?)5bel3K5`Izc$^3(zhkd}<-O`#btu&Qrh)Gt#9C=f z{m5MhW7cYB6FzDn3rt-xOS0-r>ikL$QcHDHhijkRAQgo7pNtxq6$k@pf{9l*ZGb7a zNC~lN{Cgl)cY^rnsY+8VKup@DwWJq?bGEUdEakVE?^1TPqJuKseN~7*p%FtpEF}SF zR<2}S?j<3z3=*979SKKQ zot?q-F-^`p3A(2qJw(mFEVD>k<$R5-TDQlIM8#*hs?<1F;ETv2TJU9OwGLmRO9iy# z{AEJP1Qqw-NT5-Ou)9i8dKyvm8*+nuYEEb`Kfa=l0|N$XRphyELc!!be}pb0BQX-> zMa4FgA25`4)9pKF;Kzru!F9IhIs^uTx1j=2=e@EqxxAkW@z9(i*-g<{;3}fS>^qEA z(LUAlIm1{*?HN7aIgHiR-NMMpJdAbHC7m_!#s*e7)c>q(^dyxX8lr+iR()rTadQkT zHstgf%7FQ$Ah;#c?IBF&JLUO#1M8yec?Q#SMhrEg5$I;bz`_-Q$rQMK+Q7d+AnU+s z*p8h4Tr(#Tg6n!nAb;0w82o+d!sl2f)7>(AQhI&dP=WMBIPGfs6q#NkvmvD~4if1F zn9owvd&~5anIV+^GFYU$K+rNhRNn|0Xn;kkw2u;~>oA2!fxw=_*)-j>Z(s78!!fQJ zaf+OR_Q>u$)0m8Wl}0dDF%HQ^N6k2tfl>3=ld=YddG+PPN5DDB01!(IwN2saAJN!7 zkc#N2Ek5>?b&eD-q{!?G9FZ^3uUT$GP%>qLBjpCAoS+o2EovpcENNN7&Jsg{!ADDw zYgvbM+WuzClE))QvY52K3QSOrBTcrV?dT|J#4!2Ozhj9MX?q=M)K1LZshEdI zT7KNXn~q|YS$FhimYO1Nkj$R6M<}j9^mRC&Gl~Ug?dfOpwzpUZ%NymeE99zl{X!gQ zgw!^cAuDl@UVw^r$<*7YM6j0*8}QJQkBK?d%u1ArG>mNcKVHK5^qD@~3fXvB^~aD4 zVgWTRa(U!v792hj9c`gb6_wD9YCedmZPiad2F)AIqB?XzA$yillL5D|wABhi>TAcA zN;YA?fqAw!)hV!cM(Xei(&bx|PA;E<(pG&i{@PbX`Nh#}rt6mr;pz1HkfrLb9(>6+ ze#mO+3XU51tq)m->-hypn-bfIal;tq8P*oVPME0))rHNb;WD93#7(ic4SN=hVY9T} zza4vtzWZ*fDWUsew1jc2gYMp$mwYk>w(Wb#FN|X&G);Kp@vK4Gbl5;)FE*c(ZGtox z`|I&VGl>_Y)Y<0`Z259U%I3%kXwPIw!Rc){gjRhg*uP`rS;vqQ1#2_U@JSO{NcgN%a>0k3JB(#PSAxHwE3_nL zo3>8`U3Fjx&rW19z4l^6Ntm)BV_Mf?Fn#n*ECciDOlSUb<%4`ko+Xnfy?851&%>w0 z^o2Ml>|F_Se^LUAV4#LhV%2r`_Z#@3 zr6_IbDFdG}ne{7EV=pb;*ah==G=Df5t2bqN=oA(jvgnnA9B{ot9GCSzl?PhdPhtM$ z7Tav0pnj)NtbNI1?&ZI4418`KL$Dri0`4nnVh`;z@NHADsbmZCT%N)@h3pyaES0#e zzCybGcWkx3_Jo1=_=u&3)GL~?hRj&~f-Pf3Wc=wPmZF_qiBFrx!r9VM1bI%R)TcR- zqq<+7uxT~b)S85_8L)51EsD|&K%BqF@J+cV3 zf0h=7|N7acdUw&_!?IYMwpT?#M1)Zka1fDQl!)`md_JfsCE-kjYRQ_80i0`Da9l5s z;9l9Raw%_#Xt*uI8Z`5s*{pnG_GMYQ7oosb{mP^AOSZ--_)5(ED>H)lpeAY6cd%s_ zUt<8}KsJleT;SQ$uBX0>m|^BT2DnAvHUv{j)z6~d^v|1Ek~er z%@I<9w^B{QX*`@4pbE6@T1q&s63%(JG=jf!ua6L%5|%9L9*e=4TS16Ui<_Eme=OE* zwnJ-QqG zaDt}t`wtUMUX~^jmRL@5=BB-p2sT6rV$1IvRun<~q6p6JRS{%+2oB0lRXJ!h{t$6cI@yFpr^HzqniDRf$CNeS z^LtfMM9oh@R?-S-gS#FA$Xu4>@g4j`Tpe0}JnwL%ksmKNot4PC_%(Xs%XU8|rqJHe zegcLpd+jMcj+9JFS%DPviiJtGu2I;ZFAvHY$9~)Fz5|&lvqpnH6SIgZ#o|kQc*u^C z%&9q*Z=cTmv&JvP2v7wf>6}Kz ze-h2Mu~TuP^QQH!)pAfIRoIFqI)hc!{R-n>ID>^&D2;N3KM6IUiT>m$qT~&cZf>X28&B7OSA^g1#HO|A+Fkv)BTivcA zsPDthTiXuIzd|UtegM=^okqJ3-LOxit@`^d+?yBXv#p4#7MtFgxWbJ<(aC)4Y*xv; zBIf_pvuvS}e7lJS^Eb1ZpO-1T4a9;uhk={0ie+MXUfqSKhRna4)A%+MtA;!u9T0gI zZ8UI;iOuwygQ-Oo+B8084(6k}mbda{+gMO)Jk2^%drdXfKg3YuxTDBi5s_kyM<2oX z$e!H5C3A&6U$mOJH@}DT8UGFEaS#k_sORQ8Rt($n-U3;_W`cz;Z9l<+@K;e{F@X+;c9A@V$ z(0p9s4d${oy6dobGv~68UAJbyr}du4nEpaJk;^c0)6q!;FYvQ%_$%^Smb=LM{>|1dSFW1w2hhs$fakFr_EV|-3^pkgYABJ&Q!J~_F(6;dyC4A!BpRw{d zfUaA_DuiCcQUIOMic8KDrOU|D7y3iMNsE}DE(is>En+Nq`a{`DZ^Rebb`Ry9w}=ha zuGRCGix?ih`i)G?b<%O#s$F}Ope7MNye7vIYDHMf6b^~i;xJKRo|i|84A<}@GaQHU z!;`&Lb&JYc`G_qnya{e2XrA}VY^BvWVm5<3TNQpQS^QZ#Ne+jURDRJT$x%>4K#N<< zx@m8h;h!vK<+XqM@vj%NuC5nxHz4;~!m4SXmE-YCunTP*AF_nC!V$f#OR$M=br}D7 z3G1x=O5w4evwk7Xmcpo;#=oR({g+crP1L7)sxCF~O`kJ^_PI9?TFTnEpTJR?ya$E% z`Cm&|B%iw!hxjJ&T}xSa-N_{e?z@cn>$V|KX&Kg2CL!>_GFDe>3FeiPY)^{TU)t0ltu6e)UiIx?sSrWg#9DA;w|IDLT;6PvW&xo$Fni=?jFW3i~ z-u%cHY$T3V)+}IA)y}1!geqX)vpLKivV&I^!DI)md5{3WWry) zaTS@k*7w8dulbEHS+Hg|Z@ZF(H!R(TC|ago_60c9;dCNU_%*3enhGenk+Gsp3q5k{ zE6Qi>Y5kt^Z`@@0Iw)_+|Jy3>SOpy&Ku6)gWQ_Ra{9~@*AEU{TMZ_9LScD-z?s602 zjx00g^Mr^t5J-wK-^!7!l_$7(Gn@(}6iz#hDF=CLZGOV#UXWn2O8o0*R8qwxmDGC< zk66XR``t?+;+=(9RiKeE=DxrrZr{oUJW)I5UlAo%$Bd#ets5ZP%8Gp|x#DbE(q2r| zq2IiC0JD9oXz$OSW2>-9wOs5E@KtV#wEOemnT$|3ii;Yn%}cFeRg)LpL!Oz$6diq0 z3Aywf{>oVA7%SR-;Q*}J5gf`(m%+@wC7p@is^YN5)HRrt-;eD^`0Y~`*$5g{pg9c> zdQgz0pG!{5EBv*aGW+G3n+AbB_3}&#I$fT*c)p_m?&4>4z1Kpc)vkM~yL1Gm ztQC&H*)K&We{ZgVFI~&>ysyK}Qgfa!$!o4-RpANzS0FM4Ak)xw@C3XZnKb;(Iu_(@ zhE}S@Zj|5=>sesUV~(hA5KJ2|bs*gv5SnVLa3~f+q#n1xk>|4#eCT>s->a7+sy*Mb zo&|Z;bHr5Tmk^WX=ZJAfFwHcsJ9cpRF@+w=5Os9ZTnLS!$ID-@IIJRiH zObMp=L-hq6Z_VG~+wOww!bei})S)guxtIzO`4ZK9pNo8?Lgdrr^HCdENa+uq3lHLp zH?X)0>sC+~IK_U|0Ycc=jYxY%p4;cH z_7u82cOmI=Zy0WGkYIZ#8y(emI}CiwW-Jx{V13KaZe}5#t7M4{_~DN?Gkxfg9q`k? zK`}f;6z#M7UlK~*ndW&%%pY;Kh537SmL>X9i6&c^J}3w!3WtlVlutePWzlfs7FMy& zFh4Y1^o1>Loy+|mg2w*pQwBB~sdEvX>4vWj{KOVktNzX)vOvPCON}f|$59x4M#HxF zG@(Y1W6i=4Q$y(XuWS%=C%opdU$KDtga3EwBaMrf_E1YFq4ZRgZj^CN_REJWkk_Ez zL#x{WvC5`Y^@E~K$vn$ZWuhs0J;(S&)$~Gsdn*g!Rkwa@io&)^vb9=wfZYX;!9f9w%Ue*2bh-oPTFm!TJVM{Q;zvZ$7vTeO|E_aFEz z@c`#aiV)k)za7k*XzB;>N!wY|i1x=Qd5-KoPP#_I4BpFX)|9UV#B>aLp~YnhouGm zI3U<{D;5x%>|inVo0C?)U$?$!P+U76U?@d8ri^*b3wAJnujEToI||CdNFUz8ss&!C z;{{HelZM__mDFwWlt=tXkHLO1ZkOCdVxqXKbR4E_^c}FuNV7L^cu(fRuIC&}rbk5* zce16L?cDcG>p=c&C)T#QPlH#pi#2ooF8hs@PYd-6;)il0JowyQY-YoI8nF@SP!{#O zqNkY$X_{*wp2)2fMt#GVNX0F)cv`kzgOZ59P8ZMe_Pbe!7W=bFi|*4|JoilO5!r$7 z{is!WQdrD)uSXO~_*_cfFJXECc_2H>)0zjC?+xnRsBdB|^n- zENGaGU3t&z;_lmr;y70o6zjZ)b!@jgWUz}|n4kxf*;HZ#UhYZrawHVdWygjKoR7Qi zMtb!OJKB79&sZ!b)x52pV2}RU!^ZS83NW}d0QYs*Cw~K%AH1bAKE04I?O&HOpU02I zwbF>M`5c!UAhIwJce0#6gmyr&xX_^HX{&xXfkA(pNP3P*{`J6v$FO#PWZ?pvANkpDSa9jXg;X?ckprQu0;9GfAWCbtqZWExG!qkVMzTDm%W1(;98lsdMPO)>D@`*45CnG$&4 zYadJVTs4U(pB!Xf`II->4-dG*Bm*Bg(irMl8!2gd)#)u0KC(*pP=0bhi)r=g0aBC| zqEy06@v#ISG?`V6{zTIsdbgK06xFyYwQkQu`+N*Z#$0a@@9F1r1hT*K_F{c1zQMXr?h&Gh z_J-9@&98QI(qP`;IGe2No_Ck;InE+=H4(UZob}bm2a^re*Po6lvLL`ggBWMv9Z#?g zx-zrw^0y~gs%8{#bCT5y-YY6PnBjyoyW&n9B z5o4j48!{$M#9W}5voa=L#2lxXZ_2pvTc=on_j-+s#SfbW@RWklz_q6_I3B@UpJqzs z9lv0x5``y#jB-41yfDb(M(D9caV7?SqShXmr<~F7`uCF}m2l* zFJNB-&;k77zgEGIFtb8w&l#u*Rv?|VC?fZFhyir8R$84i57_0X(D7-G3N;{{y}vT% zwOumtK-B*0)b8uL8#w?dl)mOY>eP?{b39Igvs1 zi6_g>%HV@|4&a!5@O~bGvbq;OkV+7L9p%s@#VDvd$#I0; z3ROGLjB)WpiSg!<>F6pl$oQvYj}>(lm60I33ZLn3(KC ztWD6~3;@aBzuJqk?G(3yVk1ljHcXy%t-{BDkNKVt@sI)o-(A$WB%NsCqDfLOT6&U?_Ne7|qSnf~DdvhWu8N_LlP3T3< z@wYWDDSXC7hL;cB-VVZ^M;(zg}Vt zhqDeMsJYAn^(OC-K~zaN>?5qD_j=5B@M@QF;nT@AgL(JMEFr1JK(w$hY(kuV+9%f^ zzsaVA9K>1m`S^<~WTs=wh1K%!e;B3ZyG`6IJNk6BqfY^i^Jn z-2qV@&!4+@*pMdN(c$(9h@#RJMHEyN6cl@nVngpRQ6t6{1%t+r6JupHc4K01(TGay zu_Uo3#u8&UdIZH9yWa0J`|c3T_s1W{yxG~=+1=UM+1Y*j_+P){<-v&y_~YO8tpoN9 zz;JX!2VXVkMzazR@xVNB^5QskUxK*x(HJ7B1z5ylgIy|kC)mF z$l{a!(4Wsy!U|swG1)AFYFM;afKpx3yQ#kC+DrO+4d(ZTSu)iREHT(L=b1Sl zSceW< z6uXSs`Hp!&TQz3SwJ;)>JxyY|!0{>&V-8;ftQzVCG0kgRtA$9VO<=x|Y|%~^zf%;x z<)Sc%LNeOKNhQ^RgW4H%iXm1jhPdwUn8Gm>J(Kfd?Xul+i^E~PRLVgtPje{NbdZ2> zn4KYkr`g;@8N{{9dXx`hRN=n)Tr_`vSs$IV26(Fn0lT;#In9o4?*}`M>_O4vfN2)Xn>H~DYrgu^WeBYJ2;35v!(uap#tt-q^h$P~qZP%=##Ot_q zp@zO2)~q`audc$kW;fLGZ8!8|+?pZlJ~9|qzd5>V7LU6LheGO~$%o(6`-Wt%qS!TJ z(eQV%DEsV3Wlu!nS9zU%qx1Nt-ht7EluqVIsVpf)l3Kj(SyI?fqX=e!)<*~ zWM2!ZLUF7xS~%kl5q7UZ9pG$Dzca-dGaa$=+h+!a6bEwK3ub%p$64T^*`2G zi-D47k!XXvr}H!lGg!1U+E?z1sqJwjpj031-lscF;7aph4u^q8O3+=LxsPa<#XH>9 zzw$683sJ^_QQ}?_Q_d%#y$NpDFi@|GJT8`-o&x!t1^8zm9(Hu z7Qb^JcTk>Af*pFG&(XZ}fsm08^T9YchgMlU`>{S=wU2-QSZ~zq_XLst zi9TDCLC}IH`bL^|fQo*5qF9^O-X+U%t^d%871@dE$HQbdu_l4&rpXqI>ae z#0N+mC*)?Ly7tBRM_VtHxHl9{VA0x9-cOKMneUWk-OVOI4geA}Le6-aAV$Ta@vssT z55tuQd-2dC7H)k>j6(c)91*7>y`;8+c_A=SgmG0ccLb&`VNg7@g|=kl7fz#`4umZc z*x_`nK_nH5qz8?Wbn;z>VFG&t*qoA`@8uXG(vDJ&B_e5XU_vVHiL`Oliu7faKIwm@ z|2vh0nNH~+yh|6t$Rg`tN@{6M$^mbYR#l{RqO>|9?OloPf@4EUs`*~h3oL7K7b_(_ z#L}yxoJT~`^F~NI_g>O^k@Pnu@gFVv@Q&C{E3J;p>td`SjeFTa$pz6H(aCnZN!!Ve z;~c~Rq?bA%=utx90SbN;C_~cR|6|ObpF%i%c_JojejH1Xdg1?M7Tr!prjiX-dJ~Rd z)A9#KYYi#u#yZGHA5g*jkHj2T@`#yk3>@83mx?9ay!v|nYZfMLjm8T(DyEZn{)%hO z!7mx+!QAHruD*`5X!D{)4QPJ!oX0a&EJWRWE1#uei5`<_`oJ3is80Euawk{CJ1q#) z@;53L-S0yctXXtmX#`#lh@v^l6r>THq9IVhA&8BR)*zp`ao(cT)Yl}a_At8236HRjbNll;saIF+}n$-L_&kA7y^ ztA~tMe;2Pfd;k(m@M<(Wjq&0&um|S-vxYL4{7?$7Tw5GKef9%>h2O!$b*#4LZ@RFuhmNh3T48p1 ztz*O8UV~y^$h&5F5`fr;2aEId#{u@_{5-KzHH}WD;dTvV;OUP8z#gob)bHed?&`@r zU2ywKrt`?tWtq?WKUh3GRUYp2rDDeRY(EcGX=RLFdF+bMM6XBo| zwVtZC--EIj&!WP&f5j&@WT{R25e{x=wcMTAWRtS%Qgdt}Enal}9!vo~UWNzZ9y-~Q zEZUATJSTq^Et$yTt8kz~2DN}Y5x|;CNr_NO zJ&TdjJn(LYo+V0W60-Q`dN!$M$#ZM#3SWDF~zAT8ulp|L z@o)5a37*8N`*r!2m>4*Rg?dM#{5X0o}@Iy9j+ zgw=Dt*Dce|*|n|9W9Jd}XS!t;bqHa8s``mNp3`d`;dqlxX_ySihPelCDT@G=p(g1C zwOG}$JfJ~SPrkV>t0D!|%;G!ivX-#}9nk@2G22182H%JJMvw;G?NddB2yk0;wdB0w zWEf?;Y)9x9K`>~JSv;~Hi^q*VBkQqxnx+m}c6{q#CQI%PS^Q8vCOcdDU>uq>YQ#{s zKf>60QV-n`#Qj1UUHsDy#m9%THcfgRdLdl-5b%X7UuCo6%DX_-$aA`eaxL1kU{C5v zSo6_dLNq>QTWdFdDwNfd9#_xew?bL0v=cx;eRKoki4B;WugQL+J965#b`YuhkJ<#m%!!1W4OlcEP@lQu zo46<4{%2t$cEaO?48kN8#0)O|PYL%R_nZc-j?@E2VtB`P?sE$_)9~KnLnx^q#eeFNPfT=!=SvcfiZ#eQ^)vG%##uP?Rk5Px;jEcj@&><2k?cEZ zt2&DZN3j6uD*(w+Y?7wYEpYugifstIqlQ}bLQsu1ByZrM!iJ=<5$BL+VKnoVj;f%E z(X3P3E|ldkVw>45u_s7b#Ey#i5xX)ify400K8dw`DYQNQ(N)^))=o&oMn#a&l*Sqa z!D5(B(t)cXhPC$JtO8d?T(P~n4i8p-FjK2Q^J@&#OSA28@lFhDCAC6FL^ooYs!@DV zBQ^kM`Q9{Q?GRDyV=+RTt#PqeC<<@+S?c2SabwgV)?(y2jal6Y9Rdi-m7QG!6QKB- ztquZ_OpB^?AOg|_0-rw9gx#kN{i_yjj}U|;n=tptLbY8<*XK0XIaNn5T%cD~P4RLF zP4Tba7)AUpgaUFJ(7-%a%i`Ueu%6B{t6^q@a~=HJNEPJ+8hGj?)oUX^*Mubm7%}I; zGX+2VloG+aA=&$lk;gP;M$c}q&|$*tJstx3JfR&SuZ+B?DXZ=DJs6ktMa2=TeQD(8 zrYu4#2H+cq5tIj@YaC1RYCw(-8nPr4js`Rk8xttZ+-xZSK922F_2ya4m`_xP7gUnX z%Xt3Mi0$3CB|AldO_7FpZ?fgrY}d4c$q6)Nws}>?cQs>;T>pMfq_<19)*(5rJ~tM| zGhI+`6_8I#Z@)LgtQN#?sZ~}zH}bf6=H(fSvXWuyUChlpp^iy{&uF9$kH@fY2cRIH zbyI(!QtZbc&y2!;G|Ik4%K)uJQe1-W zU_vfIy*kf~HkTl~Izme!X1`FyF|2kZcO;q?jyPhDb1{3JZ_d)y_Mh;&E!ZIG8pFF< zEm%{xMPRTm8AVzh+qvNUR|__wjz2lA`C^0mNZxowJ6}EpafO)Bqo+nbDS;)cc~^ck z0d86Ke~r9NB5N710VVl7v1BQng=>S2VvP1USFjc1Vn<#sxE{DBVHDoGLJ znwD%vV#pKd+Sjk}QfK~8#n4#0Y(18rK)y3XT09BA;9ne#rgJ3uSFsim$2)2~Hu5p8 z*cjCW(05xi zKWX$sBd?jnzLbstSeV4>yDxiaB}~b`ENBanaxsYoNs}KKi&SlxS?xBlta68qE;AOr zPG)Mg^f^2?ReLr^+Vzi-7q(|DrR}9geyKg2QNj2xk9%qw{T%t_+YpH$hSgvXj}|AnwZxU3R=g@YKwO3_A`MSId?LCp95)bz@z zqp6yxEZWClJ0lHi#>O;}rm=MP6fb{Hvp7#12yPZ_yOPRk)DrX!I^qW9!1{NU?SyLcUY(7SN3$2(y(uY;#}uM-QFnv@y2t~2Zvxbb$KK~wa=$VYZ&!5$}X8UHiQ9t5Y2oiWF4 zzKI%jX04?!;9+`nVM+dWATRkCt1g-uU)?OP4aUm9Aa>~x;^ly2J3A5q*^qhsJ zvuN8w8kZg{1T(7fDveX?jH>MH_;rUv)u{(&)V5bqr5;#?ZR68>upo6f=bL&kAFavW z6|G+G&=uIX{TCZgS9+ioeDs(^d$Puv`B!X{=q;fta2rM6HxUKWi!TLR=oTh2Pcb`j z4p~{gj6tyKnfa%iWEvGBTI~}qy!*3qBE^(kxo+eudNOZyr!c;!CySK+{>#X>j_Ri4 z_it3G;fQ>~dBP=mzz6hV_1sN=LF|I!V^AJ*Tm3VXv26{%R@K3qkDn+z)aZ=lBYB@9 zBfqM3_wjB({oW&nBU~QzOmyE*3=i~yNY|0}yS6P!4 z9fEch6cfVi^AkR!`yC-n)l%|1CYQW~RjL?=9C#TT(d?EDN#g<0MMBmoN0P)F1jUCBAZV4uxJ%wW6eNSHM0(@tIti zRD5Xhmn-xU+AAd+P(Av;N>sD!1tT|ofN`nE46yG5D6tBdD<3egmVd*%m-fMFlk@nW zLH-J9SaQM6<>+uTPqI#%K#*RVZ#R605D}+u+wms-SQ}L_&+UhpO)<1&e?R8I_x5A4 zs@?oqKh`Di(QlZuOsQ~I(hzO2Xg@nATqm1}H2;QlzW)Q}&OhtVJXL1Cs6PvpoX#2f z&;40L=?^s5O9F<&Cl1YkPrvRDBTvhKg-!x6Cj)VlDge%8z(G2B7A9^0fIYiOgBbgr`27#j>h(*@b16Vid!tX|I8GteL4S?u@ ztU>tb-_cCA+YLm%Uf7K&Z6r9+Lbe?qsbXaF&5rx|?18XHDmdYr20|Meg3r$bSv~3c zZ$|!fAgt*+)G}xgfL3qe*$rZPytOfA5M!zzI3I)tHNe{J9mKp;b@>H6t6c*5+d<4j zy<0_tSH~xR(yaz>JeWDV%{)W;sdSzg%Sl?^YcN`(%^4$~Js1sppRXH?0Dub5=LR!> z-vz%>4)|I}@+LuCyOPrv$kjb_+Guxt?iPEWFq3^-XddlL;nleqr!S5Ok3ug_RpX-% zlpP+1-dq>KO|$^Nr}K^1#UuN>J#{f**E?;Tn^vVxGrRvL-8*FzhU~-PV%^#l@E#ef87QeB2%5t??|$eRvfZDb8twZ<-Zim7b|38+sg7z-h7uI}HbjC|z~ zRCX7DlgOzao5Pj9i5{D z;|O<5E2W1T`SN8(R#p0>W+qP`jrHM$UyS^|kp*hT5Dj$rZ9=%1m!!Y zM`**PM~vKSgpfLi=+JOhsW%&KQm?A2NL{-oD3nEQ3f_XWXcyzTq8#(U?9vFxQU5+q z9LX~9HQp)EMw;XmrZIknimx|Ibk4j$ig6;Yf7r->9SI}m24C;RNcfs-7eRiXQLM41 zA3@zmu?DC~z)!ZC;7Chj-=5dtWps8fgd(mgPXm+daTnF*Yu~?Oy`O(O$jAMPJ-usMv$T)V) zwecPZQVpa+86)->dGqnCKr*1gPL5}jB?J_B#|bQ4{cjncG68KGz8f>a1UA>LUNH&@ zr$Q(@j@A`p2AYVlUdPu%ioTf0TvRouEJEyz4hLS^1qbm-Pc7f|DVyo)x2s~A9!Tps ziDgPx&`bv=u{jPe{OQ>JeRG7SI`21``33jdL4CGCd2J4xKsuyav^OC-ohud(S0MR{ z$?&`Sv%?24@UkVIo?lN10XDiv9PH>kaL1yJ{d(j^sTw~7kEzrVf9?pK&(B* z5}KaO&P#bt4r^6^Aob@3+wxu<4zO$|aqyWJk;Q=wegc*h5Wg&kHJ8?GHx`BEqW2+ebgv?u-IftUsfK^K%qYq#kpiS?N>R1Fwf?m5}UmYnfCTgl4uHd9P_KM|!;p z!*?1c*AoD0e9ro5#(fT}Jp6OEKqc+mY~)qHU@bJ8rh;9&FIa@znXPEE=)2-=FLLne zg3-(`n0HR0Ge4j2&OdjGUB#Lw0(RZ!Qk+EU=}Nw6oDxw%$MaE(S|5AlQNEZ57~*3 z8H7}ZC{E)vCsdj$hcqg_mf$y-_{AwD*a=K;!qg=UzGMj>Al^%$;|N`=0$MH5^$AT; zQl%oKX%_8yLf!_LjFY~2*C^iq3AN4hbwHm&{mWUezDM}$gx^_#{DC;B^c$g92(%)| zctKrE=r1c!|0$>!16}%wt-vD!H;Zrs>5Ut`E#WW{(s9U-Qc^0VY!F%cQ375{sgUK6 zNJydtk4g#aL_**?BOh&I!z9&OECNg{Ubkz_e+=|@Ym7W%2J_WTe=iO3glwb@n!$!k zjsSj}fiS}FtBqV!0AK}xMg^>^)DA#F0c#!Lup0W6Pw%Et1tT8#LM#OCe+R2o zz*05(RtUu<%w$F>5~z(c!Rh(8Mt*fBi*@}L0*ISI#P}KknM1xp`ZT2X{)+wTQ?!ak z*;etpUi^M5ewVGnx^os=>M|1pMtFwM1#@EQYhE@Bv7-auAXYJ(g*JYL@lz^`byf(} z07mw-c&LqsQhZ}|;x|eKlzRa86O*0);BBji$??8Y0=V$mtYHUdqOw`qf5ud{w9eCx zQ}-h|7yr$ROjzsgCJeR9w0mQ8l`QU0D~;T34vVgL8MdVKCXV^7R3ylB4w#Bu$cLD1 ztu(xPkB@oXF*m$i#z)OzAr5h%D;VPz)nF!E35qm#}o!@_4io9g!`W}`IIW_r)1q#qU;!~`l1 zCOa`PbSz|neizLTiAjjCvKafbX#$IbT_gE$-vNtq88{hsDgVxH%mjAk*Bc)4-wWX| zJgs`4*X68^%kipo55NO_QQW0;Zh5ANHSo}o32k6!u5Zf}Y|Hez%6pl@7qC{zFIH8^ zl)4@pyLc}s1B;-YpDH4d9ZSuBXb!igwMN=fYZ?~$=-P{B_w^5X@dDOMs#fJb_gKgR zwb$*j-DVTd*6uugA!{DaCz8#DYpm2RY@JeOTku^{o@C?fy6z$0d!u77wf%kWb+cno zEsd4$d>d1IBaG^Cab<;i)L;9q9t$Q^u7`^?jq0(%nuaZNQIDyst@SWV)_NR}{@;4s z7+He4_7l$S3;# zuIhhvWAkxJChYaunfqFsl)5p@nt;#nif&A>rcw2oHI1~4x>56;wffKPtkpkb_rIzy z#9TO5DG{62cIFuutYQWuCyCkmwWX|*idI@j_JnOo$$x@nB))2~2+q(BHN6b55UrI~ zFqUF~a4r`a`QT-&z8dCl&N7yzKGmFCmN5@07ztj>S&E+;Ig=uu;+T9h=g%fXPa`aQ z6WXU@uy27y%vp{FubvzEvgPoM4PV3AU(P)0dB9|rQ21DQ#))6UZXo~1j^%lu!oGoP z$!5OwpG05YX9bJvYO=pOpDYt?XcWX`4pCM@3E)Bzf^ZxtnTHrl-cdbm+Y(xwGI805 zJSO`ybLpRTA$*dW8W#k>b^m7t^Yz|@M5_97fsa$(gK%6o29BD3C5s67_3RLoJ45-v zG~Sa9p@(o$u%q+&A$;UY7F|~lCd%S&9@vPAZCvo5iVcLZJh2i%=&<>ij8-zQlzY*n z!P>6p;Qi1fkC$YT%^9w5dtLMmCfYu_+;(Vfq}L9pXERy?&=u`%eGf96njC2(U9pDDp5wBTcn z-5f&xl)NKwb+!w%(5>JfsY~on&7yzSo;ip-I1}s!&UaTaKkxNOq@I}zJT9cL_RPtT z(KEHbML^)pnIXKxw>VUzJv)ROzh%+wgOQ_DGwtUwxbEgEPHvIPRMxHG%YdSFh4}`~ zAw=xQoof%kzE5Jm#QuliE&F2eg)d>wGV+pdnXf~SP>R5aKko7!bJsk`gi{~#9b#u1 z4M3i{8b_cy&c-r#HLI@~Hv}m2YF4Q3m&9||Fh8$kaXrAhmC6evKhdZbu3IXdmysiT*q2SAJ0H= za6M}lGO?v{66F{q#Zc>ZqViHpsld}OjXZxn3-g>>fX*%WK`+LGvPp_|&&M9idhCOF z=NpTLY+$w2(g&X#izaMh&T8rLR8(XO!$+5=8Tp|ttiZ>88Wy~ssIYaxTNBS>8MduH zzq;JsyAwhn>6ngimFMNJXfR^;OFUZ9cqXZk+~E)9?dF||?0xV3FWJ{ZfOA`Mtn1`w zh~IwCe53`y)cKy}X-*D6b8Pya)n@B|Q3|rFP%%bLBhUmEYM>L65c=aF$Re*x3MTqmtH6@Vmr%D?>`kru{*49`HStgEvG%X z);LyL{@C!e{GqY7jZ1Ds=1e$0 zIDiW;qoFm3n~d{;F;DwfAg1})e0+wD(s}A4iRTm}4B(lAiv0lK*<>TX_5+L7e2OdB zx#te{xzq@#6+6(No&fd%(7l{QAy+!|VcNEwUM(xI9}$+xAM8NHaQ7r5_bY<$xAS%x zUtNSPgH^y>Dq^2$T6F`<0XvyTgS%jmxaa+a`W0Y>hQ!sOX^dVSRQE%cZ+EhGjnmLz zbh4dB5FAoPVRJvFR{Z8Pka!WpIo|>RSB;C)3~&IOpyc3PY^~-_U$FUo7whg3ha8nU z4y%!{PvPh9W*%;iNUYf1_DC@9#_GTM1nea5X0_ecOsq_?e4>$`B8rRSF%Rx$%cRBt zmKU=m>Hat)Hy7hnXCyKg{Kzf@sL-UO=0dHH;?8*Jv+$4#?478!r|!XK;LTvZeh+5Y z?PC!D+=H$5E@O>F_4l$3DrwaiG~_;@S^;RbpPf@T?a$p0u&Lg+Mx$|X?d}4&sMI>k zU1+*`YCfLFzdyh-q=VT;u06Wn~i>IhpT<$q)> zdU}K`!`R_QUhQWDc)5#1QS#5Mu}U+$6>6LJ3yae{Z3*b$FL3ltMk9an3p=24E!y!b zYp?cvs|02qh$_vq4$;hE@KH{}=w)OY@#ZUwlIj82coI7!&H#>`#3s*`Ax8eONzNzPZ45 zsnjlhyx*S~sXcqc7yFYnk^*`gi+28r5VzNrt%_x=+-5nwjfH=)j$VH0N~&U2Z7u2n zHpBkHoVKOo|4P2z3tJq2F}eB%@B5ZLv;yK8e`5Bz-viqH7tHOC0DLa9R+`D-=*oeY zVgIrST6md7Xo3kkc^PrgZ&1t=0G^k7!XysGELU-B_E=BE9Ir6XUVoyw;2t?G6Yfz* z{G&i1)yL`~&77{T}{0|_&8<~)C`4v_tr`!HAY<7=z zDarqn!kUgTd*66# zdH7U3e1eCPo(io|VEPiK4KPCCa`xt;0WDf*;u)dPg$lYDq6<(kUIG(J7)M}I^9PHV zlp3<)dR9U|h0V30OA878rW?>#E18at__2f@Akc#YaUM`fQ;D=bl$IpYauob;D=AMZ z;Tyi6=cGsrr?gt{r+p^UYEs%$9C@S`C@(8hq&@G7GJM;cgt#cy}~f~K^mm5_$3IpX*WOKBU-!5wkf=Womib30%w@isOt>H*kz8~baH z9f(I&@v9QQuhOtxeiO}b8bH-Mm{(T-Xmp1~b{U?AQD+(*PB%G5CYvV4S`VRg6?kk~ zAIaU1$yA)nJ619nj9VfFA9%$t$wm9x6-d4X2`|3G_DLUiFcwWRv%V_nRXd!~D`As8 zC$yuotkFjMZxOTVg4;=u`td*Pn6xs*$m2`dKwK;k1#nd<8z7xZHWpR8%eJc3+p6*6 zGAv^rCK-!vm$6$ax37~h#cn|(TOHv!Nk)G80bAl8Ia`@xg}J8J40|EZ%!llTN}AdV z5!T17QPrqKWtq0+F>4$ZTbmq+JIWhah%5ZjQ3;JC<0>`UU;mIP>9(*-QU?)t@a2u3 zV4m2ru8fa(!kEj9b!AEnX^C|WwEPKc>s+9Jm)SfljX!JA2hAJXYL}qHC zU#;nQG0o2WT|XtUpS3E7kcdlN?}#g0&H2{UL^N&&vhJ~FwKZl zp;!~eFqbwom|}NR`_0f}mR+<7 zLU&zVnW|Sr)kN&?h2xh;ds>3J7%GNskMsS{SX})L*0!hCGjCVgehdY)7FZL!1;>l# zV;w6h);Hgk@lT&K=9cqaWyM0>_?G9at=ot37y_h2)*&z?9=mBTSnNkPaxet)e$tm; ziC7Yw_R4x{i|8%dS;$(7ea84@AjNB7sUnah~kR1L{mi+NEZzh39|Sc38F)SB1ol(-7#=Z-h&@FR_2$i zen>I|E)lDo{APjldO-^yDy>)$+lz|B0^k+gu)wB9-scrdavSRlok2Xm+OANr!b>IH zjD<0t&83^M@Vj0y*?Vs+%{~@$^FIc^YY-t24}ZYwd+*SD;$?tB6j1T^Ke z7Skt{&qdB=pNKR^%cqruNN;Bq;*AJW#0;}?P%`hLAc1*C8?LsX?5YX}&&nLGr|>ij z^UysIA4sk&^{RG!0&*sOCDI(fm{6%~LyEO*9hF_70ml6gRvUWpMk?H%m2uDYb@`rLe9-1-dHY!we#}Z@^4kLUiXzqt=xIrM)OO^nbc6pX&GCo z%xZ0|(*FR3swlmOl~qLzifh5Us3F9TWq)^%#mCziFcC3@ zf(pGLhPN^bcemhY?NN4&!olBKwsn*{x8ea+(0~56oE2=xK$KlY4o}=4E6VPbU8(=R zZYjzh)4pP}Z4{)H)nLU4zNd=p<=)-V<_FX_m01v#&ig5xtDeEVt+k+xJ64tJNM>Hf z8xyb>zyJc~0Wbk@L};blWoXM+TzAuPOI5k5lmLROM5zN%y&5R*7QUm5;IpgAe$v6h zGX4S5qy+$`6Yvp$tpv0Na0!5ucZF=pFZshGZd#>;2lLB#Sapyd0niJ8)8hH>N=SRf zJC#g!e9!c*hr+w0L}x5^shkL8Hb0CA5U=Jaa4I7<;z-_Buws5F~@ymmQ0#z zbXRD24Y_5sr(%$+DX!*^inSes4%W=4|kB; zaX({LL_$a~5wlX)2rHAd3JrPq;4{CvQV_X`=8=u8G&$20qFjY2v7^F>JT!CP4vJn4 zNqP3yNOG%(flY6#IKs>QvZ+GR3Rjq@vwe}=#+ppdAo;n&A{C1NI-`5>VXfUN+KDvJ zo5m;9l_szA)U#aIP|Z0Ng~Bh(jY1`+5wW|fWB zAP5M=?64-<++@#~imqbb>@vRCQD(LK&;F0Am~3ic32KZ*r>*0zIm%u^zrz5e;;LN~ z?AHx~r542G3Y!qKh1#IN@rFAN75Y2L-Z>%gQ1X6)`_>OyRpC!C-iP(H6$fWK+2riJ z121-IcRGQIa^>gc4raO_5oa&qUhoaHJBnc?tV;h#1~c3KXDGO8EFNuHV4A0WO#Hon9#H^)UYCJ=1# z6o<*Pi!g&OVL1t z@67g)ya6oTq46=iuC2I%pY9*5gcc@dn6J%&9-E3!lbUWHr^wY8=@#udP%HgrtLfld zchO~%I8BJtjMx!ehsxn5sA>X5H$mZ!^Y4OR$9$5GVVYX$t(7jAs5einLND{Q3Mog0m>1aNRMC=E4qoc^8lLAaN2h52OB4wr z)1YNGn#qzrc@Tr>b>$o`SUEDLx~8W`yZHLkeb4#nbR08Zb4luiy_2{m%|u!fhe zb1`K*?q4|@zxJ?3oHX7aO9-7DTBkjdsjN$)gDvJmyD3xrdzr9g)WM+N^)vEPog6Oh z0^silYx^1H*_b z!EQXEb~{&ZP*J_7B2PtX+zMwMM(9WkBX8GCYezN`+_(5*FRVoy4|N?QH!o-rrfyjcPNn!fij znp+3R3#3`+;aCO8wWZ(Ojoe-@$4Aa_S85`UfXbPQ>2#X%{#_sty2(?JeDPwn}gofRJDZ0FprB01|@a+Kw;QS17rV*Po66 zNoxM{HR|jr#nF2p20EiGxpp->C^Sxf zJm>o+2WxpowS<~(=Y=jlGoN2ab?W3qx;QIX_HYeC+nFYY=PB2Sv~V)=To$R5x?_Bu z2}aMY!Faw;z&~)rDM_QknB*#_er~$n*3s=Pn9g%lMjB7ABL~;$XMKVJ->M0(jwj_1 z3cucBgtk@{Jk!wle66kSJfr*Q@ai=yk@YA9~8#=_+6il`` zh#K+mx^k#A+X2?QuG~1Z2e6ne^ki_?w^k<0ZL6u!21v1J>nOR%O7Q)4%Kgs>}5-WlpM&Qx~CfcNSQkWZ$+1E+mPshhwk>ur=Uc z1!QMJ$FU@<(2*dFaI5AcxdZq! z+@Y>y)bUZ`zw)Vn9$jf_KvUYTdj6 zllHCa3pbd)EQ^ zDNijW%P??paT3y5w47bNEz+?ig~z4Qa7|3y}`zm9w$cyuCjpV$-(rCNH6ofJNI6%%;Sk$77Uqn-(Qi)*=s(?T^8XbN{V@ zKZt=8s{q6`l7p)Sms!&C@0Z@;-t{rtqyRm$5%kOtfapTY8w0=4NUkrP25>sULCbv` z%g)+}uW2l-e`CP!xA;}2%Y?=YB=sLp!}KT`FZ+s4U@XOHt|2L3!wekhebGw}N1x_Z)W0ABHOXUPEIqj=d^UGt2(>+MqmzaB4#IsNq107r5z zxtOJGOF3&;(=&7_aG6K*rci_ziC5_#iR3hQuDk>!Y7gLeq%K&J0bEar z^W=_EI)B$uv%%hkmrS4pIL-USz?(&(bN2w~4ZvsF6NP;M=-w%VfOvWWdao-e#agWi zfGct6z3A~u`#*VXZU4UjOzb3kJ3Ll+CCozQ^oi&_Z$K99Jm85V-#^4N$+-od#Ofc~ zXxd|)pjy(n!UW|N^j6_9=_|_l?9sdGK1h^n`>Npnr)yVqjr11{f4Ics~_Lz@k3LY`t*ICf&VTW?;CK% zKDjoyJrgkR-@c7bY74g`JxTVEhM?iEZ*Hj#=!Uf9yg0k;)Kt^xYBXiFqLpe2uGzt< zpclNwuvA~Zo3c1y?mn9&*VXhlq4KIWFvJ^CdE(-}q)f3Q@F?v{^%m`XJoD?b+UZ;; zVzwqNe*7i%%7(nsmFHGCzCd7Yt z4TVXhAl`7VylWM0OK2Jf27MGCF=MYBz3fc~Z zsXb~=pALpD?c@i#4N?D@bq|ync)bo-Ry1mlWyOI*a2mR_m*;5iY%Q~Jmo(X1I%78Q zDyf*yXPaqASj?=In9r9Z$X7m}r$zpU^FZVqlPb@Xe!pYjHPg_+>i{%JlT)QW0L0=U z;f})cbfU6&h(*HcG`WkzpSKNmrJ?xj>1_kI?;!Vc9uI^?J6imH2;|2d? z+ODCM0SwzZ`cE3N?6d#ck<%UIWOq~obLw)CSzolA3pwjI*TqPS{xw=^|ZyETTj&elxO}9vvHF#{?LKo(ZI#lME1k91Vg)pO2n(I8J z#n75X>9V&^0P+dha!D<`@FX-&n55I`uyJQ^T5a4e03G7n`QYwC5su2nvzVaz0(g}G z6L(W#wLb@aySx)j+}D8M)c~*X>qPu+*!ThH&>Z}RTKVBw;RitQyJ6)wnfP@ket^Ia zc)@ShzYcY)C8StRnBU&K$IonZsi$6hokw&?)$vwcWM4Iq5u03m-FjSCdi4Ax%H9c2 zSh{qPJLw-^Lo>l|r8uY3XBTlEPU)=vAm*yBvX`!<$o3;>%bNxO5AQ0smNKpx_=){B zynx1!;E{$QN^Oht2=wLvT2~>EK|s^Zy31miRE|C_5u^E; z*-?lv9VAu}__gi9N$Sf6UUi5=9jPIJGd<)!(kwJ!cz47~=l^Bk?Rp|0-v-S=mANvG zD$(;V8Wf%J3+WSvIq16SkdD_roX0rYI;LdwsaKYAAw?Q?#jl$C0!;&Bs^IkYQn@Tv zk!(I;_EPIK{rHkHO}m~0E#(XrIhO-%$#xhltp$)d#-W#b2x7&z^p@MIF$ulsE%&7VUHZsD(%_5mP5@vw5oP}{hBAa*tW-8tnD6fcXYb$z z)MYoWm|O)Q;!zFHp!^Gl_b(Xv1Sry@r`a}Z$8*Oy)R!`lC$Uan6P=*EqvDnB|$RpzI==;E}$yt3rx=rv>f@bVX;_8}JSzH zQdsbWL2^&2*%{0ogXH$!Wv3OvKKhWT&3LkvR5)1vQfhY^PO*%jVtoL6(*ZaENJ;Fj zSD!NQti|UD?nM361ZX>dYb;-$htdHYzqsSQ5Nj@Mk z)z5JXQb^fUphKHyQk$Q&wRtABxgdCE&NC9DHzz7EB4KH7pv6(t^ZiYaUr`(2T!b;F zjS$??zE8nmTxS}>d^3_N$J>{q)EakWNy2CWr=e)D<*NfBg| zf=ZX3p;6AT+CI{C0DF=g0(__(vIH#z^{(R;Wai<+u+koT997)l;4Ae6&~bx<+^%>S z7PqE}J*~4sAoAFbcwPhEcEqzL@Wgor$ZdT^|82&sb)nUmy@JMzSp5~KH|1!A9B`L^ z#Y(~;`{CZ%=BQ^UgIv%4#61gE_y-nhLe%wtrPZrgH#db}5$QbXDgFy!CA{2dH@tkv0P9iVtO< zz~vydXuXe;fpEt!Rkp+j_fk}-wdnlwzgRo}007bX%S1~(GY1G33y)N2DSrBKaFqH8 zyw4|?4e{UiwqLZ%Kq~6|;c`0eGD4mm5C??f(lB@-ifvszpuE@leh@{OezFm5Ehl=G zQBGvl3Me_v<+MGx@(ONJOZAXu!-qh(C_ADd+3*!;N7PqgM~zKud{UcyaKjstNI=bb z#zB`f^&u>T4!Zc#f0{x7vmuf==$kXbok*pa&7%EeKh*hGAHSRq`_an1(WhXE zce}D<1m7^h_ZQI97nCAFqfk^R)Div&88CC#L-eW!Haz>_phc-O`UT`Liu*(+n28Yc zl+8-N8TwL-+(Zgmft-&-Za+p2(gc5v`ZpXSGpA`t!*IphzE{m>^7#j2WIyRMDDk8* z@*wH%K?GdrI?B2KV8t>48@w-IIU0TDYLhpMYwp}60UUl}X2 z8h`vqtDkrGCT_v=|F}1?(_Vxg#>x6>rUu!dD0Smce+;hA=ZwSHuKgqCWx8J59spgh ztzNZ?|1(bRBJpCRjE7@y1n}W_nYlHBWhr@tjbD0gZ4 zbrW+}hIQ`xe5W!fs{oCwG4NFQ*l(DwCV+QW*`Z-A+80FzzI301m*#R2q8DFf$7vmY z0)$V|?IFbG?6^Qzzpj-{2=1=i?+~PUHXC}}WIx=}Ffds&Nlufl?lAD3`yKjAlK{kD z86&6k+@VNvq4PT)<;G+*5;2&n`t9_?; zq7f5)uADE0ZilZtDbA;sBj_;$enAIKF-!|TvCgVm5QK%qX!-Fj3DupSY=Z_Y5*ly- zAfIx;sUc6BB4>H7>PW)+0}0+0{`iB#4tmY10<__iDf0JH!|x5e?vhAfHU76<64|`^ zR%$qlIin_Tc+|m1bEwfX97{gs5U9&T%3eLnvfi=+n>cc-fe+1-+iEtYVa5I1QS9ib zfTHb{DmS;FF~{-+yBvZrE}og25eaRr1TR7g6%mSvPpOYZI~UJlCDDwA0MV+5w*OQ) ztk%g?szx#>Y<1wvr=mGGZnox$ur;R-C~Y+O&rdIltm6zSe8vJM{h8S~5)r87KWIFp z#+$JuSRUC&wTWCFOoYoLJ$0LCm?)<}n#{9UN_%6cXcK(j<&mBBNF#XR0?ZBfFCguy{XA-&_Od~zu0~t zqLKL)-wvjh+R>V_h65`W{K;78|DO5&8LeK(eR78Et!)iD+f=Gdl}(Yv8pe1@!2seL z#>hc0R$~N3;`8tLk6tbH$B(Tp%8{?5tI@&*aTj)G{Vjk*=A^A#K*Xle>9+j^WmSV6_iQ9ovWf{iHE}L=iCnp% z9$%sZlj5)BI@JdPOBHU$6K6Sibogym1)>6H^^KtaU?ay@lNRa z;x9mB?fu`sG4R0Ia$Cs&;G@~{U@tYuE6#1OiuYGS#Q9=`>dpdwFZsYq1J})w8~D#g zTC%D50@#}`LyL~&odzhriZB^81Lnwb$|%r~B(6ASdL(Z@rIXSJ9cSOrANyQ{BKL| zA=Q^rv3Q+4lp=OI2PK$k3Cdb#n4jGz$YH6XBF*ApA89WrSVjht#v2&y?IE4YDCzT8 z<-#%walE=uD%H@oT|H!}fzK(F2T0eK!0s2~Xv9|lk~xk>7yx|4Wq;4)B@l=F_qKTH z4jNAfdCaC;ulOpCw}P z%wNV5sm4mmAMDonNEa6wxKptvQd$Kd!o$heb=o3@u|22-OP;Y%b`R+}_C1e&`ZyRu z(;ydm9ls&H3582*9xsNYx=;>KFS*C}EX0D~!Pf?UXQ8b3vIjM3gWoC4n7Cc<@Yke> z`;e^vTJ|Talkm070!9N(P5ZbJiTWX)thG}9@sY(Enhc_mZ*H-sQ^>W2|D6qNIc!Si zehv}D#Ne8~UVnkwHbXd;>+H#eh;b~EeckTIP@x78*;v5UqQ<5Ju&(y9e;l^4syS&SfhW)6xbj>~ujjtXmj`bd_inp^$At{|vn@kX9= zX^3jNgW&N!htbl~LIZEIR1Q|pyT=pHyZA}nfta!s4LA25pK{(MR9&r53CdizBCmtW zb;o?AH5)~e7+dDUA6$mbN#u#R;Nmwl6UjDDrn7Z!`ZIz^yCMZ&-NA2pO9-Ic4jiJa z|HCit0(>RExE%@=$BL%{c)U!m&$@wxx;RFZw0Yk9WnebHk3c%`JS1R3p#9cDG>!8YM& zRg|-{D%XVPKEj^xtt^MwUP60BM_+RH1>7(sC~|P}k7MDh{9}|^uyE9NzN*~? zukdl*Ym?mAkS9&OBUfheS~jfYC!(>7QiEiciBK5~|1DP1+nDJN+oBCtPS28;ghqnw z&MjI`aajoEb1at7 zZJE#cHC&ElWky30o8z>K)(BB#q@hdPi7O>UdTTI&(jo%tdG3?lsDO=`sP1B0*PJ~6 z5qi+}Ce4COEGmAg+{zP)DEp!6l)XNDW?8U^6ONurq~deU7hjf9oz(cKTFNg|*f;S} zf$b1!0a`4C7vt6FEt{2E2oHw61anGB*V!>db&TOj68N;3*3a<_)5lFI?5Pk}Rd9om zCNj@zc6(t~(U!UmxV2}VUcwqAdB05?5cnNp2z!Gd!oE9$dY$d~wW>|(TNU<^s$T{{ z$!9CeA+4m!81RU-@3uLIPt2h`7L)>(|1W)(Ef19M;2|E7aG^HAD{3E#{! zXP*lPW%n70Bv#qSG%{!Hjs%O8_B|_D1e$E`8=#ykXRmN*E@WmtsNu5?9*~Fzf;egb zF=i6;klM+wYB!&7Bq*uM(&fwBuJx;1pOdq!Cj>^oYjvQ8XCRGBZ=xI%lzg7;krl3PT|+qshalFp_O6T&b1%pO?Ce8SJNiSS z@x2=b3%|`qL+RbfSJ(+hX75G;LKYl9_HLw=`v^W)LkP{)szuG_<>n7d&`DW&*8$zE zFCvHm3&>T)#l4t?WLfs;oQD}1@QzA_k;b>o7IGc{6U5@s> zlq1vSar^ym7`M|&JSM{`f6C?tA7x`WT@WUGJsqRyH~uvhGvz*9c!jBVV+7v(#^0~X zOgZDFs+6%Kd}q)j;p=V?2;b2OfrBsVSAYPh21fFf#u-+~}3=+I5mQ&`0twcGmanEtzCQhshT=_ly_)2d<4eVjL?{-m_F$H$LP~Ba{+5Pf zz*4l|nI@Mv0!dlK&)QKQcBfvJdXWiJoB$+Z9rtPd*`=SgErdlUUo!t}ZEvCHv=lZi z8{?klWVt*w5Vt)WThZGKUNU747G1Yah3%4~T`oAmaWY3+RW;5FOz-DtqbePmLfuBr z6!Y50N;n$t#bMnPbBJvlBq-|2XIY^Ua8vQ}E}|C=GHHV0N5_hTJPr8fNPe?uUWbc3 zLH^ucToY*HIfyS)`D~vIGFX16zsO=qS(Q>Y-KVW5{^LO+>x*a{O2Ds0FFQMB)2@PF zceJ-g9`;d9RfvSFVXOq~4JNgQ#gdC7SQRW5%k4>|Amg1W0uN=h^5hX{_Bd4q+j&w7 z`^m#T)@3%5S(xy@%RSLkZtMm=k5l3_thJ|oAQVMF`Z1pNo#6aoVha1k(>_IrgQLEe zeN`X-iT_)9&KyI|74#AxdaSI`oolJcydCfE4Er;(YLx@hR-XL2WnHXT+e}A?+;H zXIMPk3INL*n!>z=Evp}aDTrRQp!V(HBRiB9KgV^y;| zf~#E~HZ&HDNnxY%w6V%xPs!|az%@L;-d{QPb7subb{7tgPGQZCV0olH9IL;>1S%4a zZ;#+wx8rCk@quIC;;fOz~l{|7gl#=CvJW4;a zKAVEbYIVP$>fe1CVWa_75;6}I!fjqUcL$9lN5S#=D9%w&$+8Y$JivoT*)Q2^#0iH+ zr7-Vf+75VhM-S)7V_Iz1qII%(Z&4C%0CeFot+(=75BA|0PHitoK(*sIqdgLi4#yF5 zYcLyj9IL+BBN1}~(k%qrCMUF7&(R}OaQyBcr&%{^(uIHmzL(MRyH{-D2^==5hx9b6 z22@2dbaDxFdla2q_0fSCEaXF^CXE8AE}lT^Qp4e$kJFePlTZt-^3k%{AXHkeQq**< zn#?yEE<>b-4L|b@Bu^BU+V9fn2W2*pIzo{l{{VA>Th)pa-~*a`c7xu?4f=FGA26>D zhY6AoYxpZTnignlD*dC`$O2TcBLYqpK!ioZQrH8E8C#!uoy3KS!3g-`B$Tlu96z4a zCMazq*_)HtsoC>6Or2BOSYZtu15Y8(qdZxIE`iz%M_Y|D*Br1F0hdl`KT{R8LV=@B zYg;NK!`al+pb|b5n-r(9IbD;Y&YsqOrVMPyLVnR!(|nl%gA-%F)2u@QvH;F)e!%+u zqLswOh%#m%)G0gtJ|vZ%_Yoti)7)$Xq1S2J612YkMT_^0K>o%rxH$1^Ef#SGXT+xK zQ&{&i+EB-pm+;srHq-DXkzsf(wwNOQ5xMsaPU>FQ;W*J5=*T`es-A^o863^XF%k|v zIajs8_Tz|k}qwV!ohf-^`KHDb4a)vi~iHUpG-zhN`&?I1MS-?TMU z6)DL691e8MLs0v3*gYEp$Eb5!Z`DJ*NWvDLgJAp+wEvv8X09m22y(0jjY z+Xx#5Ac?(LU6=qzzdvvkIv$SYe`p&DDmc#nflZ@5{ZYN=we?j)@CFC#dtMu;Jk^5D zK97nC>u;%;{+@Ehj9L4D9XJmO#v<3P^V;$5owt=9;qXqOJ{fKDPwfQZVZRi1|4%f8 z@8Af#fWCAm9PKXv$3!^hT!5B^HD~88Xv37hHeY^G+fZ4h8H>4yp>%TJ6gKOkwxv)R zjAU39iDcg7d5esHoS@5GfZ=$CZ>`syU-}t z?jf|N7={Ft@D0?F&V$?uESGQtPZ-V(_{sb8~HGFaA0C^1Fc-|;KoqAK7 z1ozBzdd|K$0eK9cb!40V(gwLX7B}~?@+x^H)bRDcv_3U$i({N-@8@sip(DtLej0xu zA9_yEp+05k4&G+H&qFrT4@4l;W=xP(d?Ptt*o4aa{BP~|!r`8{A8|$Ny5Mne_$u58>;%U4p*QI$w)f>3RcAG!Lc5B96gZ-sd`W$>Q-f^k;?II4<0s; z!k(>VAFkjsOimB1kzGZ7kAy>iRr{52se8)uYgk$SxjW87Uc;&8A#kj`22FU`4JvmH ztBD?;!8W|E4RT!oE~OOUVIqsaj)kL#4O#!|7}OVb19a=1%sHU3^13!vnI6FGZfNmv za#tMGzJWu%li=ucLtEXiLs#nB)AwS;;g!(>m5k2|L@1E>mT;IO-?^^aL{=4F|IAr3-CEykH^`N-Mg1o4N15op$z zYJk2l-O*j>0a9rnhv&viRFbIvx?px3#sk?|kS9&H6NsyJH;ZyR=8{s`<{SNh5WHbv({l^cNJ! zu)o}!~sB=avd_Mw!w?;^|0ze+BZ0li*R{RqJ`%gm8w+@cDTWVN*VK5%n``Y{Z z&BbeE`RQ$Gd(%i?cz_C|(jTZ=?{!?&8Xtlfp~uMx=6Xz@v?q^Aa{w{<>Gvy2pS-Qt+EdW-}%R8P=imGHjmBGK#c* zZX*y`s<{nDw*5u8*L*txW}QlOwI53z3Ga#<)ncv>&_=H%l*#lb(zbbkb@mOd*{}!N zB?`Pm^8l4Is}+v?KE#0B4~_{BVM-hb#E7-_AueOyUBpg4)Gih#w@hKZAE7xff@9$$ zZKC_13rmkr_{5U2MGAZLNZUu*e<5r87=uw~1k8GjgEtW^co!9b(aw-mnf>$_D)y;4 zPA@&y#?;PjP6~C;(Eb}tA~QD@y3<7s^J~467nJ6L(P9zuwR)oMD}=+b^$EsjB^(!? zXag$UXhs#VQ?OwR(s9oww^<7Fd7!=1DdudG6ju2qy5nhZ^n9sp=n>z9YXUtNJBBKC zCv?Kld=}gGlBO+lF|#X9nqgn^A4Ks|k6wYfEuQ(i5}U$QueB{BmrzW`3F`v{kp37V z)uc=~q|qDMCcoBpsN{kKCXF4uf4em*IC2zEK zygdFj-P=YOn&03G|Mf<)zKmE7#Mr;Sh=@vWwS$EbaEy8jC9MO;rnlPKf-M|>y+tQ= zy&-lK-f3%9{;?t9*@|DLP>XKVAIwG^*Z*WV#=p}x5rW{@_fFf>>2w21eVqRuZh$$> zdvxFP;b`+7oyu4^hQ8N&d-Xs96pWPk&^mm~i;g&AgB;Oo-)n1BbU?ImmC}Z}_=p}+ z3sArR-ha$TjJf|X2A~TvX--FT{?R!5_W`9?14lD*jDh3x4_c{0TO4wh{DI=O{RHVHAY|bu z*b`bfe*OeA{YI3zyE_7hy9tRI9C0QLD?Q5{tJSmpU zDU&9$TS~EOrOlC4H{V2}Ac9!cdmOxIiG1!dpu$I!@r4VK&>?<;0Mt$3SSMf_?F>hO zAU5>v%=H+@8Ye+z0(f1Wj3AmvBT|^3N^C290mpEa*imqY1KoTzx1nx$OZWo{hGPKX zl-3xIJz*6rfP--OsKs#4KTr%~Jq#a4vZ#%9FfigaIbsK>#dskSj&IeF-u`&dPS9Ax*a3t^-+Q1=P;OTHI0-x*^Yu z3SwQs9}YgjXp1C&R1g~qCquEWT~TbP-0i~JR1|Ag9TLiGq$mW{Qf5vt8flkR6ni>7 zuE~qZe{a`>x>gjUs;_pTVR{Kw6_C*CiQ!}gNbwG=XMBi@C!UMMJt~R*j$ff>jM+$v z19u3UT}iAj1i+D7N%XL*hsdH9xSd=Bw>c|`LGEX3Q14Xb8fHHhQJ?(1MI(%6Y^f&q@# zc4AZS)xn%MS+a&pBqXwKa2f{j=US`Xy+5~#-$L>AczkbjywC^^KG$`DBi~+(XmY(e zFwt%aWI>{`%|tGGUKQU%LKK$}w_U4~?TV6GnRpwjr?4moD8pblxHa4e4p_q;LQhB| z+d-otce*g~K#ZV)m64@ao8=qap# zqm?t#jD$n)jBch09Ng&khU1VkIQ%1Go0_5y!XdhdErro=4090!>$efj0x{2c8}jbC zYZwX^jz>Mp#9|VP&f6dD@1%?9pVngN|Cr#eK{sHT;QrhE_NphvM?&2olpgd4+LuQf zaH};2%_b(zDyjw&{XlhA8btJozs zG0M$Gi#}S<8~6!-QnOrtOvW`(q2+MIYtZLTfTN#Atfmb0W-~S7R$*IJjF9eFP?`=$ zcXv$Ny2CM@9AR)g)rhX_pu6ZQsNws=U2H1k`C($_A%+VJ;7Ifks|i{V9qu7E5rPo{ zBXfjZKd>*FifsIPASeAIFz|h}_R}ZbMjccDaMA`E(u*n^*E(C}d$o@4s`bhsS8x zE3_6c`6tT#Qe)m(VjV<#uL{4wOFO&gJ~~F)`!s%t9m0D>cM~&h*)-cJfyx0Id7pKj zzvyij`w-t%dLYL(zEjV`*BP0qREu^I<;oVye8Y;xN%pm{FLlBV6NY=CiAwyXgCD`o z+P%WHOuDpfeon0q-wo%7F4CLWjL{}!yoY(D-g0Iv2N}wr8T-x^rcsfdoBL0Cc{lp> z4r18c%#f|CCi-gh)Wei|crm}RdC#~IRYF&*?CD}JPOxAKSR^oijlH|i7E}^dL^!AT zT@~vh1k|x_DYUDCRmaEfzDj7|J;5p5mvkw!AFTT;W18YBYsJKjPYGF*@io9cNbyG< z`>gy zqFsFtfhU-1l|a@QXGh;TLSGmQ6EBYSNpdP?7vHZBE}$2nY?clXbK+`bcAx`Xk93GU zjO_^dQUVuyIzmY^g&(*Yu;f6DX;Ff<1vKEFFhE>43vxOi+Fsh9jRq~!zaMLeO6%F9}GaG+3+tf z<e|zS&hpoS znkBcY?%~y$vN$0wGOu(3=3GPcNo!z_(`o1(2?b8q!AGBpz|)pEMB>iB(36mH9oHBU zQ8YZB2cVV{@C_r4JJ2R&)Wt6T3%KM@D$(51q8m~J z@osbs1>bf|$|y`=+iHj&?TM|E9lp9oZPl?QOtI=FjcsL8v*UD{`1=uW@Cn;1V_f*I zE$0tR*D4YJdxk#WlI$+QXD&H&t|_{yk_`nW7F<)*2cL<;K`T7gryLtfpJH*wccrtU zwn)&J0KmrabmKrM7 zZ+rq>)sP_xhC`c(+6kxZIQn$sn9%e$%CS}G(?|Sr@eRn?`~~x<&PrQI14~Y;(52l8 z6>Iu;sheVxaUwqBQv9nH(TXvZ<1_ojw8$JAS7c|>#9i&762J6ZRe?%1 zMM|b`64J3E)Un~hj|TRRlJ%|t3qDK~W9t@?bQ~VH8-zt*_2mxGE_@`5(jTVpn&6oq z6psWP>yMO&(}@s07==Shc36f0iAvcUNDL9Su*Sl~;KpB}SE8b3A^6{ldVyay-T^rq ze>pVC{@)M^w$k<7Zso64B;N*YK%jRM-3HXv5SJ>B6z65>AxYYx0Ga8Ud6Aa|DeCjxsDhWU%xEinEwJCUKTLyZW%D@ummtQ z95Z0prU*9!hQ|u9oW%?n9uD|x4p_kf6SO5+y3%JpL0miJew1hF#%YdQFC4fn> z&44jUC;<$Q6<|4w88AE?@LCSoh6BcLX}~c6+^8(zhW`Z^Q_a$VF}08ZqY;+?hQ|UJ zQ->13@K^zsvzP(H!vU}1fK7T*3H+7@93|Fs?G{r8vAO~4872C-RSYcyZU-h71a3e+ zT1_#yBh-XsX*y!UQ4H=ocuK%6m9xm;7QjQ`hO8!Vg`WuA-}o&7$DHdzmgSmP^nb~+ zW*NAm?@E;TO#T(68M zE7bolz%|MO#;isLtg;3Sj|DJ{gc88;SOJ!^m;uAX0k7nMKXAbKEd_X8Dmt)QWdYaw zFTf#X0b{l$14j2)B4KzefMG9}0EWj3u$;vV7#D0l(#d@mmTo*Wq?$0oVC2z(HjJW6mi{7`HNO2bKklIjam9y<-Vr zcr1W1do2MBj}>4!iy1IH9Ply@_%#QN-%^0rje<(lEDJdDzW_^R0mCYk0i(w(0Su1? zFf7gz!0=cBma~`v!@~hD<$zyt!1yf%*txM7(*$N5_Nu!YKJlI0wlDQ$evz%~Y;dlF=_O{; zdlyq_Y9op|WkNpzB&^Y=zA~eaqX;YX(TL#a{lMt|L+>T0u}1$KOiQCrM2H3bTHN#` z^grK~(Qkilg+4V>M(??Z&@Vxh1^wk0rO}^zVMf1>BCOD_Kml`mV@8=rwm_^bXIg(4WK9h-5!u0il2Pv;=)LNLb50;<*{U4MkX?fAfr^ zPgKSXVz(NL+6pne5Y_;9gJo%el@MY9=zt6aaO`av;P59_03*U=fS2bJz)py=h<63R zS_544)C@40BCG)RKt%mGF;UrQ5StkXfQ`xlbVZiZ08_xp0`Npb8Q_JRGQhKstN<tU)62PAjWdZo+acO{09-9H?QG^x1y@O--#1&YmfwcrjBTH$3r@+Yq za4Is81fvRNfVCc40en(J2Dl=F09HYi1z-=5u$EwlM`nNl6k!F>6A|N^0bukXcC;A) zMwbJ49&}3s3_*wmU=%VCz^|^$0JDm$0CotG0lt|_0KY(#1>oKXr2+1IUdk3~B_WfoW9zzM zVcZ0u`j^y-(T zH$hHS!JG=ml99@#Y^r*4s++h}ZCOz?X^POj%FBsrUKwm%JF$s&>ODR5LUhzQqyFp`doC zlbBf9{kO;1VR>w57sJl=6dNdwdiH%c(WhYnU*)@u+s}u!Ttp6cpw(HiX>!CRiXh_! ztD9vY$SiHpK#1kesTP*4Z(CU2m05n>kUjYfEDd`0OLwp&mBv@UaPis9^5JdHvY#B0 zLlH8|KM_$}L^x!Yg^)h6Tr|bPvc@el%j`d8mXD&Db7!zbofP!|%M+aC3S6Bwvpjo? zvuq+qFp7{_?m^RyIifp7$Q;KYqCCgxs9@q4G10>D^mQ}GU*tlLsLN8jfg_ZvO=oaC!Z}9c`nI`@ z!*6hoH{^)=6d`l$f{5}QlTp9K(RqS}y=O%XCrH$;@;S-7Kt*1h$Sd{}r>B+nsEsplRIaeAy-aVX!Ev$vPnMJdet zOV6D8imBDcl7*JX*C+R5zG>WC>a&2LnzOF2SXUwBU4p67PaNpJANElZHU_YuX~Oi$ zxPxb4g>@PPdyhGoZyMs1HeZ^KwhOi=iLJxoy;k0w)M)>N##c9HaaM}&XT6Kkee0x@o<*o=b6Qwarmc%=>x2|Mj-YcmEX z1F+&=^D6LQW9-;()KL~BWYUL$@|)9UmB|n`tYlkMmQbk`e*>Mx8!RRYw|~>KHG{=Y z!rfo>?CD@JQuquZfkVVbs?|I5@xJB|v9HUdzkx-Nzk!C0{J-_={18!F^Tt_J3oPk= zLkHq7tt=awHEub6OT$Dz`*kN}&;f&?ka5Grn(injsxC>2E3UWSegLEy!^Brg!4LT+ zjTA-Ub%8!--AHkULfCyw&!kZ}J2)SXHlxHiRqAE{TsTS`ETqD0d_79^_ZkQ5)!2dR zOyh(4F~Z1#(;2c2|3dUox%UJ2j<5TA+5Ppa3~`NkSdXz-S z)_oxcX|~B~9Z;;+W4{I8tZ8CQj>l;6bEQxPG-i(#gN1uX^lax?@s;;s3>U^%TsoPj z!RSJ9YstwQCweG^L%I5#zsHN8D|}Euo1%l@j4O8N@r`-NWlo)wJW-sdsA$Q{o=g(+ zh5UVbwr{c+;`3}T0e)iH>Ze!4`5r*i6MFV>vRE}}A5VZM0=io1r2O{66MU5tgHt-g zrrFKCRehURr~sqS{O!wkUz3Rv^46@T`VlL0`z0tPB)G(%$&Ju(y#-P$+Pm#^|4D_u?r^=*yfbwIS?62yXc8TXzUo*oY)2pbj75w9J{8+Ff zqYK9uZHgLO#T(`LuI6|$K8vba#eXZuN15Yk{W+6lUvla;A%u6;&(elFsoiwK|3mnRzH{R%|R}Cw&?512-y4LCUj&en$YxB z4FYra%ogpG)uK*;&ab=`Ou7s@0cf@sz2|>f>gWd19)B(~qe?DDRc$d)h0hZ^qaAKX zJN#07XM5*Qknm@p#x?L1Oz4uc4Jro?DOyRv_f?-!1boAdW6#bm0 z?~=KCZZ5;s&9F)4s*ksD#UqD{#9Hq2&0L*}%jl2+X~q90`m^)%>$~NQTO`&{s(Q^r z;HD*F6QSpidKQ%4ps5o5c#WkvS=SGPO2SgHs@=uyGWQYd^=#Bq+>p5(OTAmC^}Kgm zv{bC)4${1yQ;WHcpAEucO&iqDab6~FQV50Xp*LTN!3yE!T0Opa*T9p#TQ0T}UVMjs zn2F)48EMEcjfpL5Pk?M&M7}b*qWXAcE=0F)oC@`lWz$9KVLjOHJEh0RFU6=R7v!V5 z`EHGQOszu~G@RwT`xs!cp*#msR7tiCEaGC^>KFf*$>D2Q#|xM1*~F)wK`!l%$)n!g+9dX51gCv19uHXj z6@oLzUZ!_m7g0$w6Ede3nlGu3`AW|Qej_&0)}vJE$N!bH+%{P9ukG643|PT3J#$_s zJ`w(0s%OG_F~T7vf*5XG$_)V)w_ZFcoLK^seFF|)eh)|J2CCh*DnkIboC#9xKw z^YNXQt(ZGbgro0P9CAJk9hkUPZ06=UzkFtPZmZZs*o3~n=6B*7VOI{C+%_0;4w-uP z#WtLJzV@Y_ZP7X#dXnhSy%myLn%t$Q`LE*mY{v|Vf< zEZePTjeZml2-nfEzWot&8_v^vlu(l^p)ic#zFzO0NjlE#B=sW$E_IpL8P;0UbUZ@Pm^)&e>ARIBxdGW_^ysK`}=m>>aOX1&2gG z)r#?Yyr&{g(+H$bg-4@$2xB(tS+B$5CgH*cJyYgF3X$XVtX(b+4V%X5+4NjcirJvg z*_bOnPzVo4>shT6Vu0i6(XwcVa?!H9BS3fj8?>OKAQcG5Pe(y&#us|_=_oF?^n@em z7)UMuTA!16OuVTOI;F~_gm5@IoDkhhef{E~SFCGJDwgh&Azky9$qppkiHK%txv=ch zk06wR=B|I!iwf zNmQTg3m3bwOi{IBf&w=1^x^uP_NT;mX6zS>^f_bCio+FEXJ*sv=ygISj@IB`vnP~OK!6v0dFX5JU( zI@>ILGjqABZzqhzUmR2P5a3w)Fuj)WQ?h=y->jciLXEllr5EOP7Jld{1G2NKw%r{v z>M4Ro%m%11GbmnQoN+qUv$(VXb*!g;=?`D}33gDFb1T98#h1SciIr@Y=4URoU7Cm! zlKxA-NpG!c2Itc4^J@vuy6bmen?F@0Y?!8B+GlYmA+V#&p7$Zke-nc|UPYI)cbY|^ z7_q;J^}Kox!-2Zys6l>2O11|u-ZUM?=Km&oD}#oy_@wqPT}!?iU0f=*^PE`MBf5S$ z;v=Bd^Dji#LraM$?~m7YYab*8gQD>g zDDE6nOi`0)P0=aQOtEqAf1%iMj1@%=vU+upZ15LICZp3f7ym>nYm&LG%p@Ou_AewA z==6(0#-$7h5&}Un<8N_+ufrF`6u)R`O>tODYk{stD=Al1KaS#LyQt<$Aotf50L()d zZUz|G!kV0a3p2oWJ^qDKe+&%803)u8SCu36IoGd=wG=|+2t9MWA^u=1YaGkFA$mkd z&9Ot5aXkLjamCnLi5VBkZl2NMwTUm^?WZAyuN2tEp^GWNjS1eD8T=K@sZjLn`81p_ z1Wv;y`QdtqGifF_BeVQ?ne0C|Db7w`jl=;)d_7eofc8B@wW|Y=Z#7a_wFEZ3P^{6i z69RGcz%LMeTYK6neh-;fUHyDBOnF}NE2X+Y+oV2z{Vc zoo?Z>PySFn%eaN7C{&30{+3w1@v2%}hIR`f!`fVi`i?Yu%SST}zx<}8;lr@>FA|eO zY$-8eG&^@+<=c4OGu)}q8s|x87Xl0e9&#TFHARXxbdh}t(=HEy-1zZ_iiT<(1bA*3QV>{NEi9mcpL^h=tbxVrKYc^_n#chJVNIkl zd=O-V=Fs6@4g9>)5`Y%QNi-fD#9rD1j9xGrF-1e73zQ|po_6l+dN{)OQF7!K>d363oxI7}uu8h`$k-q3%g z7vGJ|yd$;{vUGZO`i>Zwwz&~(IBulT4-6vsX{WO*4#PvGsc|J_G=nj%_QC1`oX$nA z@>sTxN8P|STSH{YxQy?~Z$%InYgX*a8eDb$fGze=>2f)dx6F>HX26u7Q zYi%bO zJ1Gem4 zg2LDI9(qEOnc#kE2N3Y8Gb8nE&r{Vz!6{Oo6Y)$nRw1x( z%qX9$dJ2u;P`yxX5WaP<%)Wb}nk_hn=~?7Ul}2^3-a8X({ZiFWC_>N=FI9f3=WlUQ z?d(fcf-o0B^PY=;x<=P3E#HV*dS-g13UaFuP0DUAE>_GmBM{TzwJJpTyQZEEey#da zHPIEtdHz~egd0}aPI;q>5{CFx&hdJys;Lm(1nXI=cdFI)p9Mn)(?2MkX4hA+)VPZ7 zO!Z!M#`Aa(6;j>e@<5v*2~H#OhB)P`Upt_A7~ZSu3KN3#IsPA1Clo@DKs~$n5z3La z9`mAVpHzcX{tn=q@kte-DzGmw9$I9n;eB4DFtj>tIK0~F=UwV#glCWO3dp`!P&f3b9e~~bT&RT2Vfx{dke~p4P9>GPxgzwjA0ga*j;qW;X(x_i z7;64SpPJllFo*Gn8^`|+sZLa@HwufY0=2DrydteC@*2nDf~ixstO4_8nRPGru{!~E z*n6ZQOGSh#Gi*$qmXlQNFWb!qL9OK$Zc%=<8r4rLVl1# ze&-=Y6tap!GD0!##R@#-Y zh)7oKAs#ZGLg+yYgnZ9KhEs?yLg?-k6qMIXaH^88rY`d0W*c*@r1lncUV0W$N!?FS z!=bDo1qydO(cmjc{;Ffg-kR98O6rxI0)nk z`J$AtVaTBT+Dl;lE318!&R?-d6{L=#XFbS>D!?yN7~i6n$l3v@RMe8;n`N&}#(#L# zZSue_cSY%qPsncS4>!6~zP0?9@!!Sn`W#1lbxVa^oJL;t?cgG?ehzAXA#Bx4_O!AT z=>EtJ_HzK}mDsaa-1Ir2c2cZDSnaB39~{+M_i?Ur{y9#9jd378UTo5Qj<`+s(jb*; zk;#;^#!1~s;dRIb9X+nySgxGOcW<`1=yRSpt4|89!<^7D>;$vJ@+d#Z35Pt~)Ze&G zN|ieX-j!0v5aOiInWjaA7xjyzr#OfUKxTBjoXdo@b%v>5O2!0)TAzq(p>}tiq|ss_FnC z5FwvcRnJo`ehH>`tExpIbHG4m?~elaQA64M)ycw7f}UmhtA7-FD)p>!fVzd?0>_*H z^cbBH6SskmHPJcwwo zoiMROp=v*2|4UuYwNO&b?Jsm}NtilHbpeYj?3Xb0K-H_OfKWSJ-B7g*uAJ0xwOZ+Y z>>(L?2PLX@t3jl2s8i0uNOiPA==xNbbGo)VT%q#0jQk(#sN>x4J=WPAqVaXZCqk0x+%S$30Ln&@bnQWVR zR4a<=&!ae>@jNt=Lfe#t_UEDEeI5Iup5!gGH0oH-25MiyAC3tP)SnBx3_8}WJ_d}% za7?Q&`Pwa6ff2zSyb-XuzNGi`Pm{-siqLYy(dqJdasQr<1x8CXl-mcfj?q$=P~ANp z0Qbi)J$CUDNGrY=S8Q06k@R)xztwy3q*UvuY@ z1>^Jc7{c*+yepSIF;$!@${Fd{^)Pm&>b*ER1{zkZb zrqmkd8E_cbRvnmTe}OvZfu6==Sbnii;R5n_ul5jb(9(^IyTi(18n{)#E=ym#XU{nNy->Rt0A#V zt5I|yLW-(b!qRw{7s3c=L4G>1$9@Vve3&x8hW*k>ii%U6)zK5Bg%o2}*;Cb(ctoZ+ z?NFq}tA%H%SzO1jW$G^fWpSM)NtK!n?DI0zH595&H~_}7zf`{vCY{!??V0Leq5WxH z&fcz47eQEe?QM=zPidHow846bu^{FQ#z&Zp@A>c zVKQP8G8;H$KQU=;9MfTu(P`F0s1X(#lX+Bhg1jhrbq|>rNfH)lnoH5OpuGurvVaz_ z=DEQF>Mw;%#o>G8pfa_SGsTqRaCor5Pt*ifT|&m{cC z!e{Oys*YVpVM+9rJnS-KH}imn2q=^TGI_vo1StDSP5Nf46A@4b>={`c;fS$_WAYIK zJ7yDv@5zHLqS*G+2`k}OvjQ4iMHY=v{fLg8>nC}+eh(tK0Z3vtyEh`@LqF-A(tRv@ zlPuK--d-5jO`51Y9c$QM3dMqODC~sK`%8Y&y>n%8iO{5y1>w0kc34vPG{;Q9YGMQh zkpfh3He;~O)v>4jrR3VpKt?tsWYfP9{Jhtj3c5)d!3mjbBwDX9uk!6VIe?`PklMF9 zdbo7H{qXaA_sP--f?l6$u93<6snuvtP={%KR zAaZ{>2)P@Zb5AIhyT^7?cglU&Ue4X(#sTEEmvb*QkOnogZo>5PT0&+c-gY-3De3v( zQZ(Ph5$8aaC-OD1_= z;DP6BQ;`OyLUBI6U2p-xWOkhcc*C15@*q>u@ToI(&=ZgrccbuIX4H&Uz-COyIFEfx zJd>1^8R!A{d3q@k+wQym(J{vq$xqmqqhn!kINz)&YiI-%a@Fx;_zrA{i)RIN0uF5} z4rG&3q%f}}@JPy}=P&T%Y@}~CL)mRX>PU)I)klqJQUl!8!-mdOXg1%`8M+mE&|2Np zS6N{ot8w2uO!zSy=E+d0R^58pH2A_cxNA7D9oJB}IskYeKwD zr96S0+lET<(hQs=#tM1u%2=}$%g>2f;Y}dY7aG*73v*9eVnf6`N-G?oBim;6^dBqE%rfB@d+1k4Ny2WZ~+Vydh@N z2ow&nG;2p?eJ$s?qKkPCcIa}Yh#5>;4{us-Du{mY7- zi8w4mfEV9JN&l!E>q6Li7`7rok-7+=kKy^G0OeSGm2Qd@Y*<7YA)_8`2<0C?a+GnS zAehZo=xl5`x@VE)(3#Mea=|>?#Le#OF zQeewh?TbwLvn0#|NX2%32NJZ(V;*s~!cQ%|6<6pze4O9USAl4Ub=6kHW@(mw9Kd`h zNZPc!NL|!J98YX1EW$NXc}tuq1oF#!^>#;Ycd>aO4U*ysc`=jzc}1CQL65m1rF9rnX^IIdy*sx zeSaFj;wMP~O^zW2G#!fnegHnDrxXil zP;Z0gXhk0TOBz;urShz(Pu)eTd+OgUgCz* zN2E#q!q{g6Sn9U=?o6L1)$;2HB1RWbpnh3z8A|gt1j6_7l45?e%*A&4GLZXNF{^2ju$|1=-WD13tn+{RH3K~MVdU`J5 z!|%)&7=HbE)D421aqLN=$q|ME4IkJl;fA9573D5`XkUb&qC}IXVzsY%dU>F!`AK0@ zRM(_=zLp0jWyaoIt7Abkr4X0chE}IPWIdQEd8pEHkAfB5X;44m7o80{m87H$sy6l2 ze-wZLouCy<%s14Hy5W6M1O#AAs`rw{V~6#}@F(LI4a%N;IR-N_bZ_rwN_B)wSaOI+ zm;BOlyO!kJ|AOZ`eFEKc>3sXPp_4sK1G}*rs*1ERIx`jHAHM`J`83DY){O1L?K0SU zS@Gy5^Y~$#j4jOyTvyHn^EVtY#SbSQiM{4PnS5(A`LD~8|JbFZ2ydSAA~Zf1)$;zEstJj^xK@OHznrmE2!W{;5MbaaBcf zmpM{M+8>>YAvKqplZs(-t&SlR7jDQfD(5K&n$)Bmk!*DH8P{gqvBA-;_`_H^voU(Z z(#JKnZ?RoK?^e=UPsKWjNX)pGM5k^s>rMtoTA70?`}G%wV3u-lj^x$4JBXFaBBz%V zYFw~kKqq)$z2fjrdP%EuHvIUM-T=K}7#Bso(vuZB)^DcdsXB%mJ#6w!sa|4ceyO(Q zTUbVaCwD9sLDaY>ys$S9mn-a8jGDY{dE{dfKNoGw)S)EbyT?3VE<}Jpa|J}9@ zoG8_{Vs4bdw%Urva+$}2%`!IYw)GWfQod~smdRV%*7fUU$j4fdkCw?#`?Xxr>vQV= z+P1LbShj6VD$C@r_9b%q^AVSmoliMAoyVxh+t$|O=C(Br>y^~D_}?;ZYZ|T_$!$w~ z#ELS|wm#7d%;p~Q?L*F`-TeR2ww_^Njr|gBYnN4~ALLA1Yn5wT-y`{~FVVIJStai$ zCvTioPF#JF{P!=>wyKmQw`yBc_>56*TdyB*pz|A+Bl2p)|7u%ax2)RM=+bR#UE7kj zwO;6NXz5;?+E(u? zWfbf{Qc1037xBVY+h4A*Kf|)%ZL2%h8h6e|+iGH!uc4f;^}%vF(*UFO|886F^Gda? zDSwy2cBM@Twu|>Uw$Sx5HtV)^0oFo19Y`rNZf%yyTiRCDvgD^)k)I%wKYXfO(aEs+ zALCYA&Y;w|wIA=%lad$P1zuK6++-$g+{?+y71k1OTLvt!@^R}h7F4Ni@xNu-*0af| z-D!pfzKZ*}Yl)`SxOIu38W_2t7R>!0O{?}dI`(k^n%2|Al1vW_Jd+`~T+=H0TF06% zMAO=2mHZny`LtH$r1dqDFJ6eI)u|-8Rnt0%8MbBEsxK2c6IG5#J&YdzK5U)2X4SOD zmu^~x2_;SIrqJ8mv~VBUs%cS{QcY`dly%b*zOrgs*9~&hdR3E}R_a2XO;=nK$64GC zxbQ-kQ?QJp?voA!74;oQ18D-?y-v!kmzZ_95KbJbIi#z|Yq1yBBCalyT7?)}l?eTx zyIkm(dX-a$+iP$LVzJaDWQJApDRT1kPvzt_8OdFiNuKP?V#z(EhE<+GInSKUt@k=)Y;@;pgoAtXt7dpC(}5{I)`ksvqO zBndL5eY46i&NyMxv{QVy=oj5OY|_ z+2$oIPTuA$LTE{)w82-fQpfa^e4JJCQF8J_eacBV70DstR%y08d0FA6Vxhz$+@f2Y zXYZM1c#?1pEB=RYF{k+#`L3N-R=ysx0tYBbfxpKzibT8`i`r|xg8qgyD=E4p!|>={ z28Kx^!p5^-4*fmSv?Te#n;iAAx8($TfSL7o{&G~tP^&zHs3y=4oJ@Rw=;wOZj2{bWku|O8Hz>3^9niGw`pYf)) zx{^h>HDw}erk3GJ!VO+#EnG~~{=0v;HnFUH&H77+XYiO87E?*YSFp6-dlmFIrEy7F z23_N2>E5Xf417*&sg9jl1^rc6CI4`hCl_dPU%I8gUt-qZq}8a5ZLuXRHp_Wz*OX(i z33)PCL%N-#yq?$-VpS7-CUY#BFIY%-sK;yu!gYm|TW2iTK1~ zYY|(?m$_{6@@6|fo9f86u8}?$R;KHi`&y}#K4Vd-S(;yw^l%3Z6WEcMhbVtU)y8_INn^hRUJSpQV@SeJ(>+^cUb;`Hn{ju4 z0G*1bXW-}0Ad%qvJ$}UXm^nf|$C_%6OF$e;_(qBeoj09Q^QVJ`KO;NthT)|z@f(Q< zS`)JR$98@rjSv=0*Rg8rr2E49G;H;)$1FMa0wH?M4>g`z0D4)PraTB0hJ#Ppa!>`_ zM?tEh3W&aqXdLuK1V2Wy2`iwuD!fp~My;28+-!WvJ87CV0Jd(u6jJ?{G#ECSfoJfC zuhQWerg+nzX5;f?!jU^F+zAG(C+j6&-^{={NQZcHQmh-%o?vF|_%vNk@CNCr!g3Xt z1#FUnR6~cr#B9Aus#a~{dDH?11MK9PG-uF74nZ{xO2=P3q~+!b+0EZ1RgdU@Zh(!G zOT6=Qr;+Lwa6flSQ(*HyH6f$(goJ|h=^#M=60#;^!Dk9|heSJ`^%c4(W$N;(-vK#xb#>#uhbpv12dMSYk;mvBb73_8yJy`#p1a0X5I>^YRBfcg~d4=FFLy zbLXyDaEVp)>27uT! z6T@&Kvi;V`5mJv48NAIJIV8;IBe(~iC{&*|0sly*v5U>9N69&F&Dt`kp}D4Y=VkZE z2HtqBTt2M9h@!S}Y7&hn+PbE?&Y~^`-!%~l7d{*jYkTCT`N!7E>5_CAScGqotGLAt zwKO0MQN5uVT(?2)B0U_O!4GVZoA~bmoSJ(~F)7&9zd^r*54QEwhGD~aqg+4c$F0Qo z#xl0*r^rueQx*@Y*qR#+Vkq5*s=BID$#Nod+)l=;U*(5n@P!*?xs}1*Z7@pWMbF7^ zB$sK^sS|@eL+wxEi1Y&DRF2xU1ajRQq#h)+RVzIKlUz2*72SW|LP*W9D1+1G!&n8y zZjviYy$jO$Kbz&+Qujd_{Krjlm~E*Ter%H*5o0H+{0AL{;KHYLJh7bcf{t-$i0JS( z*pD4pf{rhUVuL*g?}u!bwE+gF@xzM|Z-b%~zTm5tN=GSyc>T>EA>No`BLw27_E-=< zIsiN7TM$gq6N!{92&QWY45n{E#7Jr6Y}g`udEf4jo~&FaC3u^h^VH~E@PgmmBBx5d zAmGMZac(o=ORQ42%H1VDB%W@SYvZn)zxrnIs@r4*$xTSM-zLk5o613Q!Zx{u6obUc zZE`F##6BHDhb>+E2}-ihQY1?~HGbl{fW-I1Fv~}nj24M8`SR81sJyeb!0kw%A~;@)--qn$+d=-S z3^3$Z*@p-2katK`^%?xH9dczKJ3Z!y+%0kn;yseVlstGu2yyxzaG#y>ysFLDeq=aW z(9UQ{!;wtEsjzM+e|4uE7ISrgYBXkON*IlvG5=vS{@x*s24WOwHaN5+ohR&)znA3x z!fJSW-xZ%?U8wumc6_hP;AMBq?cAaOC}u+hvIp;m?QrUiQ@7nXsyW`fB>W(QbeCz=^L`v`3USd={ z7YbrO1*m^Ax+jW};M5Ng>*!WclLpCNwNh&Vinc`h%xsUT@cKcyait~e(lJ1j$pX#5 zhn>g*CCjNe*9hK{&Kn*=Smola>3q*&Iacb~ErZWHgi-&d3O{m44#c1>>{Ylt93;73df;c z8V$fu6|L-a9D$mm5T~Y|(g@M2b4OB_46Z+dd9=!w7kt$b*%y(K-9_ESfSfrZH}! zJmDAyWaCZ^Tlq z{sW0WkIN&Z{PtpKpOq>?)8rF!<;+&C$TwafCYJc^5IS(XZmeGWF>`= zO&4e)wDvngbcT=!Na4zFax>}gHdvyb4)m1{AkpNMoGBTRIC@InDh-hwc;;!jlC4_{ zzVI|!Y_UPKc!iD{(W027pHBmCLL@EFZ_LZAKv44`DcuoU#XCoun~spNvt#Y zM!~5HJSSI@R-$m+IfN%o|Bm=<8JEK9ig9UhTHhAck;Xu9sxuTb+`@Bma2fML(1AJI z$Zy`4-TBRP@YGDnSWcXmhcq$Rw@bG62`Ax%AN7gt<;2{1S&%(m{oOqpe!a`KrX}M> z7oZq|dqv!+jHV8rmsz4gTfP?}BvR;{qJfwk_~>)&;q~BsYgse?k62I-Qikqc6%s!RgLO{&G>i z>ewYkojl6kNweW||B(G$Q$e;%2wWzbBN7&-^Fx2gskYHWx$>txz;)7s5>OrbTKcD~ zvu!_wm$@WwlAbn&n|Vq8AUPyrS$tVOW82b=&%PpekbY~71<&7dFfV@>iM)ZO5$Qb8nCGt&A(AMV(?-# zV^!5y9);0W`3U5p`5O*i-pq7fjns2{9A4!`RskcxBe|hOGje`PZ9zzEh{u9 z_I)R!siocWbl|yDJixa_%s7g*y9K2%uHawYlIvCOhT^7iD6~p5VghL$R@|fZQ6e}o zcgQ~Df*JSuxm$8e=_hnq`8K#8Qy=dO-IjfA4=(5P>9_VwzVo(R-&4Q*Go~(!!5-lq znFU-~@;|Xch$c$4xg*!^{~Gk0hQZf@xuc+j*7Q72ecow<7###|QPxumSXPUK(X%H7 z$mCqN6xm2wb7@*ti{A>Pl%^4Ak`Gi!f^8nC-^ zigSh4&vCKHAw)CXGhWH$lkdvkNR`1ok9&yh*b|+>o8OZwmp8z7&SUWTTuLXs|y}htz>q0=5*IPQgho)7q=feFOLwHB7R$j=@QW zXJplyS*Sv@a)4T@i~y;#vLP9wf}Oz{&}nv8KHel(aP4F&4gFDV&+20b%zVRrtSjG4 zOXsIea)Qg>QD6kZFwwmIwkTM%`*MX$gMGcv{S{l)Fa(tFSEiscq2i&|w=dzZltd-F zO9{JpgRG~pi@8qS#;E|Ziy21`Ksc~J5+c6u%Yo8^sTLG3Mgqmo>e%`@5=*&4fnpRq zl~0Bl1$bbLRVv}bj6!8X(Lt@R5unexHM;ZvKrv-(F^b`f&8_JZr-BQhM3(d&WS#QjB==Lo)^qRzLuPHBE{q;@@!>!&-_ zA}QNn6hD^L;Y8e#h`cZ1y?jD!cL8zg1c+5N)}kg6o2*uf6(Fm_Hj?gz>ikfyA~l|Z zmogs8wY9M*Z#qL`$q>6gm9Sn`3#*-nvOln%DKbVQ`%$+lYMYdlP*W^f~tt`Yb&;o$q^ub*N3v4F39&Tu&;jlfi30hH+gP zfi@n)f~6sm_C)rOnj^92F{Z;vl(|o3o>s?>%9Pp{x9TaK3{|uw{W(&g&4q3zQFwXZ&jSgy~KL&DiWbD5%u^3 z5`$jKt;;p6hUH7{gcRf4A^aGMRPe8g3`5fZ5zJmzJx&-4CjI*o24;Uq25lTKbqH@dBaLX>DTyIOc zpRS@@0*$rY*cja212=bcHfD{=V%FFT*_rMk38=3M4d_}7&Li+~0vlp$i)Ni6zO*;8 zS6z3sZ(0D5;5IhI%vu}DqA)p27CwdgFc_LUy12++!3Y9Nu z%hpp+G|}|1lnr-w9phP{Jf8Q`y&=}iA~2Faunb=2E%x�gWbaF+g*XGwH1yRIv{u z9YTONU9MHGx~+}LUA%^vf&v9^vBP#t#v`F5TLv7Wd8tj zWl*pY0xD{0c{o~Hhv@*#A#3IWP{{{`~h+*D>MBDdr z12!xOEj@;wU|~<|#woXu7Q<3(AA&V)P;}dS#G&8l_uOpij389g456p40GQvS)olvq z)(^5zz|Ak8n>T3SRe6cKMG#dUSc2GtU-JGRFkOxg%;0lB$ZaHFB<_EZhuS`E!@Ha1 zYRc#UAkzj$57+%53F7FzwNBsVn^OY=BpxABL0Q_N5UT8`BcOqicRZS;GRnHWxvc5cIx)t^l;JhSinQ zkyx%_InqU6l(%K6(l8|E*aB1si8HoL>o>9&*zy|wL(ANi8k%rP zVz>l4c2gznhDmG&Eu4_ND=~xZm1I85j)lm5D$;=IC;s=w|01E@`v;M>9pI)_#M@AI zOzU393f(Oq!$y=b|F1%Bv;(oPeKNSKJqz$W?}M(>MGL#-RnQP)m%j?J|Nk5+ycmW0 z*fUugg~UvI7A&MkDiQ7q-n*JO9Yuv{#e2Ow=)tVLREfZ1 z4>|_>T_Ex6X*cFrQe2=b>>#ayC8l5*v;`sc&NDM#lZBE|vGuP9ThI7D^#(-U}}Z zIj}|%jwLG>*E&TpQBdNKYqdtL)G|!5yQ=|OUzcI6?S@h6uQJSF_reBmSq~`75;RrX zdq67+&=LJ*wamWlGG!QKYZ<3FiNm`eJVFSOJY_xYNaoKNeT*9~=qx2NV=cFwjr0KbP$tZC5fUc{yuGKrQprCc5G zi)WG$=A!cb(s_Gl)-|GWd5r36KsRgGQe5q1<1!^45Aegv0Z`-vg(DA09mO*4hBNc^ zx#y<#{sA?LU$Na=8ogI=VNIky>FKvE@E2o^p4k5?Z<1b9OZQY!RRxwE@T0 z3KXcY=0|nB|92hi=Aur3SKSPo$uYJg+J02;?*i&eyG(Rq)dx#wYDHrOY)QMa7E#m6 zib>r7jl!fZ6bt$`3*xX$>Nj19vq{9v*e0<=sS8L?bz`2LFY4(~Es2C*B zqdQnKEd%P|2fU%;>%|62^*X2XTra5fyPoNMtrzQEW=l_Xi2cbIK(Tq8H}jMhmCnfT z?9B$-N>ki2@=sJ`lQq)aQW^Ped|73UTYv;_1OpKx5j*y{nu}-qv0jpV^B-R5$Ldu1 zq7-8P4Dx%TvEujy3ZVY7qO2^*o`Mn@k!*9-eJz1Eo;>Tk4LR2}e#!?}wGV`lA3qZ1O;x@73 zmw??WK^}uEvj$RyR_T00Wyk~XOY_r|_yLJWm4VN}fAze!%rd0D@AQ0;404i?*ekP0 zucvLv`Bq0ZPLKY&yQbS1Uqtfe!Qge+$=7^XFzZn1)@wa(w2cxw z`{0i3G31&^S2KziSc!Ftd9+1KrcTfoSP8)_Wt<(v|Gv% z1OA~bUYdeZy+T>26xB4H&kkiCQctMKs!&!bJ~f5L%M^LLAQ8I)xCM%y_lalwo5?Ep zm<5~yQ$gS}DtKvfI=2tQm|yim&s&Eve~4nvb3Gpx#%e&DtG%%D#@1!p6gWbN8>tCB z*n^T48~`L`YKwde#xW!_VC>1ugtN_3FchR9oF(`iNFXeBt8zf^d1~*4E%7pCH7MBw zBw{Eruz5P~QVssv5#&s)20~9GF%O`iGcBnN99RkaH$#4dZt2-oJUg9DO6M1=u{lyb zR2W#D^^}62>iOyFf+UY8dj7mRyDwFM+;2oMgB1T*&j;0Dk$!29Kq7SaPvRS3%Y^_R%9f-(Q1Ova5a@yQMd4upz#iAL?yPHvy%0=n%3^)6le6dKA`BgEiUYat2>F z6e@Ie@z3I6RalZ#@SsS`7a%FLycH5VYO!Rn`+cFFm#xhjOFbUw^V`&BjWm)svgSsz z!_v^ja7Ck7grwZp^Vw0XGftL|ne_Z|6zk;K^1j|?4^Xh4b>XC_5sG!M!+fMj6dF^9 z)vRjs?ipr+wZaL5uknu&gC_g-aChNHCBnWToQFIqqn=-^19csSij|_-Q0cVcKA#nh z#l`QukpC9VLcN9;5~ntM5!GN=7J5dY&^>*=Yh89sBRP8DET$f-2esLA$Er3kf`wQp zLT&cDe5QK@+4_{9>fjlRwdPTr3P))7sFZSTudKUOLaC#4#ia zVnOP&zxCX{0c$AjyQ$~R8nAeD*8J}hosGu!EjsG~2V+SCbS48xoh2f_L}ynnqO&Uv zSR-j=O$!~tbyYgNy4-}m4AmBMj68vdvkLj9hU5vb&>MPwwINvW_jNsIalooJfc@hb zb1;N|c^!J>#{0Ol=28&gcj7QGzMEOd9phPTuQ1|E?&gS(#L*MQAdaB?G4X7bMmm6* zoFxdE4Ew7DWfxR7&IEW=0w`+-NW5ysg81vEtU4x?tAFZwXfrkz1F0L5Ynrh{$qfmV8R)#^ z4`_R?J^=S%%>4sXbRyGB;YeIgWZ{zT3dUU$yXR=I-+z$^2rqk4&)+Apo^_&8PdyYa zK1L2ho`@B?f~ynBg7zUBmUGk^Z&V4DziZAWNj)*Ny;`tEu=D?(*YjO1*hJfaxx7I# z7L64yfN9C>8>z#{`@Bp`4D2iLCF-|iArrx$J6P0; z(Opq%&ggl!)^J8UBk@aXreqrbcEGOT)_uUlTGMzQdGsLW4-1;&v zlHRw`%Tk=y5uaf5@U)6N6yHi~O{3|iN-WI)AliRhyj>P2CdLGt> zHS%hz7V@&};>-ghVPXND+J?Q9YMj#NPxyjO(MVta1`E`VwRNlio8D^0;lf5CyKg%< zSjtH~&uPbgfu5iERnP0UXI-J^{gGVIo+Ue1`c+kLsID9GUbScam1W2E7=D|FKp6BD zfd=ZVK;YGoc%126QF29suD+C>9fNJ&r&N^BA44;_n{7}F z%4l2{kAo{iDfJ2z;be6Mjx+Zu3DQ7RiHHx@O6`$|4|LW_u}GY*6sfJi&XHLE0E}dAgR(k;w_^9m|D03SJM^EYUZ*RD+6RVYZ`y|Y0 zhdpL9?ZY;thd$Vb79oOeC-8J0Pw@UN8@Jo2z}fvGiz+zN^Nj;yr}l5SS%?q;W-vKLqmekP?0I!R^U^oCP1-M2@u=zN^4r=v0 z0WJ@&bnnc(aWc{k>H+WKsGd*k%shI*-4q$8kE%#@IE%WumqpWUMcu6eV(Iya3E(km z&y@stZb@)=?2enNsAn=x0z48Oz3I&S8;n4?LY-yD7n8n@p4($J{CYRy#&flY{jmAm zUnpxMaJ8_Wc-bBSjAm^;w9&o`3z3`&>n?1JROYarf9S&Eq^74J_pYphwB?YVckRlW z$PZG}#D<<>@^&;Plm;;&*olA=P>!+Ui8uUESFCND|N4f%?8>V8=7M>mh-n%*s8rZA z9w~&89faa{V+*BPNL=lPN^cM7xl?!GatevM-C@&pNG$D+HJ^FEo;&ow$hn6^a1Yi; z8ji$wJy?_!gT%=m?3|?Ahr&JCVdp#5a6_gYG#rPpT_vrK6r8C@+9bXXb*>YW0A#bE- zL9Tf_AfTQ}xjitV*>^kie7GJ9s(NRaG;0Xg0}TzUBa$8VNk%@i!gQ#`CLaQAHyU4A^9hMFslHa zNbvsY6y{a2Fa$$t9jd`pp>aIqiHCYy_5Az(EJf-GX&U=OlP4hIJ%EM7@tm;*C5v_| z!7?o6&%im z`o+gb-qJe?h}#j5Gem$IJx7RI+5?0NqJ5&p;|w{4KOew6?cTP=BFJeVw$NwVrSobz zP`Av@aAyXx%ARfdn=n5#QO7z~;h4nqoAi9+K-Qp4`*OsI)^K#+420+(Zq#$1K`e+F zVjtZgF$Ql|&0b|}Qkr6L+y^VMPmGnQ?fU$*K}@5Onxm3#Fk6Ypf+HKOjKY$X)*@Kd zl!v4IX(-c62*tXsyA*YZV-;cm&=g;SQ_mQ&jq~MGw|t{Vb@qZ@7_|fT%Qj zEMlExKjanvW(cc@y@h|EMpQzuDc8RIN-X_{4g-6x*`)IY!&oTy7>b>S6YJp=3}u1Q zi!(ms(UxCmvR+0ukwQY&&D50G-bapEJLwlaKYK!n(>6rWBtvQI42<(fMhupmJS0z) zc{-HENPn)=Nhj!gLUd)*Z%b+v&PMQv@qQ zKco>WVwH;PFy`#CkB@K_(~nu(1!?*rrJ1MOh$i9>(g}bx1_0SH0oj zE+cTfbKz&9fR%Ww5v*o~t50#Uo*^MlFcvQ#jg2#F`+yL^+0H2X%LwN0{`hA-wr6SA zLfp%`p(!xDF@ou&d*7LO;#aJTR2D^-f5rAl%~u2Gk=V2GM9%7wu%{krBzVg$GZ-Ae zGGvvWKN^X3)tQxgUS|{=E@_bS%P35zp2&GR3e)MoEA+hFXl8(MsK3%GA*`pJ=z?`a zWFD3h>qkREUZ`*y2}FS%p}M1)hx_XX>Iiog4zE*}wh&1CBceJXCCr1So5Yj)}7Hk*1H>myk%IMR;qD?(9Jb8@)e= z$2gc$?Ta+-_r@<&s(@y0jAt=%2K)S_*6tv!QkXixPq?(7S*TlLv8@JMeup~5=0EJL zY>r2RgpBQ%Mm}Q#^U@gk@(DQ2>opTQ#nrN)AUB_-@x&~c;j>HhT*+iH(3GJ|O7<;Q z`H}Cj@EDT`Qd^?jk4S*jcSs5$hH=9L=54$50e_H5v#<6WjFU21EYNQDJcvsO;{v4ZD(Z&mPtk5v?WdoBVB zPH2?&1zqtAv$hM%4&1G^2wTOISSbAdfg)oXGK`a0ATp9fMptBbOoofPbAg_>oQyr7 z;YfTp8E4YRi3!ksNVaf63G|0S2GFXRC-ift0Q;jTAAkg~AFjm5VmMZypH94O0J4hpC)6RaHqltc`UOxG+?{-r@Cy$!INe{aayLRXA6ehh zORS&c`@B%a*XP!cm`lbGqd9Cl7~KVHUR)eLA3H%)nGg7i(?4YRBO_%htK~TH2UG}0 zh3wnTd`NCzFX!&ap#TZIO;Z-7woYZkeXh(S!|{RQv|N%56C5l)>!Epio-mCal%^gt z@iNmfD~&}??dhyNoRK8dDblIMs_A@xbo0F$+`L55_drAVm4ls=gh!@r15vtc3U= z#&HA|0wy+Sh()wPB+NK_Fh_5*a|6@>Z>Vy&t8NwfJuHW8ZD;avGjLpDKS$4hMk2I8 z@MH2B=w{A$e+pf1fav~L&mF&Efe8kuY{Kbt z(QgCFMV-MlS3Py7W|q>b3+nVp1C|OL>fKUtkYqG{?i@SEP%jsY*)rzd% z_qnL!0J19VM${ou*H-gNDlAC>>x`a69k8BGk8qY}(QmHPtUpw&=asSX$I!yd8*2V> zOa3bLar_|6Xme-6%`5$P8s9gQg-H&xu`@N3CBW|G%__mUSJ;rldUqU_>n&!%oftC< z{_QMQ$!FL_wJRDj;w2JwBzd5nWwTgaJM9tcSUGe<9V@6v<-H=9KO9b42Y8u6V_3+UY4gEPF@K|R)g6i!1EAFy!8=esP~U9pE{TBKeheo{cbu|N=R1bBkHO@Y>ZiZ5mGJm#)^K33OaSG2($}2a`JojOlq2gQ^UDf`9&ddX)e^l z5s7zmVd?HohgIRoIgCUj&Vs7tO^4J|X<+3XEm|Wui#5Xc0JY5dx3Dt(^D}G5qt3S+ z$5n-B?mTA`q%O#5KaaJS`c2dGb@MP0G(_UeJoHo^3An>P+~o)CvW&x1tsht|uV1Fp zq6nrA>)@Q%rfUdPHEU;2)$<8}I+vSM8qu{PF9mr8Kd>QEE~?i2krlM7m@W26tT!37 zkM9`YA-;WlyS9lF9|Y6rf#Qh}g`9UdI8VgzpFM;eFuRF~nq%f0B3P{ogn)PZ)vNx> zV)LNMd=_EX7UlTp`7GKlhEiMSvs!j91|#)gJ`1y-0A&6#{BEfa+h;^eD5(`>{aLq{* z_4(P0SVxVg4eI3_rq6%W5g+Bku1ste}*dt-f1byjHPzo8BAZL^6T!}9L8WLngf{sRY4PWN zI(4G=pz!kg5WF3eiBp25tgW;W?M+>ZaEKp(=EbG#vMpP%pW4AYh%_zdMlM}UVS}RT z9GRwS>{^V)9_(^9E-Yazj=Ui&n*#c`7eGLxkSR{)I$}P-Z2-7&z;75-W&8?OUurQL z9{vheRq{i^v;tuPyGLR2Sjh%Swb1JBl^84va&E3Pnuu?wH$Y@Bh}UX z%o_SlIhqDy+tEu{_{x?TH*@4H(1C@N!zo^ar)VY9=`{Y;ξ(fW)4kS)9x35fD^Z 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 z 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