Tracing: DAO layer + handler spans on tracing, drop all Context params (#141)
trace_db_call no longer takes an OpenTelemetry Context: it opens a db.<query_type>.<operation> span (same name via otel.name, same db.query_type / db.operation attrs) on the caller's ambient tracing span and runs the DAO body inside it. The cx / ctx / context parameter is gone from every DAO trait method, impl and call site, and from the helpers and background drains that only threaded it. The remaining request-handler spans (files, tags, faces, image, video, favorites, duplicates, memories) move to #[instrument]; the Context::current_with_span / with_remote_span_context plumbing is gone, as is extract_context_from_request (the tracing-actix-web root span covers it). otel::set_span_attributes replaces BoxedSpan::set_attributes. Background-job raw spans (thumbnails, video actors) are left for #142. tests/otel_db_spans.rs pins name, attributes, status and nesting (across an instrumented spawn); otel_traceparent now uses an #[instrument] handler. CLAUDE.md documents the tracing conventions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1c508cdabd
commit
b6deca2a52
55 files changed
+1942
-3852
No files matched your search
+108
-169
@@ -43,7 +43,6 @@ use crate::tags;
|
||||
///
|
||||
/// Returns the number of rows successfully backfilled this pass.
|
||||
pub fn backfill_unhashed_backlog(
|
||||
context: &opentelemetry::Context,
|
||||
library: &libraries::Library,
|
||||
exif_dao: &Arc<Mutex<Box<dyn ExifDao>>>,
|
||||
) -> usize {
|
||||
@@ -61,8 +60,7 @@ pub fn backfill_unhashed_backlog(
|
||||
// library's tick. Negligible cost given the cap.
|
||||
let rows: Vec<(i32, String)> = {
|
||||
let mut dao = exif_dao.lock().expect("Unable to lock ExifDao");
|
||||
dao.get_rows_missing_hash(context, cap + 1)
|
||||
.unwrap_or_default()
|
||||
dao.get_rows_missing_hash(cap + 1).unwrap_or_default()
|
||||
};
|
||||
if rows.is_empty() {
|
||||
return 0;
|
||||
@@ -88,13 +86,9 @@ pub fn backfill_unhashed_backlog(
|
||||
match content_hash::compute(&abs) {
|
||||
Ok(id) => {
|
||||
let mut dao = exif_dao.lock().expect("Unable to lock ExifDao");
|
||||
if let Err(e) = dao.backfill_content_hash(
|
||||
context,
|
||||
library.id,
|
||||
rel_path,
|
||||
&id.content_hash,
|
||||
id.size_bytes,
|
||||
) {
|
||||
if let Err(e) =
|
||||
dao.backfill_content_hash(library.id, rel_path, &id.content_hash, id.size_bytes)
|
||||
{
|
||||
warn!(
|
||||
"face_watch: backfill_content_hash failed for {}: {:?}",
|
||||
rel_path, e
|
||||
@@ -148,7 +142,6 @@ fn date_backfill_cap() -> i64 {
|
||||
/// exiftool is the meaningful new attempt — it handles videos and
|
||||
/// MakerNote-hosted dates kamadak can't reach.
|
||||
pub fn backfill_missing_date_taken(
|
||||
context: &opentelemetry::Context,
|
||||
library: &libraries::Library,
|
||||
exif_dao: &Arc<Mutex<Box<dyn ExifDao>>>,
|
||||
) -> usize {
|
||||
@@ -156,7 +149,7 @@ pub fn backfill_missing_date_taken(
|
||||
|
||||
let rows: Vec<(i32, String)> = {
|
||||
let mut dao = exif_dao.lock().expect("Unable to lock ExifDao");
|
||||
dao.get_rows_needing_date_backfill(context, library.id, cap + 1)
|
||||
dao.get_rows_needing_date_backfill(library.id, cap + 1)
|
||||
.unwrap_or_default()
|
||||
};
|
||||
if rows.is_empty() {
|
||||
@@ -198,7 +191,6 @@ pub fn backfill_missing_date_taken(
|
||||
continue;
|
||||
};
|
||||
match dao.backfill_date_taken(
|
||||
context,
|
||||
library.id,
|
||||
rel_path,
|
||||
rd.timestamp,
|
||||
@@ -300,7 +292,6 @@ pub struct UtcBackfillOutcome {
|
||||
/// regenerates them. Daily conversation summaries are SMS-derived and
|
||||
/// don't depend on photo dates, so they're not touched.
|
||||
pub fn backfill_utc_dates(
|
||||
context: &opentelemetry::Context,
|
||||
library: &libraries::Library,
|
||||
exif_dao: &Arc<Mutex<Box<dyn ExifDao>>>,
|
||||
reel_dao: &Arc<Mutex<Box<dyn PrecomputedReelDao>>>,
|
||||
@@ -308,13 +299,10 @@ pub fn backfill_utc_dates(
|
||||
cursor: &mut i32,
|
||||
) -> UtcBackfillOutcome {
|
||||
let cap = date_backfill_cap();
|
||||
backfill_utc_dates_capped(
|
||||
context, library, exif_dao, reel_dao, display_tz, cursor, cap,
|
||||
)
|
||||
backfill_utc_dates_capped(library, exif_dao, reel_dao, display_tz, cursor, cap)
|
||||
}
|
||||
|
||||
fn backfill_utc_dates_capped(
|
||||
context: &opentelemetry::Context,
|
||||
library: &libraries::Library,
|
||||
exif_dao: &Arc<Mutex<Box<dyn ExifDao>>>,
|
||||
reel_dao: &Arc<Mutex<Box<dyn PrecomputedReelDao>>>,
|
||||
@@ -350,7 +338,7 @@ fn backfill_utc_dates_capped(
|
||||
'paging: loop {
|
||||
let page = {
|
||||
let mut dao = exif_dao.lock().expect("Unable to lock ExifDao");
|
||||
dao.get_rows_needing_utc_backfill(context, library.id, *cursor, cap)
|
||||
dao.get_rows_needing_utc_backfill(library.id, *cursor, cap)
|
||||
.unwrap_or_default()
|
||||
};
|
||||
let page_len = page.len() as i64;
|
||||
@@ -444,7 +432,7 @@ fn backfill_utc_dates_capped(
|
||||
tz_source,
|
||||
} in &conversions
|
||||
{
|
||||
match dao.backfill_date_utc(context, row.id, *utc, *offset, tz_source.as_str()) {
|
||||
match dao.backfill_date_utc(row.id, *utc, *offset, tz_source.as_str()) {
|
||||
Ok(true) => {
|
||||
outcome.converted += 1;
|
||||
let before = display_day(zone, row.date_taken);
|
||||
@@ -468,8 +456,7 @@ fn backfill_utc_dates_capped(
|
||||
}
|
||||
|
||||
if !affected_days.is_empty() {
|
||||
outcome.reels_invalidated =
|
||||
invalidate_day_reels(context, library, reel_dao, zone, &affected_days);
|
||||
outcome.reels_invalidated = invalidate_day_reels(library, reel_dao, zone, &affected_days);
|
||||
}
|
||||
|
||||
if outcome.converted > 0 || outcome.unresolved > 0 || more_remain {
|
||||
@@ -510,7 +497,6 @@ fn reel_covered_day(reel: &PrecomputedReel, zone: chrono_tz::Tz) -> Option<Naive
|
||||
/// With the ledger row gone the nightly pre-gen's freshness gate fails
|
||||
/// and it renders a new one on its normal schedule. Returns rows deleted.
|
||||
fn invalidate_day_reels(
|
||||
context: &opentelemetry::Context,
|
||||
library: &libraries::Library,
|
||||
reel_dao: &Arc<Mutex<Box<dyn PrecomputedReelDao>>>,
|
||||
zone: chrono_tz::Tz,
|
||||
@@ -518,7 +504,7 @@ fn invalidate_day_reels(
|
||||
) -> usize {
|
||||
let keys = vec!["all".to_string(), library.id.to_string()];
|
||||
let mut dao = reel_dao.lock().expect("Unable to lock PrecomputedReelDao");
|
||||
let reels = match dao.list_for_span(context, "day", &keys) {
|
||||
let reels = match dao.list_for_span("day", &keys) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
warn!("utc_backfill: listing day reels failed: {:?}", e);
|
||||
@@ -535,7 +521,7 @@ fn invalidate_day_reels(
|
||||
return 0;
|
||||
}
|
||||
let ids: Vec<i32> = stale.iter().map(|r| r.id).collect();
|
||||
match dao.delete_ids(context, &ids) {
|
||||
match dao.delete_ids(&ids) {
|
||||
Ok(n) => {
|
||||
// Unlink too, so the on-demand cache can't serve the stale
|
||||
// render under the same key.
|
||||
@@ -563,14 +549,13 @@ fn invalidate_day_reels(
|
||||
/// doesn't call this for them), so a flapping share doesn't make the
|
||||
/// gauge dip.
|
||||
pub fn refresh_utc_backfill_progress(
|
||||
context: &opentelemetry::Context,
|
||||
library: &libraries::Library,
|
||||
exif_dao: &Arc<Mutex<Box<dyn ExifDao>>>,
|
||||
remaining: &mut HashMap<i32, i64>,
|
||||
) {
|
||||
let count = {
|
||||
let mut dao = exif_dao.lock().expect("Unable to lock ExifDao");
|
||||
dao.count_rows_needing_utc_backfill(context, library.id)
|
||||
dao.count_rows_needing_utc_backfill(library.id)
|
||||
};
|
||||
if let Ok(n) = count {
|
||||
remaining.insert(library.id, n);
|
||||
@@ -594,7 +579,6 @@ pub fn refresh_utc_backfill_progress(
|
||||
/// retry every tick at this point; future Branch may add a status
|
||||
/// column like face_detections has.
|
||||
pub fn process_clip_backlog(
|
||||
context: &opentelemetry::Context,
|
||||
library: &libraries::Library,
|
||||
clip_client: &crate::ai::clip_client::ClipClient,
|
||||
exif_dao: &Arc<Mutex<Box<dyn ExifDao>>>,
|
||||
@@ -611,7 +595,7 @@ pub fn process_clip_backlog(
|
||||
|
||||
let rows: Vec<(String, String)> = {
|
||||
let mut dao = exif_dao.lock().expect("exif dao");
|
||||
match dao.list_clip_unencoded_candidates(context, library.id, cap) {
|
||||
match dao.list_clip_unencoded_candidates(library.id, cap) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
warn!(
|
||||
@@ -653,7 +637,6 @@ pub fn process_clip_backlog(
|
||||
}
|
||||
|
||||
pub fn process_face_backlog(
|
||||
context: &opentelemetry::Context,
|
||||
library: &libraries::Library,
|
||||
face_client: &crate::ai::face_client::FaceClient,
|
||||
face_dao: &Arc<Mutex<Box<dyn faces::FaceDao>>>,
|
||||
@@ -668,7 +651,7 @@ pub fn process_face_backlog(
|
||||
|
||||
let rows: Vec<(String, String)> = {
|
||||
let mut dao = face_dao.lock().expect("face dao");
|
||||
match dao.list_unscanned_candidates(context, library.id, cap) {
|
||||
match dao.list_unscanned_candidates(library.id, cap) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
warn!(
|
||||
@@ -719,7 +702,6 @@ pub fn process_face_backlog(
|
||||
/// table (vanished mid-scan, permission denied, etc.) burned the budget
|
||||
/// every tick and the rest of the backlog never advanced.
|
||||
pub fn backfill_missing_content_hashes(
|
||||
context: &opentelemetry::Context,
|
||||
files: &[(PathBuf, String)],
|
||||
library: &libraries::Library,
|
||||
exif_dao: &Arc<Mutex<Box<dyn ExifDao>>>,
|
||||
@@ -735,7 +717,7 @@ pub fn backfill_missing_content_hashes(
|
||||
|
||||
let exif_records = {
|
||||
let mut dao = exif_dao.lock().expect("Unable to lock ExifDao");
|
||||
dao.get_exif_batch(context, Some(library.id), &image_paths)
|
||||
dao.get_exif_batch(Some(library.id), &image_paths)
|
||||
.unwrap_or_default()
|
||||
};
|
||||
// Cheap lookup back from rel_path → absolute file_path so
|
||||
@@ -775,7 +757,6 @@ pub fn backfill_missing_content_hashes(
|
||||
Ok(id) => {
|
||||
let mut dao = exif_dao.lock().expect("Unable to lock ExifDao");
|
||||
if let Err(e) = dao.backfill_content_hash(
|
||||
context,
|
||||
library.id,
|
||||
&record.file_path,
|
||||
&id.content_hash,
|
||||
@@ -820,7 +801,6 @@ pub fn backfill_missing_content_hashes(
|
||||
/// just inserted alongside any pre-existing rows the watcher walked
|
||||
/// over — covers both new uploads and the initial backlog scan.
|
||||
pub fn build_face_candidates(
|
||||
context: &opentelemetry::Context,
|
||||
library: &libraries::Library,
|
||||
files: &[(PathBuf, String)],
|
||||
exif_dao: &Arc<Mutex<Box<dyn ExifDao>>>,
|
||||
@@ -839,7 +819,7 @@ pub fn build_face_candidates(
|
||||
|
||||
let exif_records = {
|
||||
let mut dao = exif_dao.lock().expect("Unable to lock ExifDao");
|
||||
dao.get_exif_batch(context, Some(library.id), &image_paths)
|
||||
dao.get_exif_batch(Some(library.id), &image_paths)
|
||||
.unwrap_or_default()
|
||||
};
|
||||
// rel_path → content_hash (only rows with a hash; without one we have
|
||||
@@ -857,7 +837,7 @@ pub fn build_face_candidates(
|
||||
let Some(hash) = hash_by_path.get(&rel_path) else {
|
||||
continue;
|
||||
};
|
||||
match dao.already_scanned(context, hash) {
|
||||
match dao.already_scanned(hash) {
|
||||
Ok(true) => continue,
|
||||
Ok(false) => candidates.push(face_watch::FaceCandidate {
|
||||
rel_path,
|
||||
@@ -887,10 +867,6 @@ mod tests {
|
||||
use crate::faces::{FaceDao, SqliteFaceDao};
|
||||
use crate::libraries::Library;
|
||||
|
||||
fn ctx() -> opentelemetry::Context {
|
||||
opentelemetry::Context::new()
|
||||
}
|
||||
|
||||
/// Everything `setup` hands back to a test: tempdir, library, shared
|
||||
/// connection, and the two DAOs. Aliased to keep clippy's
|
||||
/// type-complexity lint satisfied.
|
||||
@@ -952,37 +928,34 @@ mod tests {
|
||||
content_hash: Option<&str>,
|
||||
) {
|
||||
let mut dao = exif_dao.lock().unwrap();
|
||||
dao.store_exif(
|
||||
&ctx(),
|
||||
InsertImageExif {
|
||||
library_id: lib_id,
|
||||
file_path: rel.to_string(),
|
||||
camera_make: None,
|
||||
camera_model: None,
|
||||
lens_model: None,
|
||||
width: None,
|
||||
height: None,
|
||||
orientation: None,
|
||||
gps_latitude: None,
|
||||
gps_longitude: None,
|
||||
gps_altitude: None,
|
||||
focal_length: None,
|
||||
aperture: None,
|
||||
shutter_speed: None,
|
||||
iso: None,
|
||||
date_taken: None,
|
||||
created_time: 0,
|
||||
last_modified: 0,
|
||||
content_hash: content_hash.map(|s| s.to_string()),
|
||||
size_bytes: None,
|
||||
phash_64: None,
|
||||
dhash_64: None,
|
||||
date_taken_source: None,
|
||||
date_utc: None,
|
||||
camera_offset_minutes: None,
|
||||
date_taken_tz_source: None,
|
||||
},
|
||||
)
|
||||
dao.store_exif(InsertImageExif {
|
||||
library_id: lib_id,
|
||||
file_path: rel.to_string(),
|
||||
camera_make: None,
|
||||
camera_model: None,
|
||||
lens_model: None,
|
||||
width: None,
|
||||
height: None,
|
||||
orientation: None,
|
||||
gps_latitude: None,
|
||||
gps_longitude: None,
|
||||
gps_altitude: None,
|
||||
focal_length: None,
|
||||
aperture: None,
|
||||
shutter_speed: None,
|
||||
iso: None,
|
||||
date_taken: None,
|
||||
created_time: 0,
|
||||
last_modified: 0,
|
||||
content_hash: content_hash.map(|s| s.to_string()),
|
||||
size_bytes: None,
|
||||
phash_64: None,
|
||||
dhash_64: None,
|
||||
date_taken_source: None,
|
||||
date_utc: None,
|
||||
camera_offset_minutes: None,
|
||||
date_taken_tz_source: None,
|
||||
})
|
||||
.expect("insert");
|
||||
}
|
||||
|
||||
@@ -1002,12 +975,12 @@ mod tests {
|
||||
insert_exif(&exif_dao, 1, "a.jpg", None);
|
||||
insert_exif(&exif_dao, 1, "b.jpg", None);
|
||||
|
||||
let backfilled = backfill_unhashed_backlog(&ctx(), &library, &exif_dao);
|
||||
let backfilled = backfill_unhashed_backlog(&library, &exif_dao);
|
||||
assert_eq!(backfilled, 2);
|
||||
|
||||
let mut dao = exif_dao.lock().unwrap();
|
||||
let rows = dao
|
||||
.get_exif_batch(&ctx(), Some(1), &["a.jpg".to_string(), "b.jpg".to_string()])
|
||||
.get_exif_batch(Some(1), &["a.jpg".to_string(), "b.jpg".to_string()])
|
||||
.unwrap();
|
||||
assert_eq!(rows.len(), 2);
|
||||
for r in rows {
|
||||
@@ -1029,12 +1002,12 @@ mod tests {
|
||||
// Row in the other library — must be skipped (different lib_id).
|
||||
insert_exif(&exif_dao, 2, "other.jpg", None);
|
||||
|
||||
let backfilled = backfill_unhashed_backlog(&ctx(), &library, &exif_dao);
|
||||
let backfilled = backfill_unhashed_backlog(&library, &exif_dao);
|
||||
assert_eq!(backfilled, 1, "only the existing in-library file hashes");
|
||||
|
||||
let mut dao = exif_dao.lock().unwrap();
|
||||
let other = dao
|
||||
.get_exif_batch(&ctx(), Some(2), &["other.jpg".to_string()])
|
||||
.get_exif_batch(Some(2), &["other.jpg".to_string()])
|
||||
.unwrap();
|
||||
assert_eq!(other.len(), 1);
|
||||
assert!(
|
||||
@@ -1042,7 +1015,7 @@ mod tests {
|
||||
"other-library row must remain unhashed"
|
||||
);
|
||||
let ghost = dao
|
||||
.get_exif_batch(&ctx(), Some(1), &["ghost.jpg".to_string()])
|
||||
.get_exif_batch(Some(1), &["ghost.jpg".to_string()])
|
||||
.unwrap();
|
||||
assert_eq!(ghost.len(), 1);
|
||||
assert!(
|
||||
@@ -1068,7 +1041,7 @@ mod tests {
|
||||
insert_exif(&exif_dao, 1, &rel, None);
|
||||
}
|
||||
|
||||
let backfilled = backfill_unhashed_backlog(&ctx(), &library, &exif_dao);
|
||||
let backfilled = backfill_unhashed_backlog(&library, &exif_dao);
|
||||
assert_eq!(backfilled, 2, "cap=2 must bound the per-tick successes");
|
||||
unsafe {
|
||||
std::env::remove_var("FACE_HASH_BACKFILL_MAX_PER_TICK");
|
||||
@@ -1091,12 +1064,11 @@ mod tests {
|
||||
(tmp.path().join("already.jpg"), "already.jpg".to_string()),
|
||||
(tmp.path().join("clip.mp4"), "clip.mp4".to_string()),
|
||||
];
|
||||
backfill_missing_content_hashes(&ctx(), &files, &library, &exif_dao);
|
||||
backfill_missing_content_hashes(&files, &library, &exif_dao);
|
||||
|
||||
let mut dao = exif_dao.lock().unwrap();
|
||||
let rows = dao
|
||||
.get_exif_batch(
|
||||
&ctx(),
|
||||
Some(1),
|
||||
&[
|
||||
"fresh.jpg".to_string(),
|
||||
@@ -1138,7 +1110,7 @@ mod tests {
|
||||
// Mark `scanned.jpg`'s hash as already detected.
|
||||
{
|
||||
let mut dao = face_dao.lock().unwrap();
|
||||
dao.mark_status(&ctx(), 1, "hash-scanned", "scanned.jpg", "no_faces", "test")
|
||||
dao.mark_status(1, "hash-scanned", "scanned.jpg", "no_faces", "test")
|
||||
.expect("mark scanned");
|
||||
}
|
||||
|
||||
@@ -1148,7 +1120,7 @@ mod tests {
|
||||
(tmp.path().join("unhashed.jpg"), "unhashed.jpg".to_string()),
|
||||
(tmp.path().join("clip.mp4"), "clip.mp4".to_string()),
|
||||
];
|
||||
let candidates = build_face_candidates(&ctx(), &library, &files, &exif_dao, &face_dao);
|
||||
let candidates = build_face_candidates(&library, &files, &exif_dao, &face_dao);
|
||||
|
||||
assert_eq!(
|
||||
candidates.len(),
|
||||
@@ -1194,37 +1166,34 @@ mod tests {
|
||||
source: Option<&str>,
|
||||
) -> i32 {
|
||||
let mut dao = exif_dao.lock().unwrap();
|
||||
dao.store_exif(
|
||||
&ctx(),
|
||||
InsertImageExif {
|
||||
library_id: lib_id,
|
||||
file_path: rel.to_string(),
|
||||
camera_make: None,
|
||||
camera_model: None,
|
||||
lens_model: None,
|
||||
width: None,
|
||||
height: None,
|
||||
orientation: None,
|
||||
gps_latitude: None,
|
||||
gps_longitude: None,
|
||||
gps_altitude: None,
|
||||
focal_length: None,
|
||||
aperture: None,
|
||||
shutter_speed: None,
|
||||
iso: None,
|
||||
date_taken,
|
||||
created_time: 0,
|
||||
last_modified: 0,
|
||||
content_hash: None,
|
||||
size_bytes: None,
|
||||
phash_64: None,
|
||||
dhash_64: None,
|
||||
date_taken_source: source.map(str::to_string),
|
||||
date_utc: None,
|
||||
camera_offset_minutes: None,
|
||||
date_taken_tz_source: None,
|
||||
},
|
||||
)
|
||||
dao.store_exif(InsertImageExif {
|
||||
library_id: lib_id,
|
||||
file_path: rel.to_string(),
|
||||
camera_make: None,
|
||||
camera_model: None,
|
||||
lens_model: None,
|
||||
width: None,
|
||||
height: None,
|
||||
orientation: None,
|
||||
gps_latitude: None,
|
||||
gps_longitude: None,
|
||||
gps_altitude: None,
|
||||
focal_length: None,
|
||||
aperture: None,
|
||||
shutter_speed: None,
|
||||
iso: None,
|
||||
date_taken,
|
||||
created_time: 0,
|
||||
last_modified: 0,
|
||||
content_hash: None,
|
||||
size_bytes: None,
|
||||
phash_64: None,
|
||||
dhash_64: None,
|
||||
date_taken_source: source.map(str::to_string),
|
||||
date_utc: None,
|
||||
camera_offset_minutes: None,
|
||||
date_taken_tz_source: None,
|
||||
})
|
||||
.expect("insert")
|
||||
.id
|
||||
}
|
||||
@@ -1241,7 +1210,7 @@ mod tests {
|
||||
exif_dao
|
||||
.lock()
|
||||
.unwrap()
|
||||
.count_rows_needing_utc_backfill(&ctx(), lib_id)
|
||||
.count_rows_needing_utc_backfill(lib_id)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
@@ -1385,8 +1354,7 @@ mod tests {
|
||||
);
|
||||
|
||||
assert_eq!(remaining(&exif_dao, 1), 5);
|
||||
let out =
|
||||
backfill_utc_dates_capped(&ctx(), &library, &exif_dao, &reel_dao, NY, &mut 0, 500);
|
||||
let out = backfill_utc_dates_capped(&library, &exif_dao, &reel_dao, NY, &mut 0, 500);
|
||||
assert_eq!(out.converted, 5, "{out:?}");
|
||||
assert_eq!(out.unresolved, 0, "{out:?}");
|
||||
|
||||
@@ -1446,12 +1414,11 @@ mod tests {
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
let before = snapshot(&conn);
|
||||
let again =
|
||||
backfill_utc_dates_capped(&ctx(), &library, &exif_dao, &reel_dao, NY, &mut 0, 500);
|
||||
let again = backfill_utc_dates_capped(&library, &exif_dao, &reel_dao, NY, &mut 0, 500);
|
||||
assert_eq!(again, UtcBackfillOutcome::default());
|
||||
assert_eq!(snapshot(&conn), before);
|
||||
let mut progress = HashMap::new();
|
||||
refresh_utc_backfill_progress(&ctx(), &library, &exif_dao, &mut progress);
|
||||
refresh_utc_backfill_progress(&library, &exif_dao, &mut progress);
|
||||
assert_eq!(progress.get(&1), Some(&0));
|
||||
}
|
||||
|
||||
@@ -1467,8 +1434,7 @@ mod tests {
|
||||
let undated = insert_legacy(&exif_dao, 1, "undated.jpg", None, None);
|
||||
let other = insert_legacy(&exif_dao, 2, "1500000000.jpg", Some(ts), Some("filename"));
|
||||
|
||||
let out =
|
||||
backfill_utc_dates_capped(&ctx(), &library, &exif_dao, &reel_dao, NY, &mut 0, 500);
|
||||
let out = backfill_utc_dates_capped(&library, &exif_dao, &reel_dao, NY, &mut 0, 500);
|
||||
assert_eq!(out.converted, 1);
|
||||
assert_eq!(row(&conn, converted).date_utc, Some(ts));
|
||||
assert_eq!(row(&conn, undated).date_utc, None);
|
||||
@@ -1508,16 +1474,8 @@ mod tests {
|
||||
// Cursor carried across ticks, as the watcher does.
|
||||
let mut cursor = 0;
|
||||
for _ in 0..4 {
|
||||
let out = backfill_utc_dates_capped(
|
||||
&ctx(),
|
||||
&library,
|
||||
&exif_dao,
|
||||
&reel_dao,
|
||||
NY,
|
||||
&mut cursor,
|
||||
2,
|
||||
);
|
||||
refresh_utc_backfill_progress(&ctx(), &library, &exif_dao, &mut progress);
|
||||
let out = backfill_utc_dates_capped(&library, &exif_dao, &reel_dao, NY, &mut cursor, 2);
|
||||
refresh_utc_backfill_progress(&library, &exif_dao, &mut progress);
|
||||
seen.push((out.converted, progress[&1]));
|
||||
}
|
||||
// Cap holds (2 per tick) and the 3 missing rows never spend it.
|
||||
@@ -1532,7 +1490,7 @@ mod tests {
|
||||
.execute(&mut *c)
|
||||
.unwrap();
|
||||
}
|
||||
refresh_utc_backfill_progress(&ctx(), &library, &exif_dao, &mut progress);
|
||||
refresh_utc_backfill_progress(&library, &exif_dao, &mut progress);
|
||||
assert_eq!(progress[&1], 0);
|
||||
}
|
||||
|
||||
@@ -1566,15 +1524,7 @@ mod tests {
|
||||
let mut cursor = 0;
|
||||
let mut converted = 0;
|
||||
for _ in 0..4 {
|
||||
let out = backfill_utc_dates_capped(
|
||||
&ctx(),
|
||||
&library,
|
||||
&exif_dao,
|
||||
&reel_dao,
|
||||
NY,
|
||||
&mut cursor,
|
||||
2,
|
||||
);
|
||||
let out = backfill_utc_dates_capped(&library, &exif_dao, &reel_dao, NY, &mut cursor, 2);
|
||||
converted += out.converted;
|
||||
}
|
||||
assert_eq!(converted, 2, "the rows behind the stuck ones still drain");
|
||||
@@ -1614,16 +1564,14 @@ mod tests {
|
||||
let health_map = libraries::new_health_map(std::slice::from_ref(&unmounted));
|
||||
assert!(!libraries::refresh_health(&health_map, &unmounted, true).is_online());
|
||||
// …and the drain itself converts nothing even if called.
|
||||
let out =
|
||||
backfill_utc_dates_capped(&ctx(), &unmounted, &exif_dao, &reel_dao, NY, &mut 0, 500);
|
||||
let out = backfill_utc_dates_capped(&unmounted, &exif_dao, &reel_dao, NY, &mut 0, 500);
|
||||
assert_eq!(out, UtcBackfillOutcome::default());
|
||||
assert_eq!(row(&conn, filed).date_utc, None);
|
||||
assert_eq!(row(&conn, manual).date_utc, None);
|
||||
|
||||
// Share returns → picked up next tick.
|
||||
assert!(libraries::refresh_health(&health_map, &library, true).is_online());
|
||||
let out =
|
||||
backfill_utc_dates_capped(&ctx(), &library, &exif_dao, &reel_dao, NY, &mut 0, 500);
|
||||
let out = backfill_utc_dates_capped(&library, &exif_dao, &reel_dao, NY, &mut 0, 500);
|
||||
assert_eq!(out.converted, 2);
|
||||
assert_eq!(remaining(&exif_dao, 1), 0);
|
||||
}
|
||||
@@ -1643,21 +1591,18 @@ mod tests {
|
||||
let id = reel_dao
|
||||
.lock()
|
||||
.unwrap()
|
||||
.record_reel(
|
||||
&ctx(),
|
||||
&InsertablePrecomputedReel {
|
||||
span: span.to_string(),
|
||||
library_key: library_key.to_string(),
|
||||
cache_key: format!("{span}-{library_key}-{month}-{day}"),
|
||||
output_path: mp4.to_string_lossy().to_string(),
|
||||
title: "t".to_string(),
|
||||
media_count: 1,
|
||||
render_version: 1,
|
||||
tz_offset_minutes: -240,
|
||||
voice: None,
|
||||
generated_at: utc(2025, month, day, 7, 0, 0),
|
||||
},
|
||||
)
|
||||
.record_reel(&InsertablePrecomputedReel {
|
||||
span: span.to_string(),
|
||||
library_key: library_key.to_string(),
|
||||
cache_key: format!("{span}-{library_key}-{month}-{day}"),
|
||||
output_path: mp4.to_string_lossy().to_string(),
|
||||
title: "t".to_string(),
|
||||
media_count: 1,
|
||||
render_version: 1,
|
||||
tz_offset_minutes: -240,
|
||||
voice: None,
|
||||
generated_at: utc(2025, month, day, 7, 0, 0),
|
||||
})
|
||||
.unwrap();
|
||||
(id, mp4)
|
||||
}
|
||||
@@ -1704,8 +1649,7 @@ mod tests {
|
||||
let (other_day, mp4_0301) = seed_reel(&reel_dao, reels_dir.path(), "day", "1", 3, 1);
|
||||
let (week, _) = seed_reel(&reel_dao, reels_dir.path(), "week", "1", 6, 12);
|
||||
|
||||
let out =
|
||||
backfill_utc_dates_capped(&ctx(), &library, &exif_dao, &reel_dao, NY, &mut 0, 500);
|
||||
let out = backfill_utc_dates_capped(&library, &exif_dao, &reel_dao, NY, &mut 0, 500);
|
||||
assert_eq!(out.converted, 2);
|
||||
assert_eq!(out.day_changed, 1, "{out:?}");
|
||||
assert_eq!(out.reels_invalidated, 2, "{out:?}");
|
||||
@@ -1722,11 +1666,7 @@ mod tests {
|
||||
// With the ledger row gone the nightly pre-gen's freshness gate
|
||||
// (`latest_for` must match the new cache key) can't skip → it
|
||||
// regenerates on its normal schedule; no new scheduler involved.
|
||||
let latest = reel_dao
|
||||
.lock()
|
||||
.unwrap()
|
||||
.latest_for(&ctx(), "day", "all")
|
||||
.unwrap();
|
||||
let latest = reel_dao.lock().unwrap().latest_for("day", "all").unwrap();
|
||||
assert!(latest.is_none());
|
||||
}
|
||||
|
||||
@@ -1749,8 +1689,7 @@ mod tests {
|
||||
seed_reel(&reel_dao, reels_dir.path(), "day", "1", 6, 11);
|
||||
seed_reel(&reel_dao, reels_dir.path(), "day", "all", 6, 12);
|
||||
|
||||
let out =
|
||||
backfill_utc_dates_capped(&ctx(), &library, &exif_dao, &reel_dao, NY, &mut 0, 500);
|
||||
let out = backfill_utc_dates_capped(&library, &exif_dao, &reel_dao, NY, &mut 0, 500);
|
||||
assert_eq!(out.converted, 1);
|
||||
assert_eq!(out.day_changed, 0);
|
||||
assert_eq!(out.reels_invalidated, 0);
|
||||
|
||||
Reference in new issue
Block a user