new rows into images would (due to the foreign key constraint) lock the corresponding
row in event using a shared lock, then the update (due to last_picture) would
upgrade the lock to exclusive, causing a deadlock later. To fix this, we move
last_picture into its own table; we could also lock it explicitly earlier, but
that would stall other transactions (and they can run for 10-15 seconds or so,
or perhaps even longer) so it is not desirable.
# update the last_picture cache as well (this should of course be done
# via a trigger, but this is less complicated :-) )
- $dbh->do('UPDATE events SET last_picture=GREATEST(last_picture, ?) FROM images WHERE event=events.id) WHERE id=(SELECT event FROM images WHERE id=?)',
+ $dbh->do('UPDATE last_picture_cache SET last_picture=GREATEST(last_picture, ?) FROM images WHERE event=events.id) WHERE id=(SELECT event FROM images WHERE id=?)',
undef, $datetime, $id)
or die "Couldn't update last_picture in SQL: $!";
}
# my $q = $dbh->prepare('SELECT t1.id,t1.date,t1.name FROM events t1 LEFT JOIN images t2 ON t1.id=t2.event WHERE t1.vhost=? GROUP BY t1.id,t1.date,t1.name ORDER BY COALESCE(MAX(t2.date),\'1970-01-01 00:00:00\'),t1.id') or
# dberror($r, "Couldn't list events");
- my $q = $dbh->prepare('SELECT id,date,name FROM events WHERE vhost=? ORDER BY last_picture DESC')
+ my $q = $dbh->prepare('SELECT id,date,name FROM events e JOIN last_picture_cache c ON e.id=c.event WHERE vhost=? ORDER BY last_picture DESC')
or dberror($r, "Couldn't list events");
$q->execute($r->get_server_name)
or dberror($r, "Couldn't get events");
id character varying NOT NULL PRIMARY KEY,
date character varying NOT NULL,
name character varying NOT NULL,
- vhost character varying NOT NULL,
- last_picture timestamp without time zone DEFAULT '1970-01-01 00:00:00'::timestamp without time zone NOT NULL
+ vhost character varying NOT NULL
+);
+
+-- In a separate table to avoid deadlocks.
+CREATE TABLE last_picture_cache (
+ event varchar PRIMARY KEY references events ( id ),
+ last_picture timestamp without time zone
);
CREATE TABLE images (