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__