OK, I've tracked down why sometimes the logging plugin is being loaded twice and I'm not sure of the best way to restrucure things to prevent it.

Here are the facts:

1) The top level object which is shared in forkserver (and a singleton in normal mode) is of type Qpsmtpd. It contains connections and transactions. This is the object that has all of the plugins attached to it, and the logging plugins are loaded once only here.

2) The transaction object is created for each SMTP transaction and contains only the elements of the current transaction and does not contain any information about the connection which contains it, nor the global object that has the plugins cached.

3) If you call $transaction->log(), a second copy of the logging plugins get loaded (and this triggers the redefined warning) and there isn't any way to prevent that (since the Transaction object doesn't know about its parents).

4) $transaction->{_size_threshold} is the entry that determines whether to store the DATA lines in memory or on disk. It is strictly a Transaction property, but calling $transaction->config('memory_threshold') means that the Transaction object now needs to grow a logging plugin, which causes the redefined warnings and a second copy of the logging plugin to be loaded.

So there seem to be a couple of ways to approach this:

1) Add either a $transaction->{_connection} or $transaction->{_qp} element, so that the transaction can crawl back up to it's containing objects to log using the cached logging plugin.

2) Create a global logging object that everything can use (instead of binding the logging to the top level object).

3) Create a global size_threshold variable (much like the way that the spool_dir is a global scalar) and just copy that into every new $transaction object in reset_transaction.

I've played around with #3, but it seems like violating the object structure (plus it winds up being called before the logging gets loaded completely). The *only* time that the Transaction object needs to call config() is to get the size_threshold, so this still might not be a bad solution.

A possible patch for method #3 is attached.

Comments?

John
=== lib/Qpsmtpd/SMTP.pm
==================================================================
--- lib/Qpsmtpd/SMTP.pm  (revision 591)
+++ lib/Qpsmtpd/SMTP.pm  (local)
@@ -118,7 +118,9 @@
 sub reset_transaction {
   my $self = shift;
   $self->run_hooks("reset_transaction") if $self->{_transaction};
-  return $self->{_transaction} = Qpsmtpd::Transaction->new();
+  $self->{_transaction} = Qpsmtpd::Transaction->new();
+  $self->{_transaction}->{_size_threshold} = $self->size_threshold();
+  return $self->{_transaction};
 }


=== lib/Qpsmtpd/TcpServer.pm
==================================================================
--- lib/Qpsmtpd/TcpServer.pm  (revision 591)
+++ lib/Qpsmtpd/TcpServer.pm  (local)
@@ -39,7 +39,7 @@
     my $self = shift;

     # should be somewhere in Qpsmtpd.pm and not here...
-    $self->load_plugins;
+    $self->load_plugins unless $self->{hooks};

     my $rc = $self->start_conversation;
     return if $rc != DONE;
=== lib/Qpsmtpd/Transaction.pm
==================================================================
--- lib/Qpsmtpd/Transaction.pm  (revision 591)
+++ lib/Qpsmtpd/Transaction.pm  (local)
@@ -15,9 +15,6 @@
   my %args = @_;
   my $self = { _rcpt => [], started => time };
   bless ($self, $class);
-  my $sz = $self->config('memory_threshold');
-  $sz = 10_000 unless defined($sz);
-  $self->{_size_threshold} = $sz;
   return $self;
 }

=== lib/Qpsmtpd.pm
==================================================================
--- lib/Qpsmtpd.pm  (revision 591)
+++ lib/Qpsmtpd.pm  (local)
@@ -1,6 +1,6 @@
 package Qpsmtpd;
 use strict;
-use vars qw($VERSION $Logger $TraceLevel $Spool_dir);
+use vars qw($VERSION $Logger $TraceLevel $Spool_dir $Size_threshold);

 use Sys::Hostname;
 use Qpsmtpd::Constants;
@@ -179,7 +179,7 @@
   $self->log(LOGNOTICE, "loading plugins from $dir");

   @plugins = $self->_load_plugins($dir, @plugins);
-
+
   return @plugins;
 }

@@ -367,6 +367,16 @@
   return $dirname;
 }

+sub size_threshold {
+  my $self = shift;
+  unless ( $Size_threshold ) {
+      $DB::single = 1;
+      my $sz = $self->config('memory_threshold');
+      $Size_threshold = 10_000 unless defined($sz);
+  }
+  return $Size_threshold;
+}
+
 1;

 __END__

Reply via email to