父 issue:#10(kvspace-cluster / 主动管理)。本 issue 是其下的具体机制项。
背景(现状事实)
kvspace 前端是纯派发层:每个 kvspace* 调用直接转发到后端 vtable,中间无任何同步——
// src/frontend.c
kvspaceGet(h, ...) { return x->vt->get(x->backend, ...); } // :148-149
kvspaceWriteInPlace(h, ...) { return x->vt->writeinplace(x->backend, ...); } // :154-155
// … list / del / cp / watch 等 27 个符号同构
handle 就是 { vtable *vt; void *dl; void *backend; }(frontend.c:45-49),没有锁、没有屏障、没有"后端忙"状态位。
kvspace-c 后端(shm://)即将获得运行期扩缩容能力(array2d/kvspace-c#18 拆分 key/value shm + 分区 ftruncate+mremap,依赖 array2d/kvspace-c#15、array2d/slotsboxmalloc#2)。mremap 会改变映射基址:扩容瞬间,任何持有旧基址派生指针的 in-flight 读写都会读到垃圾或段错误。更棘手的是 shm:// 是多进程共享:一个进程触发 remap,其它进程的映射并不会自动跟随,当前又是无锁访问(见 #10「一致性模型」待设计条:slotsboxmalloc rw_lock 未启用)。
即:扩缩容与外部读写之间目前没有互斥,remap 一旦落地就是数据竞争。
目标
在扩缩容期间,kvspace 需阻塞当前的外部读写请求,直到扩缩容完成——一个读写屏障(barrier):
- 后端发起扩缩容前,前端进入 draining 状态:拒绝/挂起新的外部读写请求。
- 等待所有 in-flight 读写排空(drain)。
- 后端执行
ftruncate+mremap(各分区独立,见 kvspace-c#18),更新基址/容量。
- 屏障解除,挂起的请求以新映射恢复执行。
对上层 kvspace* C ABI 透明:调用方感知到的只是该次调用延迟变长,不改签名、不改语义。
落点与约束
关联
背景(现状事实)
kvspace 前端是纯派发层:每个
kvspace*调用直接转发到后端 vtable,中间无任何同步——handle 就是
{ vtable *vt; void *dl; void *backend; }(frontend.c:45-49),没有锁、没有屏障、没有"后端忙"状态位。kvspace-c 后端(
shm://)即将获得运行期扩缩容能力(array2d/kvspace-c#18 拆分 key/value shm + 分区ftruncate+mremap,依赖 array2d/kvspace-c#15、array2d/slotsboxmalloc#2)。mremap会改变映射基址:扩容瞬间,任何持有旧基址派生指针的 in-flight 读写都会读到垃圾或段错误。更棘手的是shm://是多进程共享:一个进程触发 remap,其它进程的映射并不会自动跟随,当前又是无锁访问(见 #10「一致性模型」待设计条:slotsboxmallocrw_lock未启用)。即:扩缩容与外部读写之间目前没有互斥,remap 一旦落地就是数据竞争。
目标
在扩缩容期间,kvspace 需阻塞当前的外部读写请求,直到扩缩容完成——一个读写屏障(barrier):
ftruncate+mremap(各分区独立,见 kvspace-c#18),更新基址/容量。对上层
kvspace*C ABI 透明:调用方感知到的只是该次调用延迟变长,不改签名、不改语义。落点与约束
frontend.c的kvspaceGet/WriteInPlace/WriteNewPlace/Del/…)还是下沉到各后端 vtable,需先定:shm://跨进程共享,屏障状态必须落在共享内存里(如kvspace_hdr_t增一个 epoch/版本号 + 状态位),各进程访问前校验、remap 后按新 epoch 重映射。这是本 issue 的真正难点,纯进程内pthread_rwlock不够。关联
mremap)—— remap 换基址是本屏障要保护的具体动作。