diff --git a/db/raw.rs b/db/raw.rs index 4e53413..37953bd 100644 --- a/db/raw.rs +++ b/db/raw.rs @@ -226,8 +226,8 @@ pub(crate) fn insert_recording(tx: &rusqlite::Transaction, o: &db::Open, id: Com Ok(()) } -/// Tranfers the given recording range from the `recording` and `recording_playback` tables to the -/// `garbage` table. `sample_file_dir_id` is assumed to be correct. +/// Transfers the given recording range from the `recording` and associated tables to the `garbage` +/// table. `sample_file_dir_id` is assumed to be correct. /// /// Returns the number of recordings which were deleted. pub(crate) fn delete_recordings(tx: &rusqlite::Transaction, sample_file_dir_id: i32, @@ -244,19 +244,25 @@ pub(crate) fn delete_recordings(tx: &rusqlite::Transaction, sample_file_dir_id: :start <= composite_id and composite_id < :end "#)?; - let mut del1 = tx.prepare_cached(r#" + let mut del_playback = tx.prepare_cached(r#" delete from recording_playback where :start <= composite_id and composite_id < :end "#)?; - let mut del2 = tx.prepare_cached(r#" + let mut del_integrity = tx.prepare_cached(r#" delete from recording_integrity where :start <= composite_id and composite_id < :end "#)?; - let mut del3 = tx.prepare_cached(r#" + let mut del_detection = tx.prepare_cached(r#" + delete from recording_object_detection + where + :start <= composite_id and + composite_id < :end + "#)?; + let mut del_main = tx.prepare_cached(r#" delete from recording where :start <= composite_id and @@ -271,17 +277,20 @@ pub(crate) fn delete_recordings(tx: &rusqlite::Transaction, sample_file_dir_id: ":start": ids.start.0, ":end": ids.end.0, }; - let n1 = del1.execute_named(p)?; - if n1 != n { - bail!("inserted {} garbage rows but deleted {} recording_playback rows!", n, n1); + let n_playback = del_playback.execute_named(p)?; + if n_playback != n { + bail!("inserted {} garbage rows but deleted {} recording_playback rows!", n, n_playback); } - let n2 = del2.execute_named(p)?; - if n2 > n { // fewer is okay; recording_integrity is optional. - bail!("inserted {} garbage rows but deleted {} recording_integrity rows!", n, n2); + let n_integrity = del_integrity.execute_named(p)?; + if n_integrity > n { // fewer is okay; recording_integrity is optional. + bail!("inserted {} garbage rows but deleted {} recording_integrity rows!", n, n_integrity); } - let n3 = del3.execute_named(p)?; - if n3 != n { - bail!("deleted {} recording rows but {} recording_playback rows!", n3, n); + // Any number of object detection rows is okay, as there can be zero or more models per + // recording. + del_detection.execute_named(p)?; + let n_main = del_main.execute_named(p)?; + if n_main != n { + bail!("inserted {} garbage rows but deleted {} recording rows!", n, n_main); } Ok(n) } diff --git a/db/schema.sql b/db/schema.sql index e361bef..d79b43e 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -497,5 +497,45 @@ create table signal_change ( changes blob not null ); +create table object_detection_model ( + id integer primary key, + uuid blob unique not null check (length(uuid) = 16), + name text not null, + + -- The actual model and label mappings, in a tbd protocol buffer message + -- format. + data blob +); + +-- An entry for every supported label in any model. (E.g., there is one row +-- for "person" even if there are many models that support detecting people.) +create table object_detection_label ( + id integer primary key, + uuid blob unique not null check (length(uuid) = 16), + name text unique not null, + color text +); + +create table recording_object_detection ( + composite_id integer not null references recording (composite_id), + model_id integer not null references object_detection_model (id), + + -- repeated: + -- * frame delta unsigned varint + -- * label unsigned varint + -- * xmin, xmax, ymin, ymax as fixed 8-bit numbers + -- (any value from knowing xmin <= xmax, ymin <= ymax? + -- probably not a whole byte anyway.) + -- although 256/300 or 256/320 is not super clean. awkward. + -- * score/probability/whatever-it's-called as fixed 8-bit number + -- linear scale? + frame_data blob not null, + + -- Operations are almost always done on a bounded set of recordings, so + -- and perhaps on all models. Use composite_id as the prefix of the primary + -- key to make these efficient. + primary key (composite_id, model_id) +); + insert into version (id, unix_time, notes) values (6, cast(strftime('%s', 'now') as int), 'db creation'); diff --git a/db/upgrade/v5_to_v6.rs b/db/upgrade/v5_to_v6.rs index b3e2acc..159239c 100644 --- a/db/upgrade/v5_to_v6.rs +++ b/db/upgrade/v5_to_v6.rs @@ -209,6 +209,27 @@ pub fn run(_args: &super::Args, tx: &rusqlite::Transaction) -> Result<(), Error> revocation_reason_detail = 'Blake2b->Blake3 upgrade' where revocation_reason is null; + + create table object_detection_model ( + id integer primary key, + uuid blob unique not null check (length(uuid) = 16), + name text not null, + data blob + ); + + create table object_detection_label ( + id integer primary key, + uuid blob unique not null check (length(uuid) = 16), + name text unique not null, + color text + ); + + create table recording_object_detection ( + composite_id integer not null references recording (composite_id), + model_id integer not null references object_detection_model (id), + frame_data blob not null, + primary key (composite_id, model_id) + ); "#)?; Ok(()) } diff --git a/guide/schema.md b/guide/schema.md index b87522b..55f4888 100644 --- a/guide/schema.md +++ b/guide/schema.md @@ -252,8 +252,7 @@ Version 6 adds over version 5: streams. * hashes in Blake3 rather than older SHA-1 (for file integrity checksums) or Blake2b (for sessions). +* a preliminary schema for [object + detection](https://en.wikipedia.org/wiki/Object_detection). -On upgrading to this version, sessions will be wiped. - -Before it is finalized, it likely will also add a schema for [object -detection](https://en.wikipedia.org/wiki/Object_detection). +On upgrading to this version, sessions will be revoked.