如何在RocksDB中实现ConditionalPut?探究CockroachDB的实现方案
CockroachDB 中 ConditionalPut 的实现
CockroachDB 的键值 API 提供的 ConditionalPut(key, value, expected-value),底层基于 RocksDB 的能力实现,核心是原子化的读校验+写入流程:
- 整个操作会被包裹在 RocksDB 的事务中,避免并发操作带来的竞态问题。
- 在事务内部,先读取目标 key 的当前存储值,和传入的
expected-value做对比:- 若值完全匹配(或 key 不存在且
expected-value为空),执行 Put 操作写入新值; - 若值不匹配,直接返回操作失败,不执行任何写入。
- 若值完全匹配(或 key 不存在且
- 最后提交 RocksDB 事务,确保整个读-校验-写流程的原子性——要么全部成功,要么全部不生效。
注:针对分布式场景,CockroachDB 还会结合自身的 Raft 共识协议保证跨节点一致性,但这属于上层分布式逻辑,与 RocksDB 底层实现无关。
RocksDB 中实现条件 Put 操作的方法
RocksDB 原生没有直接提供 ConditionalPut API,但可以通过两种方式实现类似的条件写入逻辑:
方式一:使用 Transaction API(推荐,支持并发冲突处理)
这是最可靠的实现方式,利用 RocksDB 的事务机制保证原子性和并发安全:
- 通过
TransactionDB::BeginTransaction开启一个事务; - 在事务内部调用
Transaction::Get读取目标 key 的当前值; - 对比读取值与预期值:
- 匹配的话,调用
Transaction::Put将新值写入事务; - 不匹配则终止事务,返回失败;
- 匹配的话,调用
- 调用
Transaction::Commit提交事务——若提交时发现 key 已被其他并发操作修改,RocksDB 会返回冲突错误,上层可按需实现重试逻辑。
方式二:手动结合快照+WriteBatch(仅低并发场景适用)
这种方式无法处理并发冲突,仅适合对一致性要求较低的场景:
- 调用
DB::GetSnapshot获取当前 DB 的快照,确保读取的是某个时间点的一致性视图; - 通过快照读取目标 key 的当前值,和预期值对比;
- 若匹配,创建
WriteBatch并添加 Put 操作,调用DB::Write提交批量操作; - 最后释放快照。
注意:这种方式下读取和写入之间无锁保护,若期间有其他操作修改 key,会导致条件校验失效,出现不符合预期的写入。
内容的提问来源于stack exchange,提问作者databasechaser
相关产品推荐
相关产品推荐

