Commit Graph

713 Commits

Author SHA1 Message Date
Scott Lamb 91636d3193 refine flush_if_sec behavior
The new behavior eliminates a couple unpleasant edge cases in which it
would never flush:

* if all recording stops, whatever was unflushed would stay that way
* if every recording attempt produces a 0-duration recording (such as if the
  camera sends only one frame and thus no PTS delta can be calculated),
  the list of recordings to flush would continue to grow
2018-03-23 15:16:43 -07:00
Scott Lamb addeb9d2f6 add a TimerGuard around db locks & ops
I moved the clocks member from LockedDatabase to Database to make this happen,
so the new DatabaseGuard (replacing a direct MutexGuard<LockedDatabase>) can
access it before acquiring the lock.

I also made the type of clock a type parameter of Database (and so several
other things throughout the system). This allowed me to drop the Arc<>, but
more importantly it means that the Clocks trait doesn't need to stay
object-safe. I plan to take advantage of that shortly.
2018-03-23 13:31:23 -07:00
Scott Lamb c0da1ef880 make v1->v3 upgrade work with --features=bundled
--features=bundled enables -DSQLITE_DEFAULT_FOREIGN_KEYS=1, and so some
operations have to be done in the proper order.

* enable foreign key enforcement all the time, so I test this more reliably.
* reorder some parts of the v1->v3 order. foreign key enforcement is
  immediate (rather than deferred) by default. and ensure
  old_recording_playback isn't left with a dangling reference to old_recording
  at the v2 stage. Instead, wait until v3 to delete tables it depends on.
2018-03-22 09:05:40 -07:00
Scott Lamb c46c50af8f fix another upgrade error in dfee66c 2018-03-22 00:08:49 -07:00
Scott Lamb 2ff7ecb6f4 fix upgrade procedure broken in dfee66c 2018-03-22 00:00:39 -07:00
Scott Lamb 1c9f2a4d83 initial schema for user authentication (#26)
This is only the database schema, which I'm adding now in the hopes of
freezing schema version 3. There's no way yet to create users, much less
actually authenticate.
2018-03-21 23:57:45 -07:00
Scott Lamb dfee66c84b support additional recording_integrity timestamps
These are not actually populated by the code yet. I'm trying to get the
v3 schema frozen as soon as possible; actually using the fields can come
later.

Add some explanation of their value in time.md, along with some general
musing on leap seconds, and a correction on the frequency error of my cameras.
2018-03-21 22:32:41 -07:00
Scott Lamb 88051a1188 adjust startup timings again
I forgot to drop the cache before grabbing the numbers earlier today.
2018-03-20 22:37:45 -07:00
Scott Lamb bdf52d743b adjust some timings in schema.md
The new numbers are taken from my odroid setup. In particular, the size check
is noticeably slower than what I'd gathered before, enough to show that it
shouldn't be performed on startup.
2018-03-20 08:46:48 -07:00
Dolf Starreveld 58152e8d94 Major refactoring of UI code, small UI changes. (#48)
* Major refactoring of UI code, small UI changes.

* Single file index.js split up into separate modules
* Modules for handling UI view components
* Modules for handling JSON/Model data
* Modules for support tasks
* Module to encapsulate Moonfire API
* Main application module
* index.js simplified to just activating main app
* Settings file functionality expanded
* UI adds "Time Format" popup to allow changing time representation
* CSS changes/additions to streamline looks
* Recordings loading indicator only appears after 500ms delay, if at all

* Address first set of PR change requests from Scott.

* Add copyright headers to all files (except JSON files)
* Fix bug with entering time values in range pickers
* Fixed an erroneous comment and/or spelling error here and there
* Fixed JSDoc comments where [description] was not filled in
* Removed a TODO from NVRApplication as it no longer applies
* Fixed bug handling "infinite" case of video segment lengths
* Fixed bug in "trim" handler and trim execution

* Retrofit video continues loading from separate PR

Signed-off-by: Dolf Starreveld <dolf@starreveld.com>

* Address PR comments

Signed-off-by: Dolf Starreveld <dolf@starreveld.com>

* Address PR comments

Signed-off-by: Dolf Starreveld <dolf@starreveld.com>
2018-03-20 07:03:12 -07:00
Scott Lamb caac324bd5 remove moonfire.sublime-workspace
10e736d added this, looks like mistakenly. This file has machine-specific
paths in it, and PR #48 adds it to .gitignore.
2018-03-18 20:59:32 -07:00
Scott Lamb 320374c6e9 favicon: security camera in orange/red circle
This is derived from the following icon:
https://thenounproject.com/term/security-camera/72530
by iconsmind.com. I paid for the royalty-free license.

Fixes #50.
2018-03-12 22:47:44 -07:00
Scott Lamb 0e365a23e1
Merge pull request #52 from dolfs/pr-fix-video-close
Fix bug where video stream continued fetching on player close.
2018-03-12 21:34:47 -07:00
Dolf Starreveld 10e736dd63 Fix bug where video stream continued fetching on player close. 2018-03-12 21:11:27 -07:00
Scott Lamb 4c8daa6d24 save timestamps along with opens 2018-03-10 16:15:36 -08:00
Scott Lamb 5854b31b76 serve .map files as Javascript
This fixes #47 for now at least.
2018-03-10 16:04:37 -08:00
Scott Lamb f81d699c8c new recording_integrity table
A couple rarely-used fields move to here, and I expect I'll add more.
Redo the check command to just put everything in RAM for simplicity.
2018-03-09 13:37:30 -08:00
Scott Lamb 03809eee8e clean up leftover throwaway logging 2018-03-09 10:46:34 -08:00
Scott Lamb 84ce24b7f6
Merge pull request #24 from dolfs/pr-ui-dev-2
Settings can now be taken from separate file with local override.
2018-03-08 21:59:49 -08:00
Dolf Starreveld 353a860146 Normalize case of "Moonfire" 2018-03-08 21:52:15 -08:00
Dolf Starreveld 5727adf3df Settings can now be taken from separate file with local override.
* Various settings in settings-nvr.js module
* settings-nvr-local.js can override settings-nvr.js
* settings-nvr-local is unchecked file
* Both files can be straight maps, or functions returning maps
* webpack env and args available to those functions
2018-03-08 18:26:41 -08:00
Scott Lamb 678fb54b21 delete stale webpack.config.js
This was obsoleted by #22 / a03b986 but mistakenly not deleted.
2018-03-08 02:42:30 -08:00
Dolf Starreveld 8a0bc4c401 Change to allow formatTime to accept a format string. (#23)
* Default format string causes it to work as before
* New FFFF format supported for fractional second in 90k units
2018-03-08 02:41:13 -08:00
Dolf Starreveld a03b98631a Changes to allow active development of UI using webpack and hotloading. (#22)
* Changes to allow active development of UI using webpack and hotloading.

* Update to webpack 4 (will make this work)
* Update webpack.config.js accordingly
* Move webpack.config.js to its own directory
* Split webpack.config.js into base.config.js, dev.config.js and prod.config.js
* Update configs to be "right" for development vs production using --mode

* Want configuration through (optional) local file that is not
  checked in

* Updated package.json for newer babel-loader

* Put in a proxy to localhost port 8080 for evelopment server.

This allows "yarn start" to work on the machine where MoonFire's
server is running. This would be the default situation. Users in
a different setup can change the proxy settings.
2018-03-07 17:34:08 -08:00
Scott Lamb d6fa470713 tests and fixes for Writer and Syncer
* separate these out into a new file, writer.rs, as dir.rs was getting
  unwieldy.
* extract traits for the parts of SampleFileDir and std::fs::File they needed;
  set up mock implementations.
* move clock.rs to a new base crate to be accessible from the db crate.
* add tests that exercise all the retry paths.
* bugfix: account for the new recording's bytes when calculating how much to
  delete.
* bugfix: when retrying an unlink failure in collect_garbage, we shouldn't
  warn about all the recordings no longer existing. Do this by retrying each
  step rather than the whole procedure again.
* avoid double-panic scenarios, which I hit while tweaking the mocks. These
  are quite annoying to debug as Rust doesn't print information about either
  panic. I ended up using lldb to get a backtrace. Better to be cautious about
  what we're doing when already panicking.
* give more context on raw::insert_recording errors, which I hit as well while
  tweaking the new tests.
2018-03-07 04:42:46 -08:00
Dolf Starreveld e4cc8d6c0f Install and build script enhancements (#21)
* Install and build script enhancements

* Use functions for all reporting for consistent output
* Update reporting text to be more clear
* Add some additional messages
* Re-check some install prep items also in install script
* Fix a bug where the wrong db directory would be configured to the service

* Satisfy PR requested changes (spelling mostly).
2018-03-07 04:31:51 -08:00
Scott Lamb 672a327ee2
support serving Access-Control-Allow-Origin header (#19)
support serving Access-Control-Allow-Origin header

Closes #17.
2018-03-03 06:43:36 -08:00
Dolf Starreveld 760b8d95fb Rewrite of the installation script and accompanying documentation. (#15)
Rewrite of the installation script and accompanying documentation.
2018-03-03 06:41:15 -08:00
Scott Lamb b78ffc3808 view in-progress recordings!
The time from recorded to viewable was previously 60-120 sec for the first
recording of a RTSP session, 0-60 sec otherwise. Now it's one frame.
2018-03-02 15:40:32 -08:00
Scott Lamb 45f7b30619 allow listing and viewing uncommitted recordings
There may be considerable lag between being fully written and being committed
when using the flush_if_sec feature. Additionally, this is a step toward
listing and viewing recordings before they're fully written. That's a
considerable delay: 60 to 120 seconds for the first recording of a run,
0 to 60 seconds for subsequent recordings.

These recordings aren't yet included in the information returned by
/api/?days=true. They probably should be, but small steps.
2018-03-02 11:38:11 -08:00
Scott Lamb b17761e871 move list_recordings_by_* logic into raw.rs
I want to start having the db.rs version augment this with the uncommitted
recordings, and it's nice to have the separation of the raw db vs augmented
versions. Also, this fits with the general theme of shrinking db.rs a bit.

I had to put the raw video_sample_entry_id into the rows rather than
the video_sample_entry Arc. In hindsight, this is better anyway: the common
callers don't need to do the btree lookup and arc clone on every row. I think
I'd originally done it that way only because I was quite new to rust and
didn't understand that db could be used from within the row callback given
that both borrows are immutable.
2018-03-01 20:59:05 -08:00
Scott Lamb b2a8b3c216 update "moonfire-nvr check" for new schema 2018-03-01 17:07:42 -08:00
Scott Lamb b677964d1a properly account for bytes to add with next flush
This was considering them as 0, so it would under-delete until the next flush
them delete all at once. That effectively doubled the number of bytes not yet
deleted as they're first transferred to garbage, flushed again, then unlinked.
2018-03-01 13:50:59 -08:00
Scott Lamb 0f2e71ec4a more safety around adding/deleting dirs 2018-03-01 12:24:32 -08:00
Scott Lamb f01f523c2c refine 1->3 upgrade process
In hindsight, the "post_tx" step in the upgrade process introduced in
e7f5733 doesn't make sense. If the procedure fails at this stage, nothing says
it still needs to be completed. If the sample file dirs have to be updated
after the database, then there should be another database version to mark that
it's fully completed, and indeed that's the purpose version 3 serves. So get
rid of the Upgrader trait and just go back to a simple run function per
version.

In the case of the sample file dir metadata, it actually can happen before the
database transaction; the stuff written to the database later just needs to be
consistent with what it finds if there's an existing metadata file from a
half-completed update.

For safety, ensure there are no unexpected directory contents before
upgrading 1->2, and ensure the metadata matches before upgrading 2->3.
2018-03-01 09:47:56 -08:00
Scott Lamb bcf42fe02c move db upgrade logic into db crate
This allows shrinking db's API surface.
2018-02-28 21:21:47 -08:00
Scott Lamb fbe1231af0 move open_id from recording_playback to recording
I want to be able to use it in etags without having to do a full scan of the
recording_playback in advance, which would greatly increase time to first
byte. I probably will even use it in urls to ensure the segments they point to
are stable. I haven't actually done this yet - it will wait until I implement
serving unflushed recordings - but I want to get the schema set up properly.
2018-02-28 20:52:43 -08:00
Scott Lamb fb4d88d3e2 make db::dir::Writer equally stubborn
Every recording it starts must be sent to the syncer with at least one sample
written. It will try forever (unless the channel is down, then panic). This
avoids the situation in which it prevents something in the uncommitted
VecDeque from ever being synced and thus any further recordings from being
flushed.
2018-02-28 12:32:52 -08:00
Scott Lamb b1d71c4e8d improve Syncer's robustness
The new approach is to, rather than panicking, retry forever. The assumption
is that if a given operation is failing, a following operation is unlikely to
succeed, so it's simpler to just keep trying the earlier one than come up with
ways to undo it and proceed with later operations.

I still need to apply this approach to the Writer class. It currently unwraps
(crashes) or just gives up on a recording without ever sending it to the
Syncer. Given that recordings are all synced in order, that means further ones
can never be synced.
2018-02-28 11:07:55 -08:00
Scott Lamb b790075ca2 fix flush_if_sec updates not hitting db 2018-02-23 14:49:10 -08:00
Scott Lamb 81e1ec97b3 more sanity checking for delete_oldest_recordings 2018-02-23 14:05:07 -08:00
Scott Lamb 8d9939603e fix repeated deletions within a flush
When list_oldest_recordings was called twice with no intervening flush, it
returned the same rows twice. This led to trying to delete it twice and all
following flushes failing with a "no such recording x/y" message. Now, return
each row only once, and track how many bytes have been returned.

I think dir.rs's logic is still wrong for how many bytes to delete when
multiple recordings are flushed at once (it ignores the bytes added by the
first when computing the bytes to delete for the second), but this is
progress.
2018-02-23 13:49:57 -08:00
Scott Lamb 843e1b49c8 take FnMut closures by reference
I mistakenly thought these had to be monomorphized. (The FnOnce still
does, until rust-lang/rfcs#1909 is implemented.) Turns out this way works
fine. It should result in less compile time / code size, though I didn't check
this.
2018-02-23 09:19:42 -08:00
Scott Lamb d9841fd634 fix compilation error in benchmark
This needs a separate run of "cargo +nightly bench --features=nightly", so I
missed it in a couple previous commits. I probably should set up travis-ci...
2018-02-22 21:57:43 -08:00
Scott Lamb bf45ae6011 extend recording_playback with an open_id
As noted in schema.sql, this can be used for disambiguation. It also may be
useful in diagnosing data integrity problems.

Also, sneak in a couple minor improvements: better diagnostics in a couple
places, fix to 1->2 upgrade procedure.
2018-02-22 21:46:41 -08:00
Scott Lamb b037c9bdd7 knob to reduce db commits (SSD write cycles)
This improves the practicality of having many streams (including the doubling
of streams by having main + sub streams for each camera). With these tuned
properly, extra streams don't cause any extra write cycles in normal or error
cases. Consider the worst case in which each RTSP session immediately sends a
single frame and then fails. Moonfire retries every second, so this would
formerly cause one commit per second per stream. (flush_if_sec=0 preserves
this behavior.) Now the commits can be arbitrarily infrequent by setting
higher values of flush_if_sec.

WARNING: this isn't production-ready! I hacked up dir.rs to make tests pass
and "moonfire-nvr run" work in the best-case scenario, but it doesn't handle
errors gracefully. I've been debating what to do when writing a recording
fails. I considered "abandoning" the recording then either reusing or skipping
its id. (in the latter case, marking the file as garbage if it can't be
unlinked immediately). I think now there's no point in abandoning a recording.
If I can't write to that file, there's no reason to believe another will work
better. It's better to retry that recording forever, and perhaps put the whole
directory into an error state that stops recording until those writes go
through. I'm planning to redesign dir.rs to make this happen.
2018-02-22 16:35:34 -08:00
Scott Lamb 31adbc1e9f initial split of database to a separate crate
It should reduce compile time / memory usage to put quite a bit of the code
into a separate crate. I also intend to limit visibility of some things to
only within the db crate, but that's for a future change. This is the smallest
move that will compile.
2018-02-20 23:15:39 -08:00
Scott Lamb d84e754b2a replace homegrown Error with failure crate
This reduces boilerplate, making it a bit easier for me to split the db stuff
out into its own crate.
2018-02-20 22:46:14 -08:00
Scott Lamb 253f3de399 reorganize the sample file directory
The filenames now represent composite ids (stream id + recording id) rather
than a separate uuid system with its own reservation for a few benefits:

  * This provides more information when there are inconsistencies.

  * This avoids the need for managing the reservations during recording. I
    expect this to simplify delaying flushing of newly written sample files.
    Now the directory has to be scanned at startup for files that never got
    written to the database, but that's acceptably fast even with millions of
    files.

  * Less information to keep in memory and in the recording_playback table.

I'd considered using one directory per stream, which might help if the
filesystem has trouble coping with huge directories. But that would mean each
dir has to be fsync()ed separately (more latency and/or more multithreading).
So I'll stick with this until I see concrete evidence of a problem that would
solve.

Test coverage of the error conditions is poor. I plan to do some restructuring
of the db/dir code, hopefully making steps toward testability along the way.
2018-02-20 10:11:10 -08:00
Scott Lamb e7f5733f29 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.
2018-02-14 23:35:52 -08:00