mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2025-12-08 08:42:41 -05:00
new database/sample file dir interlock scheme
The idea is to avoid the problems described in src/schema.proto; those
possibilities have bothered me for a while. A bonus is that (in a future
commit) it can replace the sample file uuid scheme in favor of using
<camera_uuid>-<stream_type>/<recording_id> for several advantages:
* on data integrity problems (specifically, extra sample files), more
information to use to understand what happened.
* no more reserving sample files prior to using them. This avoids some extra
database transactions on startup (now there's an extra two total rather
than an extra one per stream). It also simplifies an upcoming change I
want to make in which some streams are not flushed immediately, reducing
the write load significantly (maybe one per minute total rather than one
per stream per minute).
* get rid of eight bytes per playback cache entry in RAM (and nine bytes
per recording_playback row on flash).
The implementation is still pretty rough in places:
* Lack of tests.
* Poor ode organization. In particular, SampleFileDirectory::write_meta
shouldn't be exposed beyond db. I'm thinking about moving db.rs and
SampleFileDirectory to a new crate, moonfire_nvr_db. This would improve
compile times as well.
* No tooling for renaming a sample file directory.
* Config subcommand still panics in conditions that can be reasonably
expected to happen.
This commit is contained in:
@@ -207,9 +207,11 @@ fn confirm_deletion(siv: &mut Cursive, db: &Arc<db::Database>, id: i32, to_delet
|
||||
|
||||
fn lower_retention(db: &Arc<db::Database>, zero_limits: BTreeMap<i32, Vec<dir::NewLimit>>)
|
||||
-> Result<(), Error> {
|
||||
let dirs_to_open: Vec<_> = zero_limits.keys().map(|id| *id).collect();
|
||||
db.lock().open_sample_file_dirs(&dirs_to_open[..])?;
|
||||
for (dir_id, l) in &zero_limits {
|
||||
let dir = db.lock().sample_file_dirs_by_id().get(dir_id).unwrap().open()?;
|
||||
dir::lower_retention(dir, db.clone(), &l)?;
|
||||
let dir = db.lock().sample_file_dirs_by_id().get(dir_id).unwrap().get()?;
|
||||
dir::lower_retention(dir.clone(), db.clone(), &l)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -145,8 +145,9 @@ fn actually_delete(model: &RefCell<Model>, siv: &mut Cursive) {
|
||||
siv.pop_layer(); // deletion confirmation
|
||||
siv.pop_layer(); // retention dialog
|
||||
let dir = {
|
||||
let l = model.db.lock();
|
||||
l.sample_file_dirs_by_id().get(&model.dir_id).unwrap().open().unwrap()
|
||||
let mut l = model.db.lock();
|
||||
l.open_sample_file_dirs(&[model.dir_id]).unwrap(); // TODO: don't unwrap.
|
||||
l.sample_file_dirs_by_id().get(&model.dir_id).unwrap().get().unwrap()
|
||||
};
|
||||
if let Err(e) = dir::lower_retention(dir, model.db.clone(), &new_limits[..]) {
|
||||
siv.add_layer(views::Dialog::text(format!("Unable to delete excess video: {}", e))
|
||||
@@ -281,7 +282,7 @@ fn edit_dir_dialog(db: &Arc<db::Database>, siv: &mut Cursive, dir_id: i32) {
|
||||
let mut total_retain = 0;
|
||||
let fs_capacity;
|
||||
{
|
||||
let l = db.lock();
|
||||
let mut l = db.lock();
|
||||
for (&id, s) in l.streams_by_id() {
|
||||
let c = l.cameras_by_id().get(&s.camera_id).expect("stream without camera");
|
||||
if s.sample_file_dir_id != Some(dir_id) {
|
||||
@@ -299,10 +300,9 @@ fn edit_dir_dialog(db: &Arc<db::Database>, siv: &mut Cursive, dir_id: i32) {
|
||||
if streams.is_empty() {
|
||||
return delete_dir_dialog(db, siv, dir_id);
|
||||
}
|
||||
l.open_sample_file_dirs(&[dir_id]).unwrap(); // TODO: don't unwrap.
|
||||
let dir = l.sample_file_dirs_by_id().get(&dir_id).unwrap();
|
||||
|
||||
// TODO: go another way if open fails.
|
||||
let stat = dir.open().unwrap().statfs().unwrap();
|
||||
let stat = dir.get().unwrap().statfs().unwrap();
|
||||
fs_capacity = stat.f_bsize as i64 * stat.f_bavail as i64 + total_used;
|
||||
path = dir.path.clone();
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ struct Args {
|
||||
pub fn run() -> Result<(), Error> {
|
||||
let args: Args = super::parse_args(USAGE)?;
|
||||
let (_db_dir, conn) = super::open_conn(&args.flag_db_dir, super::OpenMode::ReadWrite)?;
|
||||
let db = Arc::new(db::Database::new(conn)?);
|
||||
let db = Arc::new(db::Database::new(conn, true)?);
|
||||
|
||||
let mut siv = Cursive::new();
|
||||
//siv.add_global_callback('q', |s| s.quit());
|
||||
|
||||
Reference in New Issue
Block a user