Module: Mbeditor::CollaborationDocStore
- Defined in:
- app/services/mbeditor/collaboration_doc_store.rb
Overview
Thread-safe, in-memory cache of opaque Yjs bytes per active file. It never interprets the bytes (no Ruby CRDT): it only buffers the latest snapshot plus recent deltas so a late-joiner can sync instantly. Modeled on the existing TTL caches (GitInfoService, AvailabilityProbe): Mutex + monotonic clock.
Constant Summary collapse
- GRACE_TTL =
Grace window (seconds): a room with no activity for longer than this is evicted by sweep!. Because every op refreshes last_activity, a room that just went empty survives this long, so a quick reopen recovers its buffer.
300- ROOM_CAP =
Hard cap on cached rooms. Exceeding it evicts the least-recently-active room, so process memory stays bounded even if rooms are never swept.
200- SWEEP_INTERVAL =
Idle GC rides on traffic: every write/read attempts a sweep, but the scan runs at most once per this interval so a busy room doesn't pay for it on every op. With no explicit scheduler, memory stays bounded over a long session as long as some activity continues. Kept well under GRACE_TTL so an idle room is reclaimed soon after its grace window elapses.
60
Class Method Summary collapse
- .record_update(path, bytes, now: monotonic) ⇒ Object
- .replace_snapshot(path, bytes, now: monotonic) ⇒ Object
- .reset! ⇒ Object
- .state_for(path, now: monotonic) ⇒ Object
- .sweep!(now: monotonic, grace: GRACE_TTL) ⇒ Object
Class Method Details
.record_update(path, bytes, now: monotonic) ⇒ Object
30 31 32 33 34 35 36 |
# File 'app/services/mbeditor/collaboration_doc_store.rb', line 30 def record_update(path, bytes, now: monotonic) MUTEX.synchronize do room = touch(path, now) room[:deltas] << bytes end nil end |
.replace_snapshot(path, bytes, now: monotonic) ⇒ Object
38 39 40 41 42 43 44 45 |
# File 'app/services/mbeditor/collaboration_doc_store.rb', line 38 def replace_snapshot(path, bytes, now: monotonic) MUTEX.synchronize do room = touch(path, now) room[:snapshot] = bytes room[:deltas] = [] end nil end |
.reset! ⇒ Object
66 67 68 69 70 71 72 |
# File 'app/services/mbeditor/collaboration_doc_store.rb', line 66 def reset! MUTEX.synchronize do @rooms = {} @last_sweep = nil end nil end |
.state_for(path, now: monotonic) ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'app/services/mbeditor/collaboration_doc_store.rb', line 47 def state_for(path, now: monotonic) MUTEX.synchronize do room = rooms[path] if room room[:last_activity] = now result = { snapshot: room[:snapshot], deltas: room[:deltas].dup } else result = { snapshot: nil, deltas: [] } end maybe_sweep(now) result end end |
.sweep!(now: monotonic, grace: GRACE_TTL) ⇒ Object
61 62 63 64 |
# File 'app/services/mbeditor/collaboration_doc_store.rb', line 61 def sweep!(now: monotonic, grace: GRACE_TTL) MUTEX.synchronize { evict_idle(now, grace) } nil end |