You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spamassassin.apache.org by mm...@apache.org on 2007/08/27 15:59:34 UTC

svn commit: r570127 - /spamassassin/trunk/lib/Mail/SpamAssassin/AsyncLoop.pm

Author: mmartinec
Date: Mon Aug 27 06:59:33 2007
New Revision: 570127

URL: http://svn.apache.org/viewvc?rev=570127&view=rev
Log:
Shave off up to 1 second of wait time during the final call of
complete_lookups() from harvest_dnsbl_queries(), if all queries
have expired by the current time + 1 second.  Explanation:
harvest_dnsbl_queries polls in full 1 second intervals.  Even if
all queries expire at some time during the last 1 s interval,
the 'select' would still wait for the full 1 second period.
Now the last 1 s wait interval is reduced to only cover up to
the latest query expiration time. This optimization is made
possible by the subsecond timing.



Modified:
    spamassassin/trunk/lib/Mail/SpamAssassin/AsyncLoop.pm

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/AsyncLoop.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/AsyncLoop.pm?rev=570127&r1=570126&r2=570127&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/AsyncLoop.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/AsyncLoop.pm Mon Aug 27 06:59:33 2007
@@ -223,19 +223,50 @@
   $self->{queries_started} = 0;
   $self->{queries_completed} = 0;
 
+  my $now = time;
+
+  if (defined $timeout && $timeout > 0 &&
+      %$pending && $self->{total_queries_started} > 0)
+  {
+    # shrink 'select' timeout if a caller specified unnecessarily long
+    # value, beyond the latest deadline of any outstanding request;
+    # can save needless wait time (up to 1 second in harvest_dnsbl_queries)
+    my $timeout_shrink_factor =
+           1 - 0.7 * ( ($self->{total_queries_completed} /
+                        $self->{total_queries_started}) ** 2 );
+    my $max_deadline;
+    while (my($key,$ent) = each %$pending) {
+      my $dt = $ent->{timeout};
+      if ($dt > 1.0) {  # only allow shrinking of timeouts over 1 second
+        $dt *= $timeout_shrink_factor;
+        $dt = 1.0  if $dt < 1.0;  # don't shrink below 1 second
+      }
+      my $deadline = $ent->{start_time} + $dt;
+      if (!defined $max_deadline || $deadline > $max_deadline) {
+        $max_deadline = $deadline;
+      }
+    }
+    my $sufficient_timeout = $max_deadline - $now;
+    $sufficient_timeout = 0  if $sufficient_timeout < 0;
+    if (defined $max_deadline && $timeout > $sufficient_timeout) {
+      dbg("async: reducing select timeout from %.1f to %.1f s",
+          $timeout, $sufficient_timeout);
+      $timeout = $sufficient_timeout;
+    }
+  }
+
   # trap this loop in an eval { } block, as Net::DNS could throw
   # die()s our way; in particular, process_dnsbl_results() has
   # thrown die()s before (bug 3794).
   eval {
-    my $now = time;
 
-    if (%$pending) {  # anything to do?
-      # dbg("async: before select, timeout=%.1f", $timeout)  if $timeout > 0;
+    if (%$pending) {  # any outstanding requests still?
       $self->{last_poll_responses_time} = $now;
-      my $nfound;
-      $nfound = $self->{main}->{resolver}->poll_responses($timeout);
-      dbg("async: select found %s responses ready", !$nfound ? 'no' : $nfound);
+      my $nfound = $self->{main}->{resolver}->poll_responses($timeout);
+      dbg("async: select found %s responses ready (t.o.=%.1f)",
+          !$nfound ? 'no' : $nfound,  $timeout);
     }
+    $now = time;  # capture new timestamp, after possible sleep in 'select'
 
     while (my($key,$ent) = each %$pending) {
       my $id = $ent->{id};
@@ -249,16 +280,15 @@
         $ent->{finish_time} = $now  if !defined $ent->{finish_time};
         $ent->{response_packet} = delete $self->{finished}->{$id};
 
-        dbg("async: query completed in %.3f s: %s",
-            $ent->{finish_time} - $ent->{start_time}, $ent->{display_id});
+        my $elapsed = $ent->{finish_time} - $ent->{start_time};
+        dbg("async: completed in %.3f s: %s", $elapsed, $ent->{display_id});
+        $self->{timing_by_query}->{". $key"} += $elapsed;
 
         if (defined $ent->{completed_callback}) {
           $ent->{completed_callback}->($ent);
         }
         $self->{queries_completed}++;
         $self->{total_queries_completed}++;
-        $self->{timing_by_query}->{". $key"} +=
-          $ent->{finish_time} - $ent->{start_time};
         delete $pending->{$key};
       }
     }
@@ -273,8 +303,11 @@
 
       while (my($key,$ent) = each %$pending) {
         $typecount{$ent->{type}}++;
-        my $dt = $ent->{timeout} * $timeout_shrink_factor;
-        $dt = 1.0  if $dt < 1.0;  # don't shrink allowed time below 1 second
+        my $dt = $ent->{timeout};
+        if ($dt > 1.0) {  # only allow shrinking of timeouts over 1 second
+          $dt *= $timeout_shrink_factor;
+          $dt = 1.0  if $dt < 1.0;  # don't shrink below 1 second
+        }
         $allexpired = 0  if $now <= $ent->{start_time} + $dt;
       }
       dbg("async: queries completed: %d, started: %d",
@@ -326,7 +359,7 @@
     dbg("async: aborting after %.3f s, %s: %s",
         $now - $ent->{start_time},
         defined $ent->{timeout} && $now > $ent->{start_time} + $ent->{timeout}
-          ? 'past original deadline' : 'shrunk deadline',
+          ? 'past original deadline' : 'deadline shrunk',
         $ent->{display_id} );
     $foundcnt++;
     $self->{timing_by_query}->{"X $key"} = $now - $ent->{start_time};