SuperAPI AI 工具集

allocator-migration

编程与开发

查看项目

更新于 10-16 04:36

技能介绍

用途

该技能面向 Turso 核心代码的分配器迁移工作,尤其适用于以下场景:将标准堆集合替换为 crate::alloc 别名,或为分配路径增加可失败(fallible)分配能力。

核心规则

  • 在迁移模块中使用 crate::alloc::*。
  • 保持调用点名称稳定:Vec、Box、HashMap、BTreeSet、Arc 及类似标准名称。
  • 新的分配器专用名称使用 Turso,而非 Limbo。
  • nightly 分配器行为使用 cfg(nightly),而非 Cargo feature。
  • 除非用户明确要求,不要修改 set_allocator。
  • 目前 Arc 与 Weak 继续经由 crate::sync 路由,以兼容 shuttle;分配器感知的共享指针留作 TODO。
  • 除非测试阻塞编译或用户要求,不要将测试迁移到可失败分配。

导入模式

对于迁移模块,优先使用单一分配器命名空间导入:

use crate::alloc::*;

然后移除冲突的导入,例如:

use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque};
use std::rc::Rc;
use std::sync::Arc;
use std::vec::Vec;
use crate::sync::Arc;

仅在未迁移类型仍需要标准库集合的狭窄边界处,保留显式的 std::... 导入。

构造器

在使用 use crate::alloc::* 之后,使用常规构造器名称:

Vec::new()
Vec::with_capacity(capacity)
HashMap::new()
BTreeSet::new()
Box::new(value)
Arc::new(value)

分配器扩展 trait 在底层按需提供分配器感知的构造器。

当某个方法变为可失败时,优先更改返回类型,而不是重命名方法:

pub fn new(...) -> Result<Self>

不要仅因为返回类型改变就把方法重命名为 try_new,除非本地 API 已使用该模式或用户要求。

可失败分配

在返回 Result、或可合理改为返回 Result 的迁移生产代码中,使用可失败分配 API:

try_vec![a, b, c]?
vec.try_push(value)?
vec.try_extend(iter)?
vec.try_reserve(additional)?
Vec::try_with_capacity(capacity)?
iter.try_collect::<Vec<_>>()?

尽可能直接使用 ?。TryReserveError 会转换为 LimboError,因此避免重复的手动错误映射。

当 try_with_capacity 或 try_reserve 已处理容量失败时,不要添加手动容量溢出检查。在添加检查或重构分配逻辑之前,先与之前的代码进行比较。

迭代器收集

使用 TursoIteratorExt::try_collect 进行分配器感知的收集。

支持的模式包括普通集合、Option 和 Result:

let values: Vec<_> = iter.try_collect()?;

let maybe_values: Option<Vec<_>> = iter_of_options.try_collect()?;

let result_values: Result<Vec<_>, E> = iter_of_results.try_collect()?;

对于无效项应产生 None 的解析场景,优先使用:

let parsed = input
    .split_whitespace()
    .map(|s| s.parse::<u64>().ok())
    .try_collect()?;

String 与标准库边界

String 在 stable 上并非完全分配器参数化。当迁移代码仍执行字符串格式化、to_string、format! 或 join 时,除非用户要求,不要过度迁移。在有用时添加聚焦的 TODO:

// TODO: make this formatting allocation fallible once String is allocator-aware
// in the Turso allocation namespace.

某些中心类型在单独迁移之前可能仍使用标准集合,尤其是:

  • Value::Blob
  • record payloads
  • 共享指针内部
  • 外部 API 表面

在这些边界处,显式的 std::vec::Vec 转换是可接受的。保持它们狭窄,避免将标准集合导入扩散到迁移模块中。

迁移工作流

  1. 检查模块及附近的调用方。
  2. 在简化检查或更改容量计算之前,与之前的代码进行比较。
  3. 添加 use crate::alloc::*。
  4. 移除冲突的标准集合与指针导入。
  5. 转换构造器与变更路径。
  6. 在适当处让承载分配的函数返回 Result。
  7. 在生产代码中一致使用可失败 API。
  8. 除非必要,保持测试不可失败。
  9. 检查格式化与编译。
  10. 为每个连贯的迁移切片提交。

提交边界

将基础分配器工作与迁移分开。

基础提交包括:

  • core::alloc 中的别名
  • 扩展 trait
  • try_vec!
  • try_collect
  • TryReserveError 转换
  • 分配器后端设置

迁移提交应聚焦于模块,例如:

  • RowSet
  • VDBE arrays
  • sorter
  • stats
  • schema
  • statement
  • virtual tables

在每个连贯切片后频繁提交。

验证

对于普通迁移切片,检查格式化与编译:

cargo fmt
cargo check -p turso_core

在分配器敏感提交之前,还要检查 nightly cfg 构建:

RUSTFLAGS="--cfg nightly" cargo +nightly check -p turso_core

对于分配器集合性能工作,使用 Divan 对比脚本。它默认运行 alloc_collections 基准,并打印排序后的 std 与 Turso 对比表:

scripts/compare-divan-std-turso.py --run

要运行 nightly 分配器路径,执行:

scripts/compare-divan-std-turso.py --run --nightly

有用的变体:

scripts/compare-divan-std-turso.py --run --bench-filter hash_map --filter hash_map
scripts/compare-divan-std-turso.py --run --save-output /tmp/alloc_collections.txt
scripts/compare-divan-std-turso.py /tmp/alloc_collections.txt

仅当触及的代码路径有风险、行为发生变化,或编译不足以验证迁移时,才运行聚焦测试。

适用场景与限制

该技能适用于 Turso 核心代码的分配器迁移,包括将标准堆集合替换为 crate::alloc 别名、增加可失败分配路径、以及分配器集合性能对比。限制方面:String 在 stable 上并非完全分配器参数化,相关格式化代码不应过度迁移;某些中心类型与外部 API 表面在单独迁移前仍使用标准集合;测试默认不迁移到可失败分配;set_allocator 除非用户明确要求否则不修改。