Frontend SWE / SWE · Phone OOD / VO System Programming

Databricks 协作 Playlist:Add/Remove/Reorder 的数据模型与同步事件

用 playlist entry 标识重复歌曲,比较整表数组、位置键和双向链,设计原子重排与多人可见事件。

题目重点:用 playlist entry 标识重复歌曲,比较整表数组、位置键和双向链,设计原子重排与多人可见事件。

题意与假设

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

  • 一个 playlist 可包含同一 song 多次,因此操作定位 playlist_entry_id 而非 song_id;参与者权限、重复歌规则、排序并发冲突由本文训练契约定义,题目未明确。
  • 支持 add 到尾或指定相邻项、remove 一个 entry、reorder 一个 entry 到另一位置;列表查询必须输出确定的全序。

解题路线

  1. 基础 schema:playlist(id,owner,version),playlist_entry(id,playlist_id,song_id,prev_id,next_id,created_at,deleted_at)。用独立 entry ID 避免重复 song 无法区分;事务内维护 head/tail 或 sentinel 与相邻指针。
  2. 添加更新旧尾和新节点,删除同时接通前后邻居,移动先从原处摘除再插目标位置。每次事务用 playlist version 条件更新或行锁保护邻接关系,检查目标仍属于同列表,失败返回 409 让客户端拉取最新版本重试。
  3. 链式模型定位已知 entry 的局部写 O(1),但要顺序读完整列表 O(N) 且链断裂/循环需校验;数组 JSON 一次读方便但每次 move 可重写 O(N)。有序 position key 可让分页读高效,却有中间插入时 key 间隙耗尽与 rebalance 问题。选型由读写比、列表长度和事务能力决定。
  4. 提交事务时同时写 outbox event(playlist_id, version, op, entry_id, neighbors);事件在事务后发布,接收方按 version 顺序补拉缺口。浏览器实时协作通常用 WebSocket/SSE;webhook 适合通知其他服务,不能把 webhook 直接当浏览器长连接。
  5. 权限检查与版本检查应在同一操作边界;读缓存键带 version,变更后失效。客户端可乐观渲染,但收到服务端 409 或版本跳跃时按快照重建。

手动走一遍

列表 A→B→C,移动 B 到 C 后:先把 A.next 指向 C、C.prev 指向 A,再把 B 插入 C 后,得到 A→C→B。若另一用户同时删除 C,两事务不能各自按旧邻居提交;一方版本冲突后重取列表再决定目标位置。

规模与取舍

已知 entry ID 且索引可定位时,链表局部 add/remove/move O(1) 邻接更新,但数据库事务、锁与索引成本另计;全量 list O(N)。JSON 数组重排通常 O(N) 写;位置键读 O(log N+K) 分页、插入常见 O(log N) 但需偶尔 rebalance。事件日志空间随操作数增长并设保留/快照。

易错点与追问

容易失分的边界

  • 用 song_id 当条目 ID,重复歌无法正确移除。
  • 只改一个指针使链表断裂或成环。
  • 两个用户并发移动却没有版本/事务保护。
  • 把 webhook 当浏览器实时通道。
  • 只算 O(1) 写不讨论 O(N) 列表读与分页。

继续深挖

  • 同一首歌可以出现两次吗?
  • 多人同时移动同一条目如何定义胜者?
  • 长列表如何分页而不遍历全部节点?
  • 客户端断线后如何从版本号补事件?
  • 用户撤销一次重排如何设计?
✓已复制微信号!