Files
zoneminder/scripts/ZoneMinder/lib/ZoneMinder/Frame.pm
T
Isaac ConnorandClaude Opus 5.5 c4ef3fdd62 feat: key Frames by (EventId, FrameId) and drop the surrogate Id refs #5164
Every query on Frames filters on EventId and orders or ranges by FrameId,
and nothing needs a frame by Id. The Id primary key was a clustered index
nothing read, and EventId_FrameId_idx was a secondary index every query
used. On a copy of a local table that secondary index was half the
table's size. With (EventId, FrameId) as the primary key the index is
gone, and an event's rows are stored together, so deleting an event is a
range delete.

zm_update-1.39.36.sql:
- converts AI_Detections.FrameId from Frames.Id to the per-event frame
  number, drops its foreign key to Frames and indexes (EventId, FrameId).
  A composite foreign key cannot replace it: ON DELETE SET NULL would
  have to null the NOT NULL EventId, and Frames rows are written in
  batches, so a detection can be recorded before its frame row.
- removes duplicate (EventId, FrameId) rows, keeping the earliest.
- rebuilds Frames with the new primary key.
- removes ON UPDATE CURRENT_TIMESTAMP from Frames.TimeStamp. Any UPDATE
  of a frame row was overwriting its capture time.
Each step checks the current schema first, so the migration can be
re-run.

REST API: view, edit and delete take /frames/<action>/<EventId>/<FrameId>.json.
The old single-Id URLs return 404. CakePHP 2 has no composite keys, so
the model's primaryKey is EventId. That keeps Event's dependent cascade
delete limited to the event's own frames. The controller writes with
explicit (EventId, FrameId) conditions instead of save(), which would
match rows on EventId alone. Edit no longer changes EventId or FrameId.

view=image with fid but no eid used to look up Frames.Id. It now returns
404.

The Perl Frame class is identified by (EventId, FrameId).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:48:26 -04:00

77 lines
1.9 KiB
Perl

# ==========================================================================
#
# ZoneMinder Monitor Module, $Date$, $Revision$
# Copyright (C) 2001-2008 Philip Coombes
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# ==========================================================================
#
# This module contains the common definitions and functions used by the rest
# of the ZoneMinder scripts
#
package ZoneMinder::Frame;
use 5.006;
use strict;
use warnings;
require ZoneMinder::Base;
require ZoneMinder::Object;
use parent qw(ZoneMinder::Object);
use vars qw/ $table @identified_by %fields /;
$table = 'Frames';
@identified_by = ('EventId', 'FrameId');
%fields = (
EventId => 'EventId',
FrameId => 'FrameId',
Type => 'Type',
TimeStamp => 'TimeStamp',
Delta => 'Delta',
Score => 'Score',
);
sub Event {
return new ZoneMinder::Event( $_[0]{EventId} );
} # end sub Event
1;
__END__
=head1 NAME
ZoneMinder::Frame - Perl Class for Frames
=head1 SYNOPSIS
use ZoneMinder::Frame;
=head1 AUTHOR
Isaac Connor, E<lt>isaac@zoneminder.comE<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2001-2017 ZoneMinder LLC
Licensed under the GNU General Public License v2 or later; see the COPYING
file distributed with ZoneMinder for the full text.
=cut