Scott Lamb b41a6c43da shutdown better
After a frustrating search for a suitable channel to use for shutdown
(tokio::sync::Receiver and
futures::future::Shared<tokio::sync::oneshot::Receiver> didn't look
quite right) in which I rethought my life decisions, I finally just made
my own (server/base/shutdown.rs). We can easily poll it or wait for it
in async or sync contexts. Most importantly, it's convenient; not that
it really matters here, but it's also efficient.

We now do a slightly better job of propagating a "graceful" shutdown
signal, and this channel will give us tools to improve it over time.

* Shut down even when writer or syncer operations are stuck. Fixes #117
* Not done yet: streamers should instantly shut down without waiting for
  a connection attempt or frame or something. I'll probably
  implement that when removing --rtsp-library=ffmpeg. The code should be
  cleaner then.
* Not done yet: fix a couple places that sleep for up to a second when
  they could shut down immediately. I just need to do the plumbing for
  mock clocks to work.

I also implemented an immediate shutdown mode, activated by a second
signal. I think this will mitigate the streamer wait situation.
2021-09-23 16:33:29 -07:00

61 lines
2.0 KiB
Rust

// This file is part of Moonfire NVR, a security camera network video recorder.
// Copyright (C) 2020 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt.
// SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception.
//! Subcommand to check the database and sample file dir for errors.
use db::check;
use failure::Error;
use std::path::PathBuf;
use structopt::StructOpt;
#[derive(StructOpt)]
pub struct Args {
/// Directory holding the SQLite3 index database.
#[structopt(
long,
default_value = "/var/lib/moonfire-nvr/db",
value_name = "path",
parse(from_os_str)
)]
db_dir: PathBuf,
/// Compare sample file lengths on disk to the database.
#[structopt(long)]
compare_lens: bool,
/// Trash sample files without matching recording rows in the database.
/// This addresses "Missing ... row" errors.
///
/// The ids are added to the "garbage" table to indicate the files need to
/// be deleted. Garbage is collected on normal startup.
#[structopt(long)]
trash_orphan_sample_files: bool,
/// Delete recording rows in the database without matching sample files.
/// This addresses "Recording ... missing file" errors.
#[structopt(long)]
delete_orphan_rows: bool,
/// Trash recordings when their database rows appear corrupt.
/// This addresses "bad video_index" errors.
///
/// The ids are added to the "garbage" table to indicate their files need to
/// be deleted. Garbage is collected on normal startup.
#[structopt(long)]
trash_corrupt_rows: bool,
}
pub fn run(args: Args) -> Result<i32, Error> {
let (_db_dir, mut conn) = super::open_conn(&args.db_dir, super::OpenMode::ReadWrite)?;
check::run(
&mut conn,
&check::Options {
compare_lens: args.compare_lens,
trash_orphan_sample_files: args.trash_orphan_sample_files,
delete_orphan_rows: args.delete_orphan_rows,
trash_corrupt_rows: args.trash_corrupt_rows,
},
)
}