From 52d5f80e0813bf841792bc53bca22ff21228dd85 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 16 May 2026 23:14:37 -0400 Subject: [PATCH] docs: clarify per-monitor UPDATE lock state in zmstats resync The previous comment claimed each UPDATE couldn't hold any bucket lock that would deadlock with the trigger path, which conflated statement- level locks with TX-level locks. By the time we reach this loop the TX already holds bucket-row X-locks from the earlier DELETEs plus any ES X-locks acquired by the bucket DELETE triggers cascading. Rewrite the comment to distinguish those TX-held locks from the locks acquired by the new UPDATE statement and to be explicit that the TX's lock acquisition direction is preserved. --- scripts/zmstats.pl.in | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/scripts/zmstats.pl.in b/scripts/zmstats.pl.in index dee478141..70b066452 100644 --- a/scripts/zmstats.pl.in +++ b/scripts/zmstats.pl.in @@ -179,9 +179,14 @@ while (!$zm_terminate) { } } - # One UPDATE per monitor: each takes a single ES X-lock and reads - # nothing else, so it can't hold any bucket-row lock that would - # deadlock with the trigger path. + # One UPDATE per monitor. The transaction at this point is still + # holding the bucket-row X-locks acquired by the earlier DELETEs and + # any ES X-locks the bucket DELETE triggers acquired as a cascade. + # Those were all acquired in the canonical order (buckets -> ES) so + # they don't conflict with the trigger writers. The new statement + # itself only X-locks the one ES row it targets and reads no other + # table, so it doesn't add any cross-table dependency that could form + # a new cycle — its lock acquisition continues in the same direction. if (!$err) { for my $mid (sort { $a <=> $b } keys %agg) { my $a = $agg{$mid};