pub async fn archive(
conn: &Connection,
cutoff: &str,
archived_at: &str,
archive_path: &Path,
) -> Result<ArchiveReport>Expand description
Move closed edge intervals and superseded log rows older than cutoff into
the cold database at archive_path (§5.7, D-012, D-022).
The whole session is one BEGIN IMMEDIATE … COMMIT transaction (D-012):
copy-then-delete must be atomic, or a crash between the phases duplicates or
loses rows. The archive-session marker that unlocks the delete guards
(D-008 revised) is created as the first statement of that transaction and
dropped as the last, so it never exists as committed state — commit drops
it, rollback discards it, and there is no crash path that leaves the guards
disarmed.
ATTACH is issued outside the transaction and DETACH is issued unconditionally
on the way out, including on error: ATTACH is not transactional and survives
ROLLBACK, so a leaked handle would make every later archive or cold-DB
reconstruct fail with “database cold is already in use”.
archived_at is when the session ran; cutoff is the boundary it used.
Both go into cold.archive_horizon, and until Wave 4.5 both columns were
written with the cutoff — so the table recorded that every archive had run at
the instant it was archiving up to, which is the one time it certainly did
not run. The two are different clocks (Doctrine II) and the row exists to
carry both: the cutoff says what was moved, archived_at says when the
decision was taken, and only the second can answer “how stale is this cold
file”. The column was there, correctly named, holding the wrong value.