动机
#199(struct 提案1)确立的创建语义是克隆原型 + 覆盖给定字段:Point{x=1.0} = 把定义子树 /lib/Point·(默认值原型)拷到实例根,再覆盖字面量给出的字段。这需要一个子树递归拷贝原语。当前 kv· 系列只有
get / set / del / deltree / list / listlen / listn / mkindex / extindex / rmindexext / watch
没有任何拷贝原语,只能在 runtime 用 list + get + set 逐成员搬运——每成员一次 KV 往返,正是 #116/#194 指出的解释执行瓶颈。struct 创建是高频操作,逐成员搬运不可接受。
因此新增两个 kv· rwir:
kv·cp(src, dst) —— 拷贝单个 key 的 XValue(src → dst),不含成员子树。对齐 unix cp。
kv·cpdir(src, dst) —— 递归拷贝以 src 为根的整棵容器子树。对齐 unix cp -r。
语义
kv·cp(src, dst)
- 读参
src(路径),写参 dst(路径)。
- 把
src 处 XValue(head + body 原样,kind/dims/值全保留)写到 dst。
- 不触碰
src·(memindex)与任何 src·* 成员——纯单 key。
src 不存在 → runtime 报错。
kv·cpdir(src, dst)
- 读参
src,写参 dst。
- 递归拷贝三层容器结构(
kvlang-container-memindex-split 方案2):
src 值 → dst
src· memindex → dst·
- 每个
src·k 成员 → dst·k;成员自身是容器/struct/extindex 则继续递归。
- 即把 key 前缀
src 整体重映射为 dst,语义等价"深拷贝子树"。
- extindex / 扩展存储:成员若是落扩展存储的大值(
kvspace-meta-extension-split),cpdir 须正确复制其扩展句柄指向的数据(深拷贝,或后续可选 CoW)——不能只拷元存 slot 而共享底层 buffer 造成别名。此点是本 issue 的主要设计风险。
支撑 struct 创建
lower 大致为:
kv·cpdir(/lib/Point·, p·) # 克隆默认值原型子树(含 y=0.0 默认)
kv·set(p, <marker kind=/lib/Point>) # 实例根标记,kind=类型路径(区别于定义节点 kind=struct)
kv·set(p·x, 1.0) # 覆盖给定字段
(marker 与覆盖的精确顺序留给 #199 的 struct 实现;本 issue 只提供 cpdir/cp 原语。)
实现:必须落在 kvspace 层(本 issue 的核心)
加速是本 issue 的目的,cp/cpdir 必须由 kvspace 层直接支持,不接受 runtime 用 list+get+set 组合的客户端逐成员搬运(那正是 #116/#194 的瓶颈,等于没做)。因此:
- kvspace C ABI 新增两个符号:
kvspaceCp(kv, src, dst, …) / kvspaceCpTree(kv, src, dst, …),进权威 ABI(当前 24 符号 → 26)。两后端各自实现,拷贝在后端内部完成:
- durable(redis/fs/s3):服务端 COPY / 批量管道 / 目录级复制,免客户端 O(members) 网络往返。
- shm:共享内存内直接 memcpy 子树 + extension 段,零网络。
- kv·cp / kv·cpdir rwir 只是这两个 ABI 的薄封装,不在 runtime 侧展开子树遍历。
- 落地顺序(
dev-order-bottom-up):先 kvspace(c/durable) 实现 cp/cptree + kvspace tutorial 验证 → 再 runtime kv· rwir 薄封装 → 最后 tutorial。
待定问题
dst 已存在时:覆盖 / 报错 / 先 deltree 再写?(建议 cpdir 先隐式清 dst 子树,语义确定)
- extindex 成员:深拷贝 vs CoW(先深拷贝,CoW 作后续优化)。
- 跨后端 cp(
src/dst 不同 kvspace 实例)是否在本 issue 范围(建议否,先同实例)。
- ABI 签名:
kvspaceCpTree(kv, src, dst, err, cap) 返回复制成员数?是否需原子性保证。
关联
#199 struct 提案1(本 issue 的直接需求方,克隆原型创建)
kvlang-container-memindex-split(三层容器结构,cpdir 的拷贝对象)
kvspace-meta-extension-split(extindex/扩展存储,cpdir 的深拷贝难点)
#116 / #194(逐 key 往返开销 → 服务端拷贝快路径的动机)
dev-order-bottom-up(落地顺序:kvspace ABI → kvspace tutorial → runtime kv· rwir → tutorial)
动机
#199(struct 提案1)确立的创建语义是克隆原型 + 覆盖给定字段:Point{x=1.0}= 把定义子树/lib/Point·(默认值原型)拷到实例根,再覆盖字面量给出的字段。这需要一个子树递归拷贝原语。当前 kv· 系列只有没有任何拷贝原语,只能在 runtime 用
list + get + set逐成员搬运——每成员一次 KV 往返,正是#116/#194指出的解释执行瓶颈。struct 创建是高频操作,逐成员搬运不可接受。因此新增两个 kv· rwir:
kv·cp(src, dst)—— 拷贝单个 key 的 XValue(src→dst),不含成员子树。对齐 unixcp。kv·cpdir(src, dst)—— 递归拷贝以src为根的整棵容器子树。对齐 unixcp -r。语义
kv·cp(src, dst)
src(路径),写参dst(路径)。src处 XValue(head + body 原样,kind/dims/值全保留)写到dst。src·(memindex)与任何src·*成员——纯单 key。src不存在 → runtime 报错。kv·cpdir(src, dst)
src,写参dst。kvlang-container-memindex-split方案2):src值 →dstsrc·memindex →dst·src·k成员 →dst·k;成员自身是容器/struct/extindex 则继续递归。src整体重映射为dst,语义等价"深拷贝子树"。kvspace-meta-extension-split),cpdir 须正确复制其扩展句柄指向的数据(深拷贝,或后续可选 CoW)——不能只拷元存 slot 而共享底层 buffer 造成别名。此点是本 issue 的主要设计风险。支撑 struct 创建
lower 大致为:
(marker 与覆盖的精确顺序留给
#199的 struct 实现;本 issue 只提供 cpdir/cp 原语。)实现:必须落在 kvspace 层(本 issue 的核心)
加速是本 issue 的目的,cp/cpdir 必须由 kvspace 层直接支持,不接受 runtime 用
list+get+set组合的客户端逐成员搬运(那正是#116/#194的瓶颈,等于没做)。因此:kvspaceCp(kv, src, dst, …)/kvspaceCpTree(kv, src, dst, …),进权威 ABI(当前 24 符号 → 26)。两后端各自实现,拷贝在后端内部完成:dev-order-bottom-up):先 kvspace(c/durable) 实现 cp/cptree + kvspace tutorial 验证 → 再 runtime kv· rwir 薄封装 → 最后 tutorial。待定问题
dst已存在时:覆盖 / 报错 / 先 deltree 再写?(建议 cpdir 先隐式清dst子树,语义确定)src/dst不同 kvspace 实例)是否在本 issue 范围(建议否,先同实例)。kvspaceCpTree(kv, src, dst, err, cap)返回复制成员数?是否需原子性保证。关联
#199struct 提案1(本 issue 的直接需求方,克隆原型创建)kvlang-container-memindex-split(三层容器结构,cpdir 的拷贝对象)kvspace-meta-extension-split(extindex/扩展存储,cpdir 的深拷贝难点)#116/#194(逐 key 往返开销 → 服务端拷贝快路径的动机)dev-order-bottom-up(落地顺序:kvspace ABI → kvspace tutorial → runtime kv· rwir → tutorial)