persistBatch refreshed each pre-existing backfilled header with a per-row
updateHeaderContent in its own implicit transaction — the same N-commits-per-page
anti-pattern #310 fixed in MailSyncer. Route the whole pre-existing subset through
the batched MessageDao.updateHeaderContents(List) @Transaction so a page costs one
commit instead of one fsync per message (amplified on the encrypted cache).
Semantics are unchanged: updateHeaderContents applies updateHeaderContent to each
row in list order, so the same rows get the same values (and the same casefold
columns); the isNotEmpty guard still skips an empty refresh batch; brand-new rows
stay insert-only. No schema change.
Adds a PII-free, counts-only AppLog breadcrumb at the persist point.
Tests:
- MailBackfillerTest: the refresh routes through the batched update and never the
per-row one; a partial page refreshes only its pre-existing subset in one batched
call; an all-new page skips the batch entirely (empty boundary); breadcrumb counts.
- MessageDaoTest (real Room): the batch writes byte-for-byte the same row as the
per-row path; an empty batch is a no-op.
Closes#322