You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spamassassin.apache.org by he...@apache.org on 2019/06/09 11:42:11 UTC

svn commit: r1860896 - in /spamassassin: branches/3.4/lib/Mail/SpamAssassin/Conf/Parser.pm trunk/lib/Mail/SpamAssassin/Conf/Parser.pm

Author: hege
Date: Sun Jun  9 11:42:11 2019
New Revision: 1860896

URL: http://svn.apache.org/viewvc?rev=1860896&view=rev
Log:
Bug 7689 - reduce lint time from quadratic to linear

Modified:
    spamassassin/branches/3.4/lib/Mail/SpamAssassin/Conf/Parser.pm
    spamassassin/trunk/lib/Mail/SpamAssassin/Conf/Parser.pm

Modified: spamassassin/branches/3.4/lib/Mail/SpamAssassin/Conf/Parser.pm
URL: http://svn.apache.org/viewvc/spamassassin/branches/3.4/lib/Mail/SpamAssassin/Conf/Parser.pm?rev=1860896&r1=1860895&r2=1860896&view=diff
==============================================================================
--- spamassassin/branches/3.4/lib/Mail/SpamAssassin/Conf/Parser.pm (original)
+++ spamassassin/branches/3.4/lib/Mail/SpamAssassin/Conf/Parser.pm Sun Jun  9 11:42:11 2019
@@ -978,24 +978,29 @@ sub trace_meta_dependencies {
   foreach my $name (keys %{$conf->{tests}}) {
     next unless ($conf->{test_types}->{$name}
                     == $Mail::SpamAssassin::Conf::TYPE_META_TESTS);
-
-    my $deps = [ ];
-    my $alreadydone = { };
-    $self->_meta_deps_recurse($conf, $name, $name, $deps, $alreadydone);
-    $conf->{meta_dependencies}->{$name} = join (' ', @{$deps});
+    my $alreadydone = {};
+    $self->_meta_deps_recurse($conf, $name, $name, $alreadydone);
   }
 }
 
 sub _meta_deps_recurse {
-  my ($self, $conf, $toprule, $name, $deps, $alreadydone) = @_;
+  my ($self, $conf, $toprule, $name, $alreadydone) = @_;
 
-  # Only do each rule once per top-level meta; avoid infinite recursion
-  return if $alreadydone->{$name};
-  $alreadydone->{$name} = 1;
+  # Avoid recomputing the dependencies of a rule
+  return split(' ', $conf->{meta_dependencies}->{$name}) if defined $conf->{meta_dependencies}->{$name};
 
   # Obviously, don't trace empty or nonexistent rules
   my $rule = $conf->{tests}->{$name};
-  return unless $rule;
+  unless ($rule) {
+      $conf->{meta_dependencies}->{$name} = '';
+      return ( );
+  }
+
+  # Avoid infinite recursion
+  return ( ) if exists $alreadydone->{$name};
+  $alreadydone->{$name} = ( );
+
+  my %deps;
 
   # Lex the rule into tokens using a rather simple RE method ...
   my @tokens = ($rule =~ /($ARITH_EXPRESSION_LEXER)/og);
@@ -1010,9 +1015,12 @@ sub _meta_deps_recurse {
     next unless exists $conf_tests->{$token};
 
     # add and recurse
-    push(@{$deps}, untaint_var($token));
-    $self->_meta_deps_recurse($conf, $toprule, $token, $deps, $alreadydone);
+    $deps{untaint_var($token)} = ( );
+    my @subdeps = $self->_meta_deps_recurse($conf, $toprule, $token, $alreadydone);
+    @deps{@subdeps} = ( );
   }
+  $conf->{meta_dependencies}->{$name} = join (' ', keys %deps);
+  return keys %deps;
 }
 
 sub fix_priorities {

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Conf/Parser.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Conf/Parser.pm?rev=1860896&r1=1860895&r2=1860896&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Conf/Parser.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Conf/Parser.pm Sun Jun  9 11:42:11 2019
@@ -972,24 +972,29 @@ sub trace_meta_dependencies {
   foreach my $name (keys %{$conf->{tests}}) {
     next unless ($conf->{test_types}->{$name}
                     == $Mail::SpamAssassin::Conf::TYPE_META_TESTS);
-
-    my $deps = [ ];
-    my $alreadydone = { };
-    $self->_meta_deps_recurse($conf, $name, $name, $deps, $alreadydone);
-    $conf->{meta_dependencies}->{$name} = join (' ', @{$deps});
+    my $alreadydone = {};
+    $self->_meta_deps_recurse($conf, $name, $name, $alreadydone);
   }
 }
 
 sub _meta_deps_recurse {
-  my ($self, $conf, $toprule, $name, $deps, $alreadydone) = @_;
+  my ($self, $conf, $toprule, $name, $alreadydone) = @_;
 
-  # Only do each rule once per top-level meta; avoid infinite recursion
-  return if $alreadydone->{$name};
-  $alreadydone->{$name} = 1;
+  # Avoid recomputing the dependencies of a rule
+  return split(' ', $conf->{meta_dependencies}->{$name}) if defined $conf->{meta_dependencies}->{$name};
 
   # Obviously, don't trace empty or nonexistent rules
   my $rule = $conf->{tests}->{$name};
-  return unless $rule;
+  unless ($rule) {
+      $conf->{meta_dependencies}->{$name} = '';
+      return ( );
+  }
+
+  # Avoid infinite recursion
+  return ( ) if exists $alreadydone->{$name};
+  $alreadydone->{$name} = ( );
+
+  my %deps;
 
   # Lex the rule into tokens using a rather simple RE method ...
   my @tokens = ($rule =~ /($ARITH_EXPRESSION_LEXER)/og);
@@ -1004,9 +1009,12 @@ sub _meta_deps_recurse {
     next unless exists $conf_tests->{$token};
 
     # add and recurse
-    push(@{$deps}, untaint_var($token));
-    $self->_meta_deps_recurse($conf, $toprule, $token, $deps, $alreadydone);
+    $deps{untaint_var($token)} = ( );
+    my @subdeps = $self->_meta_deps_recurse($conf, $toprule, $token, $alreadydone);
+    @deps{@subdeps} = ( );
   }
+  $conf->{meta_dependencies}->{$name} = join (' ', keys %deps);
+  return keys %deps;
 }
 
 sub fix_priorities {