Added
import-existing30-second heartbeat log line. The existingMatched N files so far...progress only ticked every 100 matches, so a long ExcludedAlbum or filtered run left INFO-level output silent for many minutes and users (#347) read silence as a hang. The heartbeat prints total scanned, matched, skipped-re-hash, filtered, unmatched, hash errors, and the last-seen asset id. (#348)
Changed
import-existingskips the SHA-256 re-read on files already adopted at the same path with unchanged size + mtime. Previously every restart paid the full hash cost on every already-adopted file (there's no resume checkpoint), which turned into hours per restart on HDD-backed photo trees. The check is mtime-keyed, so any size or mtime change still forces a real re-hash and silent content drift stays caught. (#348)- State DB schema migrates v10 -> v11 on first run. Adds nullable
imported_size INTEGERandimported_mtime INTEGERcolumns toassets. Pre-v11 rows survive with NULL values (the import path treats those as "no snapshot, re-hash" on the first post-upgrade pass), so the upgrade is one-way and idempotent on re-entry. (#348)
Fixed
- Tracing writer no longer back-pressures the runtime under heavy log volume. When the consumer of stderr (Docker stdout pipe, screen PTY, journald) drained slower than events were emitted, every
tracing::info!/tracing::debug!call parked on the writer mutex behind a synchronousStderr::write_all. Theimport-existingheartbeat task and the scan loop both wedged while spawn-blocking workers continued churning -- the failure signature reporters saw in #347 (heartbeats fired twice then stopped, but file-read counters kept growing). Wraps the writer withtracing_appender::non_blockingin lossy mode so events drop instead of stall under saturation. (#349) RedactingWriter::writeno longer allocates aStringper event when the password is unset or absent from the buffer. Under trace-level logging the previous implementation triggeredString::from_utf8_lossyon every event whose buffer was at least the password length, which compounded with the back-pressure above as the dominant heap churn forimport-existing. Adds a byte-level pre-scan that short-circuits when no match is possible. (#349)import-existingper-pageFetcher responselog line no longer pretty-prints the full CloudKit JSON at DEBUG. Tracing field expressions are evaluated eagerly, soserde_json::to_string_pretty(&response)allocated ~500 KB - 1 MB every page even when DEBUG was not actually being emitted. Now logs the metadata at DEBUG and gates the raw body behind TRACE. (#349)
Full changelog: CHANGELOG.md