From 8e1c15291d264079098862af1addd8d38b9acd73 Mon Sep 17 00:00:00 2001 From: Blake Blackshear Date: Thu, 2 Sep 2021 08:24:53 -0500 Subject: [PATCH] optimize checking recordings for events sorts events and recordings so you can avoid a cartesian product of checking all events against all recordings --- frigate/record.py | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/frigate/record.py b/frigate/record.py index c4e132e1c..cb00d59a3 100644 --- a/frigate/record.py +++ b/frigate/record.py @@ -186,20 +186,38 @@ class RecordingCleanup(threading.Thread): expire_date = min(min_end, expire_before) # Get recordings to check for expiration - recordings: Recordings = Recordings.select().where( - Recordings.camera == camera, - Recordings.end_time < expire_date, + recordings: Recordings = ( + Recordings.select() + .where( + Recordings.camera == camera, + Recordings.end_time < expire_date, + ) + .order_by(Recordings.start_time.desc()) + .objects() ) # Get all the events to check against - events: Event = Event.select().where( - Event.camera == camera, Event.end_time < expire_date, Event.has_clip + events: Event = ( + Event.select() + .where( + Event.camera == camera, Event.end_time < expire_date, Event.has_clip + ) + .order_by(Event.start_time.desc()) + .objects() ) # loop over recordings and see if they overlap with any non-expired events + event_start = 0 + logger.debug( + f"Checking {len(recordings)} recordings against {len(events)} events" + ) for recording in recordings: keep = False - for event in events: + # since the events and recordings are sorted, we can skip events + # that start after the previous recording segment ended + for idx in range(event_start, len(events)): + event = events[idx] + # logger.debug(f"Checking event {event.id}") if ( ( # event starts in this segment event.start_time > recording.start_time @@ -217,6 +235,10 @@ class RecordingCleanup(threading.Thread): keep = True break + # if the event starts after the current recording, skip it next time + if event.start_time > recording.end_time: + event_start = idx + # Delete recordings outside of the retention window if not keep: Path(recording.path).unlink(missing_ok=True)