pub(crate) fn update_object_meta(
store: &Store,
oref_str: &str,
meta_update: &HashMap<String, Value>,
) -> Result<(), String>Expand description
Update object meta by oref string. Merges meta into existing object.
The whole read-merge-write round trip runs inside ONE Store::with_tx
critical section (a single acquisition of the store’s connection Mutex,
wrapping a real SQLite transaction) instead of two separate
must_get/update calls. This closes a lost-update race: two
call sites can legitimately fire on the SAME block within milliseconds
of each other — e.g. persist_session_id (clearing a stale --resume
id) and clear_active_pid both run from independent async tasks on a
persistent controller’s process exit. Each used to read a pre-write
snapshot of the block’s entire meta map, merge in its own single key,
and write the entire merged map back — so whichever of the two won
the race to write LAST silently reverted the other’s change (every key
it didn’t itself touch reverts to whatever it read, which may already
be stale). with_tx holds the one connection lock across the full
read+merge+write, so no other Store::* call for ANY object can
interleave inside it — the two writers now strictly serialize instead
of racing, and each one’s merge is always built from the other’s
already-committed result. See
REPORT_LOGIN_PERSIST_FAILURE_AND_STUCK_WORKING_2026_07_27.md.