SWE · 90 分钟 OA Coding

Coinbase 四层 In-Memory Database OA:读写、Scan、TTL 与 Backup

一篇 OA 题目明确四层递进为存读 data、scan、过期时间与 backup;本文以标注清楚的训练契约拆解状态与快照边界。

题目重点:一篇 OA 题目明确四层递进为存读 data、scan、过期时间与 backup;本文以标注清楚的训练契约拆解状态与快照边界。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 以下为训练版:每个 key 对应一个 value,set(key,value,now,ttl?)、get(key,now)、scan(prefix,now)、backup(now);原题可能是 record-field 结构,不能把此接口当原题。
  • ttl>0 时条目在 [setAt,setAt+ttl) 有效,now==expireAt 已过期;未给 TTL 则永不过期。时间戳按非降序调用,若允许回溯需另存版本。
  • scan 只返回当前有效且 key 以 prefix 开头的条目,按 key 字典序;题目没有披露 scan 是否按 prefix 或如何排序。
  • backup 产出不可变深拷贝,保留存活 value 与剩余 TTL;题目只写 backup,没有说恢复、快照编号或输出格式,restore 只作追问讨论。

解题路线

  1. 先向面试官核对签名、record/field 层级、返回值、同时间操作顺序与 TTL 边界;把每层可运行测试写在扩展前,避免依赖未公开假设。
  2. 基础层用 Map 存 value 与 expireAt;get 统一调用 alive(entry,now)。set 覆写时替换旧值和到期点,删除/不存在返回口径依接口定。
  3. scan 遍历条目并过滤 alive 与 prefix,最后按 key 排序;若条目数大且 scan 很频繁,再讨论有序树或 trie,维护 TTL 删除与排序一致性。
  4. TTL 层采用读取时惰性过滤,所有 get/scan/backup 必须共用同一可见性判断;需要省内存可补最小堆清理,但堆中旧到期事件必须带 generation,防止误删后来覆写的新值。
  5. backup(now) 只收集当时可见条目、复制 value、记录 remainingTTL=expireAt-now;备份必须与并发写入有一致的快照点。若面试官追问恢复,再确认恢复时间与 TTL 重启规则。

手动走一遍

训练例:set(a,7,t=10,ttl=5),t=14 get(a)=7 且 backup 记剩余 1;t=15 get(a)=null,scan('a',15) 与 backup(15) 均不含 a。若 t=14 重写 a=9 且无 TTL,旧 t=15 的到期事件不能删掉新值。此例是本文契约,不是题目样例。

规模与取舍

设 n 为库内条目,k 为 scan 命中数:Map 的 set/get 平均 O(1)、空间 O(n);朴素 scan O(n+k log k) 时间、O(k) 结果空间;完整 backup O(n) 时间与 O(存活数据量) 新空间。并发一致性和 value 拷贝成本取决于真实接口。

易错点与追问

容易失分的边界

  • 把这帖与 的时序 KV 历史查询/CAS 当作同一原题。
  • 在 get 过滤了过期项,却让 scan 或 backup 返回已过期值。
  • 把 value 的浅引用放进备份,后续写入改掉旧快照。
  • TTL 边界用 <= 与 < 混乱,恰在到期时行为不一致。
  • 未确认原题有 restore 就补出具体恢复返回值或排名规则。

继续深挖

  • 如果真实接口是 record-field,scan 如何排序并返回字段?
  • 允许历史时间查询时需要版本链还是全量快照?
  • backup 与并发 set 如何得到线性化快照?
  • 若支持 restore,剩余 TTL 从恢复时刻还是原绝对时间算?
✓已复制微信号!