Stop the local walk queueing work nothing claims
walk::scan_root enqueued an ExtractMetadata and a Thumbnail job for every image it inserted or found changed. No handler claims either kind. The walk is only reachable from the scan_local example today, so no real catalog holds these rows, but it is the same leftover the remote scan carried (#73) and it is what a local library would inherit. Both debts are already recorded where their consumers look: an inserted or changed image is written at metadata_state 1, which is the metadata sweep's work list, and the thumbnail store answers for itself. The tests that used job rows as the measure of "this image owes work" now read metadata_state, which is the record the sweep actually uses; the no-requeue test marks the first image read before the second scan, so it still proves an unchanged neighbour is not put back in debt. Refs #73
This commit is contained in:
+21
-53
@@ -48,7 +48,6 @@ use dr_types::{Availability, FormatFilter, RootId, SourceRef};
|
|||||||
use rusqlite::{Connection, OptionalExtension};
|
use rusqlite::{Connection, OptionalExtension};
|
||||||
|
|
||||||
use crate::error::CatalogError;
|
use crate::error::CatalogError;
|
||||||
use crate::jobs::{self, JobKind, Priority};
|
|
||||||
use crate::query::availability_code;
|
use crate::query::availability_code;
|
||||||
use crate::scan::{
|
use crate::scan::{
|
||||||
classify_dir, classify_entry, DirAction, DirState, EntryAction, KnownFile, ScanOutcome,
|
classify_dir, classify_entry, DirAction, DirState, EntryAction, KnownFile, ScanOutcome,
|
||||||
@@ -336,7 +335,7 @@ pub fn scan_root(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
EntryAction::Insert => {
|
EntryAction::Insert => {
|
||||||
let id = insert_image(
|
insert_image(
|
||||||
&tx,
|
&tx,
|
||||||
root,
|
root,
|
||||||
folder_id,
|
folder_id,
|
||||||
@@ -345,11 +344,10 @@ pub fn scan_root(
|
|||||||
entry.meta.mtime,
|
entry.meta.mtime,
|
||||||
now,
|
now,
|
||||||
)?;
|
)?;
|
||||||
queue_reading_it(&tx, id)?;
|
|
||||||
report.inserted += 1;
|
report.inserted += 1;
|
||||||
}
|
}
|
||||||
EntryAction::Changed => {
|
EntryAction::Changed => {
|
||||||
let id = update_image(
|
update_image(
|
||||||
&tx,
|
&tx,
|
||||||
root,
|
root,
|
||||||
folder_id,
|
folder_id,
|
||||||
@@ -357,7 +355,6 @@ pub fn scan_root(
|
|||||||
entry.meta.size,
|
entry.meta.size,
|
||||||
entry.meta.mtime,
|
entry.meta.mtime,
|
||||||
)?;
|
)?;
|
||||||
queue_reading_it(&tx, id)?;
|
|
||||||
report.updated += 1;
|
report.updated += 1;
|
||||||
}
|
}
|
||||||
EntryAction::Ignored => unreachable!("returned above"),
|
EntryAction::Ignored => unreachable!("returned above"),
|
||||||
@@ -640,7 +637,7 @@ fn insert_image(
|
|||||||
size: u64,
|
size: u64,
|
||||||
mtime: i64,
|
mtime: i64,
|
||||||
now: i64,
|
now: i64,
|
||||||
) -> Result<i64, CatalogError> {
|
) -> Result<(), CatalogError> {
|
||||||
// `metadata_state = 1`: the scan knows the name, the size and the mtime,
|
// `metadata_state = 1`: the scan knows the name, the size and the mtime,
|
||||||
// and has read no EXIF. Claiming otherwise would make a date filter
|
// and has read no EXIF. Claiming otherwise would make a date filter
|
||||||
// silently wrong on a freshly scanned library.
|
// silently wrong on a freshly scanned library.
|
||||||
@@ -664,7 +661,7 @@ fn insert_image(
|
|||||||
now,
|
now,
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
image_id(conn, root, src)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_image(
|
fn update_image(
|
||||||
@@ -674,7 +671,7 @@ fn update_image(
|
|||||||
src: &SourceRef,
|
src: &SourceRef,
|
||||||
size: u64,
|
size: u64,
|
||||||
mtime: i64,
|
mtime: i64,
|
||||||
) -> Result<i64, CatalogError> {
|
) -> Result<(), CatalogError> {
|
||||||
// The content hash is dropped, not recomputed: it described bytes that no
|
// The content hash is dropped, not recomputed: it described bytes that no
|
||||||
// longer exist, and leaving it would let reconnect-by-hash match this image
|
// longer exist, and leaving it would let reconnect-by-hash match this image
|
||||||
// to a file it is no longer a copy of. `metadata_state` goes back to 1 for
|
// to a file it is no longer a copy of. `metadata_state` goes back to 1 for
|
||||||
@@ -692,37 +689,7 @@ fn update_image(
|
|||||||
src.key(),
|
src.key(),
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
image_id(conn, root, src)
|
Ok(())
|
||||||
}
|
|
||||||
|
|
||||||
fn image_id(conn: &Connection, root: RootId, src: &SourceRef) -> Result<i64, CatalogError> {
|
|
||||||
Ok(conn.query_row(
|
|
||||||
"SELECT id FROM images WHERE root_id = ?1 AND source_ref = ?2",
|
|
||||||
rusqlite::params![root.0 as i64, src.key()],
|
|
||||||
|r| r.get(0),
|
|
||||||
)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Queue the work that turns a stat-only row into a usable grid cell.
|
|
||||||
///
|
|
||||||
/// Enqueued inside the scan's transaction, so a folder's rows and the jobs that
|
|
||||||
/// finish them land together — a crash between the two would otherwise leave
|
|
||||||
/// images no worker was ever told about.
|
|
||||||
fn queue_reading_it(conn: &Connection, image_id: i64) -> Result<(), CatalogError> {
|
|
||||||
jobs::enqueue(
|
|
||||||
conn,
|
|
||||||
JobKind::ExtractMetadata,
|
|
||||||
Some(image_id),
|
|
||||||
Priority::Background,
|
|
||||||
None,
|
|
||||||
)?;
|
|
||||||
jobs::enqueue(
|
|
||||||
conn,
|
|
||||||
JobKind::Thumbnail,
|
|
||||||
Some(image_id),
|
|
||||||
Priority::Background,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TRACES: FR-CAT-9
|
/// TRACES: FR-CAT-9
|
||||||
@@ -1096,7 +1063,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn a_resaved_file_is_queued_for_rereading_and_loses_its_stale_hash() {
|
fn a_resaved_file_owes_a_reread_and_loses_its_stale_hash() {
|
||||||
let lib = Library::new("resaved");
|
let lib = Library::new("resaved");
|
||||||
lib.file("IMG.CR3", b"raw");
|
lib.file("IMG.CR3", b"raw");
|
||||||
lib.scan();
|
lib.scan();
|
||||||
@@ -1121,9 +1088,8 @@ mod tests {
|
|||||||
"a hash of bytes that no longer exist would match this image to the \
|
"a hash of bytes that no longer exist would match this image to the \
|
||||||
wrong file on reconnect"
|
wrong file on reconnect"
|
||||||
);
|
);
|
||||||
assert_eq!(lib.count("SELECT metadata_state FROM images"), 1);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
lib.count("SELECT count(*) FROM jobs WHERE kind = 1"),
|
lib.count("SELECT metadata_state FROM images"),
|
||||||
1,
|
1,
|
||||||
"EXIF must be re-read"
|
"EXIF must be re-read"
|
||||||
);
|
);
|
||||||
@@ -1137,7 +1103,11 @@ mod tests {
|
|||||||
let lib = Library::new("no-requeue");
|
let lib = Library::new("no-requeue");
|
||||||
lib.file("a.CR3", b"raw");
|
lib.file("a.CR3", b"raw");
|
||||||
lib.scan();
|
lib.scan();
|
||||||
lib.conn().execute("DELETE FROM jobs", []).unwrap();
|
// As if the metadata sweep had read it: what is owed is recorded in
|
||||||
|
// `metadata_state`, and the thumbnail store answers for itself.
|
||||||
|
lib.conn()
|
||||||
|
.execute("UPDATE images SET metadata_state = 2", [])
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
lib.file("b.CR3", b"raw");
|
lib.file("b.CR3", b"raw");
|
||||||
let r = lib.scan();
|
let r = lib.scan();
|
||||||
@@ -1145,9 +1115,9 @@ mod tests {
|
|||||||
assert_eq!(r.inserted, 1);
|
assert_eq!(r.inserted, 1);
|
||||||
assert_eq!(r.unchanged, 1);
|
assert_eq!(r.unchanged, 1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
lib.count("SELECT count(*) FROM jobs"),
|
lib.count("SELECT count(*) FROM images WHERE metadata_state < 2"),
|
||||||
2,
|
1,
|
||||||
"EXIF and a thumbnail for the new image, and nothing for the old one"
|
"EXIF owed for the new image, and nothing for the old one"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1171,17 +1141,15 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn a_new_image_is_queued_for_a_thumbnail_and_for_exif() {
|
fn a_new_image_owes_its_exif_and_queues_nothing() {
|
||||||
|
// The sweeps find their work from `metadata_state` and the thumbnail
|
||||||
|
// store. A queued job would be a second record of the same debt, and
|
||||||
|
// no handler claims one (#73).
|
||||||
let lib = Library::new("queued");
|
let lib = Library::new("queued");
|
||||||
lib.file("IMG.CR3", b"raw");
|
lib.file("IMG.CR3", b"raw");
|
||||||
lib.scan();
|
lib.scan();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(lib.count("SELECT count(*) FROM jobs"), 0);
|
||||||
lib.count("SELECT count(*) FROM jobs WHERE kind = 2"),
|
|
||||||
1,
|
|
||||||
"no thumbnail job means an empty grid cell forever"
|
|
||||||
);
|
|
||||||
assert_eq!(lib.count("SELECT count(*) FROM jobs WHERE kind = 1"), 1);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
lib.count("SELECT metadata_state FROM images"),
|
lib.count("SELECT metadata_state FROM images"),
|
||||||
1,
|
1,
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user