承接 umbrella #212 第 2/3 项。关联 kvspace#9、kvspace-c#16;参照 kvspace-c#13(shm_set_raw 同尺寸就地覆写,已合)与 #116(跨后端验证范式)。
设计原则(p0/p2/p5)
砍掉所有分支与向后兼容,不做加法式:重定义并删除旧 API,不新增与旧符号并存的东西。每个原语走唯一正确方向,前置条件不满足直接 error,绝不静默"回落"、绝不用 bool/if 包庇两种所有权。durable 无常驻映射,其不可避免的那次拷贝下沉进 frontend 适配层,runtime 侧永不自己拷贝、看到的接口与 shm 一致。
现状
读一个值 = 两次拷贝(kvspaceGet 后端 malloc+memcpy + kvlangXvalueCopyMalloc)+ free;写一个标量走 kvspaceSet:runtime 侧 encode 完整 TLV + own 转交 + kvlangKvSet 合并 keys/lens/vals(≈5 malloc + 4 memcpy),即使 shm shm_set_raw 底层同尺寸已就地,这些 runtime 拷贝仍全额付出。shm 数据本在共享 mmap(read_tlv *out=sbo_data+off 即零拷贝指针)。
一、kvspace 代理(frontend + kvspace.h)—— 删旧立新
读:唯一读 = 借用,重定义 kvspaceGet、删拷贝语义
int kvspaceGet(void *h, const char *key, int resolve,
uint8_t **out, uint32_t *out_len, void **hold);
shm→*out 指向 mmap、*hold=NULL(零拷贝);durable→物化进缓冲、*out=*hold=该缓冲(拷贝下沉、Rust 侧零改动)。释放复用 kvspaceBytesFree(hold,len)(hold=NULL 即 no-op),不发明新符号。旧拷贝签名删除,消费者全迁移。
写:kvspaceSet 拆成两个一等原语,删 kvspaceSet 与 kvspaceXvalueBodyPtr
/* 就地覆写:key 必须已存在、kind 不变、body_len==原 body_len,只改 body raw;
违反前置条件→非 0 并填 err(绝不静默重分配/回落)。shm 直接 memcpy 进原 box;durable 适配层等价覆写。*/
int kvspaceWriteInPlace(void *h, const char *key, int resolve,
const uint8_t *body, uint32_t body_len, char *err, uint32_t err_cap);
/* 新位置写:分配新 box、写完整 TLV(=原 kvspaceSet),用于新建/变 kind/变长。*/
int kvspaceWriteNewPlace(void *h, const char *const *keys, const uint8_t *vals,
const uint32_t *lens, uint32_t n, char *err, uint32_t err_cap);
WriteInPlace 封装就地写、不再向 runtime 暴露 mmap 裸指针(取代 kvspaceXvalueBodyPtr);WriteNewPlace = 原 kvspaceSet 改名。
二、kvspace-c
读 kvspaceShmGet 已零拷贝;写导出 kvspaceWriteInPlace 后端符号(复用 shm_set_raw 同尺寸就地逻辑的 body-only 入口);WriteNewPlace=现有 set。
三、runtime-c —— 借用读 + 二选一写(无 bool、无回落)
kvlangXvalue_t 加 void *hold(非 bool);Free 恒 kvspaceBytesFree(hold,len)(借用 hold=NULL no-op、自持 hold=buffer 释放),消费者侧无 if。
- 读包装器
KvGetOne/KvWatch 走借用 kvspaceGet,省 CopyMalloc;KvGetBatch 多值聚合仍 own+hold。
- 先修悬垂
kvlangBuiltinExecuteCopy:nw>1 写前物化借用值。
- 写
kvlangBuiltinWriteResult 按definite条件二选一:目标存在且 kind/长度不变→WriteInPlace(零 encode/合并);否则→WriteNewPlace。判据取自本步刚借用读到的旧 head。
四、runtime-rs
engine.rs get 走借用 + kvspaceBytesFree(hold);写按条件调两原语;ffi.rs 删 kvspaceSet/kvspaceXvalueBodyPtr、加两写原语、改 Get 签名。
非目标
多进程并发锁 = 独立 issue:slotsboxmalloc 完全无锁(04_multithread 稳定 FAIL)、零拷贝裸指针+就地 memcpy 并发下有撕裂风险,属既有缺陷、单进程 régime 不触发,补根自旋锁另开(对齐 kvspace-c#13 尾注)。
实施顺序
- kvspace-c 导出
WriteInPlace(body-only 就地)。
- frontend+头:重定义借用
kvspaceGet、加两写原语、删 kvspaceSet/kvspaceXvalueBodyPtr、装库。
tutorial-c/07_zerocopy.c 对照通过。
- runtime-c:
hold + 统一 Free + 修 ExecuteCopy + 借用读 + 二选一写。
- runtime-rs 同步。
- benchmark 复测 + tutorial 237 例三后端全回归。
验证
对照 shm 借用落 mmap 区间/hold==NULL/与拷贝路径 memcmp==0、fs hold!=NULL 且内容一致;对不存在 key/变长调 WriteInPlace 须返回非 0(前置断言生效、不静默成功);tutorial 237×三后端逐字节不变;run.py -k iops 改造前后对比 shm 列落快照。
承接 umbrella #212 第 2/3 项。关联 kvspace#9、kvspace-c#16;参照 kvspace-c#13(
shm_set_raw同尺寸就地覆写,已合)与 #116(跨后端验证范式)。设计原则(p0/p2/p5)
砍掉所有分支与向后兼容,不做加法式:重定义并删除旧 API,不新增与旧符号并存的东西。每个原语走唯一正确方向,前置条件不满足直接 error,绝不静默"回落"、绝不用 bool/if 包庇两种所有权。durable 无常驻映射,其不可避免的那次拷贝下沉进 frontend 适配层,runtime 侧永不自己拷贝、看到的接口与 shm 一致。
现状
读一个值 = 两次拷贝(
kvspaceGet后端 malloc+memcpy +kvlangXvalueCopyMalloc)+ free;写一个标量走kvspaceSet:runtime 侧 encode 完整 TLV + own 转交 +kvlangKvSet合并 keys/lens/vals(≈5 malloc + 4 memcpy),即使 shmshm_set_raw底层同尺寸已就地,这些 runtime 拷贝仍全额付出。shm 数据本在共享 mmap(read_tlv*out=sbo_data+off即零拷贝指针)。一、kvspace 代理(frontend + kvspace.h)—— 删旧立新
读:唯一读 = 借用,重定义
kvspaceGet、删拷贝语义shm→
*out指向 mmap、*hold=NULL(零拷贝);durable→物化进缓冲、*out=*hold=该缓冲(拷贝下沉、Rust 侧零改动)。释放复用kvspaceBytesFree(hold,len)(hold=NULL 即 no-op),不发明新符号。旧拷贝签名删除,消费者全迁移。写:
kvspaceSet拆成两个一等原语,删kvspaceSet与kvspaceXvalueBodyPtrWriteInPlace封装就地写、不再向 runtime 暴露 mmap 裸指针(取代kvspaceXvalueBodyPtr);WriteNewPlace= 原kvspaceSet改名。二、kvspace-c
读
kvspaceShmGet已零拷贝;写导出kvspaceWriteInPlace后端符号(复用shm_set_raw同尺寸就地逻辑的 body-only 入口);WriteNewPlace=现有 set。三、runtime-c —— 借用读 + 二选一写(无 bool、无回落)
kvlangXvalue_t加void *hold(非 bool);Free恒kvspaceBytesFree(hold,len)(借用 hold=NULL no-op、自持 hold=buffer 释放),消费者侧无 if。KvGetOne/KvWatch走借用kvspaceGet,省CopyMalloc;KvGetBatch多值聚合仍 own+hold。kvlangBuiltinExecuteCopy:nw>1写前物化借用值。kvlangBuiltinWriteResult按definite条件二选一:目标存在且 kind/长度不变→WriteInPlace(零 encode/合并);否则→WriteNewPlace。判据取自本步刚借用读到的旧 head。四、runtime-rs
engine.rsget 走借用 +kvspaceBytesFree(hold);写按条件调两原语;ffi.rs删kvspaceSet/kvspaceXvalueBodyPtr、加两写原语、改 Get 签名。非目标
多进程并发锁 = 独立 issue:slotsboxmalloc 完全无锁(
04_multithread稳定 FAIL)、零拷贝裸指针+就地 memcpy 并发下有撕裂风险,属既有缺陷、单进程 régime 不触发,补根自旋锁另开(对齐 kvspace-c#13 尾注)。实施顺序
WriteInPlace(body-only 就地)。kvspaceGet、加两写原语、删kvspaceSet/kvspaceXvalueBodyPtr、装库。tutorial-c/07_zerocopy.c对照通过。hold+ 统一 Free + 修 ExecuteCopy + 借用读 + 二选一写。验证
对照 shm 借用落 mmap 区间/
hold==NULL/与拷贝路径memcmp==0、fshold!=NULL且内容一致;对不存在 key/变长调WriteInPlace须返回非 0(前置断言生效、不静默成功);tutorial 237×三后端逐字节不变;run.py -k iops改造前后对比 shm 列落快照。