Performance
App state sync: move-not-clone through the blocking thread handoff (#818)process_patch_list offloads snapshot and patch processing to runtime::blocking, whose closure requires 'static. Previously, the only way to satisfy that bound was to deep-clone the data before moving it in:
| eliminated copy | shape | measured cost |
|---|---|---|
snapshot.clone() per bootstrap | ~20k records × 1 KB (~21 MB) | ~8.4 ms, ~60k allocs |
patch.clone() per resume patch | ~1k mutations × 2 KB (~2 MB) | ~305 µs, ~3k allocs |
keys_map.clone() per patch | key-cache HashMap | now an Arc refcount bump |
PatchList with Option::take, moved into the blocking closure, returned through the result tuple, and restored to pl.snapshot before the function returns. Patches are drained with mem::take, processed one by one the same way, and reassembled in order into pl.patches. The key cache is wrapped in Arc once so each per-patch closure handoff is a cheap refcount increment.
The staleness guard runs on a borrow before the take, so its behavior is unchanged. On any error path ? propagates before the caller can observe the intermediate empty fields.
The caller contract (get_missing_key_ids and has-more bookkeeping read pl.snapshot and pl.patches after the call) is protected by a regression test.
Breaking changes
None.process_patch_list keeps its existing signature and returns a PatchList carrying the same data as before.