svn commit: r1936613 - spamassassin/trunk/lib/Mail/SpamAssassin/Plugin
[email protected] Mon, 27 Jul 2026 07:20:20 -0000
| Newsgroups | gmane.mail.spam.spamassassin.cvs |
|---|---|
| Message-ID | <178513682076.2894552.14818992064045189878@svn03-he-fi> |
Author: gbechis Date: Mon Jul 27 07:20:20 2026 New Revision: 1936613 Log: Replace meta-rule full-rescan retry with a dependency-driven work queue do_meta_tests() restarted its entire foreach over meta_check_ready (or meta_pending when finishing) via \"goto RULE\" every time any meta resolved, re-checking the dependency list of every still-pending meta each time, even ones unaffected by what just resolved. Replace it with an explicit work queue seeded the same way, where resolving a meta pushes only the specific metas listed in its meta_deprules reverse-map (the same map PerMsgStatus::rule_ready() already uses) instead of rescanning everything. Co-Authored-By: Claude Sonnet 5 <[email protected]> initialize queue Submitted by: Giovanni <[email protected]> Github: closes #32 Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Check.pm Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Check.pm ============================================================================== --- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Check.pm Mon Jul 27 06:32:31 2026 (r1936612) +++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Check.pm Mon Jul 27 07:20:20 2026 (r1936613) @@ -298,9 +298,9 @@ sub do_meta_tests { my $mr = $pms->{meta_check_ready}; my $mp = $pms->{meta_pending}; my $md = $pms->{conf}->{meta_dependencies}; + my $mdr = $pms->{conf}->{meta_deprules}; my $mt = $pms->{conf}->{meta_tests}; my $h = $pms->{tests_already_hit}; - my $retry; # When finishing, first mark all unrun non-meta rules as finished, # it will enable the next loop to finish everything properly @@ -314,14 +314,31 @@ sub do_meta_tests { } } -RULE: - foreach my $rulename ($finish ? keys %$mp : keys %$mr) { + # Work queue of metas worth (re)checking, seeded from meta_check_ready + # (or all pending metas when finishing). Running a meta can make other + # metas newly ready (a meta depending on it); rather than rescanning + # every pending/ready meta again on each such change (as a "goto RULE" + # restart would), push only the specific metas that depend on whatever + # just resolved, via the same meta_deprules reverse-dependency map + # PerMsgStatus::rule_ready() uses. + my @queue = $finish ? keys %$mp : keys %$mr; + my %queued; @queued{@queue} = (1) x @queue; + + while (@queue) { + my $rulename = shift @queue; + delete $queued{$rulename}; + next if exists $h->{$rulename}; # already resolved + # Meta is not ready if some dependency has not run yet + my $ready = 1; foreach my $deprule (@{$md->{$rulename}||[]}) { if (!exists $h->{$deprule}) { - next RULE; + $ready = 0; + last; } } + next if !$ready; + # Metasubs look like ($_[1]->{$rulename}||0) ... my $result = $mt->{$rulename}->($pms, $h); if ($result) { @@ -333,11 +350,15 @@ RULE: } delete $mr->{$rulename}; delete $mp->{$rulename}; - # Reiterate all metas again, in case some meta depended on us - $retry = 1; - } - goto RULE if $retry--; + # $rulename just resolved (in %$h); queue only the metas that + # specifically depend on it, instead of every pending/ready meta. + foreach my $deprule (keys %{$mdr->{$rulename} || {}}) { + next if $queued{$deprule}; + push @queue, $deprule; + $queued{$deprule} = 1; + } + } delete $pms->{meta_check_ready}; }