diff --git a/db/db.rs b/db/db.rs index 4b393a9..f6704b9 100644 --- a/db/db.rs +++ b/db/db.rs @@ -584,10 +584,11 @@ pub struct LockedDatabase { to_delete: Vec, } +/// Represents a row of the `open` database table. #[derive(Copy, Clone, Debug)] -struct Open { - id: u32, - uuid: Uuid, +pub(crate) struct Open { + pub(crate) id: u32, + pub(crate) uuid: Uuid, } /// A modification to be done to a `Stream`, used within `LockedDatabase::flush`. @@ -802,6 +803,10 @@ impl LockedDatabase { /// On success, for each affected sample file directory with a flush watcher set, sends a /// `Flush` event. pub(crate) fn flush(&mut self, reason: &str) -> Result<(), Error> { + let o = match self.open.as_ref() { + None => bail!("database is read-only"), + Some(o) => o, + }; let tx = self.conn.transaction()?; let mut mods = FnvHashMap::with_capacity_and_hasher(self.streams_by_id.len(), Default::default()); @@ -825,7 +830,7 @@ impl LockedDatabase { if !l.synced { break; } if let Some(ref r) = l.recording { raw::insert_recording( - &tx, CompositeId::new(stream_id, s.next_recording_id + i), &r)?; + &tx, o, CompositeId::new(stream_id, s.next_recording_id + i), &r)?; } i += 1; } diff --git a/db/dir.rs b/db/dir.rs index ce431c7..38c55f3 100644 --- a/db/dir.rs +++ b/db/dir.rs @@ -603,7 +603,9 @@ impl Syncer { format!("{}-{}: unflushed={} >= if={}", c.short_name, s.type_.as_str(), unflushed, s.flush_if) }; - let _ = db.flush(&reason); + if let Err(e) = db.flush(&reason) { + error!("flush failure on save: {:?}", e); + } } } diff --git a/db/raw.rs b/db/raw.rs index a62d29d..9586d14 100644 --- a/db/raw.rs +++ b/db/raw.rs @@ -47,8 +47,8 @@ const INSERT_RECORDING_SQL: &'static str = r#" "#; const INSERT_RECORDING_PLAYBACK_SQL: &'static str = r#" - insert into recording_playback (composite_id, sample_file_sha1, video_index) - values (:composite_id, :sample_file_sha1, :video_index) + insert into recording_playback (composite_id, open_id, sample_file_sha1, video_index) + values (:composite_id, :open_id, :sample_file_sha1, :video_index) "#; const STREAM_MIN_START_SQL: &'static str = r#" @@ -73,7 +73,7 @@ const STREAM_MAX_START_SQL: &'static str = r#" "#; /// Inserts the specified recording (for from `try_flush` only). -pub(crate) fn insert_recording(tx: &rusqlite::Transaction, id: CompositeId, +pub(crate) fn insert_recording(tx: &rusqlite::Transaction, o: &db::Open, id: CompositeId, r: &db::RecordingToInsert) -> Result<(), Error> { if r.time.end < r.time.start { bail!("end time {} must be >= start time {}", r.time.end, r.time.start); @@ -98,6 +98,7 @@ pub(crate) fn insert_recording(tx: &rusqlite::Transaction, id: CompositeId, let sha1 = &r.sample_file_sha1[..]; stmt.execute_named(&[ (":composite_id", &id.0), + (":open_id", &o.id), (":sample_file_sha1", &sha1), (":video_index", &r.video_index), ])?; diff --git a/db/schema.sql b/db/schema.sql index 97f5c13..cf5936c 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -202,6 +202,12 @@ create table recording_playback ( -- See description on recording table. composite_id integer primary key references recording (composite_id), + -- The open in which this was committed to the database. For a given + -- composite_id, only one recording will ever be committed to the database, + -- but in-memory state may reflect a recording which never gets committed. + -- This field allows disambiguation in etags and such. + open_id integer not null references open (id), + -- The sha1 hash of the contents of the sample file. sample_file_sha1 blob not null check (length(sample_file_sha1) = 20), diff --git a/src/cmds/upgrade/v1_to_v2.rs b/src/cmds/upgrade/v1_to_v2.rs index ff908bb..f34b4b5 100644 --- a/src/cmds/upgrade/v1_to_v2.rs +++ b/src/cmds/upgrade/v1_to_v2.rs @@ -235,7 +235,7 @@ impl<'a> super::Upgrader for U<'a> { -- Insert sub stream (if path is non-empty) using any id. insert into stream (camera_id, sample_file_dir_id, type, record, rtsp_path, - retain_bytes, next_recording_id) + retain_bytes, flush_if_sec, next_recording_id) select old_camera.id, sample_file_dir.id, @@ -243,7 +243,7 @@ impl<'a> super::Upgrader for U<'a> { 0, old_camera.sub_rtsp_path, 0, - 60, + 90, 1 from old_camera cross join sample_file_dir diff --git a/src/cmds/upgrade/v2_to_v3.rs b/src/cmds/upgrade/v2_to_v3.rs index a8bc7ba..51227c5 100644 --- a/src/cmds/upgrade/v2_to_v3.rs +++ b/src/cmds/upgrade/v2_to_v3.rs @@ -148,16 +148,18 @@ impl super::Upgrader for U { alter table recording_playback rename to old_recording_playback; create table recording_playback ( composite_id integer primary key references recording (composite_id), + open_id integer not null references open (id), sample_file_sha1 blob not null check (length(sample_file_sha1) = 20), video_index blob not null check (length(video_index) > 0) ); insert into recording_playback select - composite_id, - sample_file_sha1, - video_index + p.composite_id, + o.id, + p.sample_file_sha1, + p.video_index from - old_recording_playback; + old_recording_playback p cross join open o; drop table old_recording_playback; "#)?; Ok(()) diff --git a/src/main.rs b/src/main.rs index 4bc3b4b..98f2bf5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -136,7 +136,7 @@ fn main() { h.clone().install().unwrap(); if let Err(e) = { let _a = h.async(); args.arg_command.unwrap().run() } { - error!("{}", e); + error!("{:?}", e); ::std::process::exit(1); } info!("Success.");