CacheSQL(一):手写数据库的工程化重生
CacheSQL一手写数据库的工程化重生写过一套 2000 行的 B 树手写数据库当时觉得能跑了。放了一阵子回头看发现能跑和能交付之间隔了十万八千里。CacheSQL 就是这段回头路走出来的。同一个 B 树内核但外面长了三层新东西复制、HTTP、测试。从原型变成了产品。一、原型长什么样这是手写数据库那版的核心结构com.bluepointsoft.database ├── database.java # 数据库入口HashMap 管理表 ├── praseSql.java # SQL 解析 ├── btree/ │ ├── BPTree.java # B 树封装 │ ├── Node.java # B 树节点核心1054 行 │ └── Tree.java ├── table/ │ ├── Table.java # 内存表 │ ├── Row.java # 行数据软删除 │ └── rowSet.java # 行集合 ├── container/myList.java # 自定义 long[] 数组 └── fun/function.java # SQL 函数桩这个版本解决了核心问题——B 树的插入、分裂、删除、合并、范围查询——但有几个硬伤没有测试。能跑但不知道什么情况下会崩。database 类用ConcurrentHashMap是原型遗留思维。手写数据库那版我开始用 HashMap后来多线程冲突才换成 ConcurrentHashMap但当时没有真正理解这意味着什么——不是锁的问题是一个项目需要从跑的 Demo切换到可交付产品。SQL 解析是散装函数不是引擎。praseSql.select_items(sql)、praseSql.select_table(sql)、praseSql.select_where(sql)——每次查都要调三个静态方法各自解析一次 SQL。没有对外 API。只能内嵌调用 Java没 HTTP 接口其他语言用不了。没有文档。别人不知道这玩意怎么用。二、工程化重生的五个改动2.1 项目结构从平铺到分层com.browise.database ├── database.java # 表管理 定时刷新 ├── SqlQueryEngine.java # SQL 引擎独立模块 ├── btree/ # B 树核心不变 ├── table/ # Table/Row/rowSet核心不变 ├── index/CompositeKey.java # 新增联合索引 ├── server/ # 新增HTTP 服务层 ├── replication/ # 新增主从复制 ├── core/util/DBUtil.java # 新增连接池 配置管理 └── core/exception/utilException.java # 新增统一异常核心层btree table基本没动。新东西全加在外面核心层连复制都不知道——ReplicationManager 对 Table 和 BPTree 完全透明。2.2 从 HashMap 到 ConcurrentHashMap手写数据库那版database.java 用的是HashMapString, Table。AI 审计时指出的第一个问题是线程不安全——两个线程同时 load 同一张表会互相覆盖。我换成 ConcurrentHashMap 时没多想。后来才意识到这个切换意味着什么HashMap → ConcurrentHashMap 这个决策本身是产品意识的起点——你开始假设这个系统会被并发调用而不是只在你自己的电脑上跑一个线程。CacheSQL 里更进一步。tables.putIfAbsent替代了tables.put防止并发 load 时创建重复 Table。refresh 时用tables.put(name, fresh)原子替换——先创建新 Table 实例加载最新数据完成后再替换引用刷新期间的查询不受影响。2.3 SQL 解析从散装函数到独立引擎手写数据库那版 SQL 解析是三个静态函数ListStringitemspraseSql.select_items(sql);ListStringtablespraseSql.select_table(sql);StringwherepraseSql.select_where(sql);CacheSQL 拆出了独立的SqlQueryEngineSQL 模板化 → 解析 → 缓存执行计划 → 下次同模板直接复用省掉重复解析。这个设计让后续加 HTTP 接口时天然就支持了 SQL 查询——不需要单独实现一套查询逻辑。2.4 从零测试到 53 项测试 6 项集成手写数据库那版没有任何测试用例。CacheSQL 加了两层测试53 项单元测试B 树 15 项SQL 引擎 11 项内存表 17 项复制模块 8 项并发 2 项6 项集成测试端到端验证主从复制的完整生命周期——写入广播、Slave 转发、幂等性、Master 宕机缓冲、恢复后自动重放不是说测试越多越好。但一个没有测试的产品你不敢交付给任何人。2.5 从零文档到 7 份功能说明书、部署手册、操作手册、测试报告、性能测试、两版审计报告。加上已有的 4 篇手写数据库博客——这些文档不是给评委看的是给未来任何一个接手这个系统的人看的。三、什么没变B 树核心逻辑几乎没变。256 阶和原型一样一次加载 256 个子节点树高度为 2100万数据软删除原型里的isDelete标记保留仍是 O(1)不移动 ArrayList 元素预留空间原型里 10% 的预留设计保留批量插入时减少分裂频率关键字校准 validate原型里那个踩了大坑的函数保留——分裂后父节点的 entry key 不更新就会路由出错不是什么都要重写。核心对了外围加工程化就好。四、AI 在这个过程中的角色手写数据库 4 篇博客提到的 B 树算法分裂、借位合并、二分变体、validate 校准有一些是我自己写的软删除、预留都是我的经验有一些是 AI 辅助生成的代码框架、文档结构。CacheSQL 的工程化升级AI 承担了大部分写代码的工作项目结构、测试用例、文档框架、异常处理、配置文件解析。我承担的是架构决策ReplicationManager 对核心层透明、OpLog 用定长环形缓冲区而非 ArrayList、insert 用 upsert 语义保证幂等——这些没有一个是 AI 主动建议的。用 AI 写代码用经验做决策。这就是从原型到产品之间AI 和人的分工。下一篇[CacheSQL二主从复制——OpLog 环形缓冲区与故障自动恢复]系列CacheSQL 工程化交付实录共 5 篇含桥接篇