On 5/10/05, Elliot F <[EMAIL PROTECTED]> wrote:

> It was really more of a practical question, like:  "how should I go about
> writing a non-blocking plugin that communicates with an external resource?"

The simple answer (which you know already) is, "message passing." 
That pops the top off of a can of worms in which you have to select a message
passing abstraction and an
asynchronous abstraction (fork or thread or talk with external
long-lived process
which itself is a thread, or a fork, or might be a server in France)

You must:
   define the communication protocol used in the messages
   become satisfied with the return speed from queueing the message
   associate the point in the process where the message was sent with
   some identifier which will appear in the response
   wait for the responses, perhaps by registering your communication
channels with
      the main socket select 
   when the response comes back, re-enter the plugin somehow

I do not know if high-perf provides, at this point, the framework required to
support non-blocking plugins.  This framework would include

   a "PENDING" response code which could be returned from any plugin,
     along with a coderef to call to see if the response is in, and instructions
     on how to tell when to call the coderef 

I don't recall seeing nonblocking plugins come up on this list previously in
other than theoretical contexts, please correct me if we support them already

perhaps PENDING would have two flavors, "PENDING_POLL" which would
mean that the plug-in is prepared to handle its own communications in a
nonblocking way and should be queued for polling every second or two, and
the trickier but more robust PENDING_SELECT which would return not only
a coderef but a file descriptor number that we check in the main select and
run the coderef when it goes readable.  They could be combined by having
the fdnum be optional -- when provided, the callback is incorporated into
the select loop, when not, the coderef will be polled.

Matt Sergeant says that an async plugin must currently be split into two phases,
http://svn.perl.org/viewcvs/qpsmtpd/trunk/plugins/dnsbl?rev=356 is supposed
to be an example.

To provide the above-described PENDING response code, responses might
need to become "response objects" that can include arguments -- maybe --  anyway
changing them would be easy since they're all centralized to the constants file.

so we'd add PENDING to the contants file as something to export, only instead
of a constant it's

     sub PENDING {
         my ($coderef, $fd) = @_;
         ref($coderef) eq 'CODE' or
             croak "PENDING takes coderef, [fd] as arguments not @_";
         $fd and return [$coderef, $fd];
         return [$coderef]
     }

and pollserver can check responses for being arrayrefs and treat them
as pendings
when that's what comes back.

How to do this with Danga:: sockets I do not know.

And after all these changes are in place to support non-blocking
plugins, will the
performance really increase?

There will be more bookkeeping overhead, meaning less idle CPU, and
response time
on individual messages will improve.  But throughput?  Throughput is
what we care
about, and by having a pool of processes -- the -j switch -- we don't
need to care
if any one of them is blocking or not at any one time.  Tuning becomes
trickier --
I would rewrite the comment that says "set -j to number of CPUs" which
is appropriate
for CPU-bound activity -- like compiling -- but in network-bound
activity, we want
-j to be set much higher --   our simultaneous connections limit
divided by five, or
something like that, to limit the waits for blocking plugins in other
connections handled
by any particular process to a maximum of five times the worst case for a plugin
timeout.

but I'm not talking about the current version of high_perf.

In the case that the external resource will really take a long time
(like more than
fifteen seconds) to respond, a way to write to it might be to send the
query to it
in such a way that a long-lived plugin manager will cache the response when it
comes back, issue a DENYSOFT, then when the retry happens, the response is
cached and available immediately.  Which sucks on at least two counts,
one being that the cache would need to store everything and what if
the state changes,
the other being that delays suck.

I might be in a good enough mood to slap together a selecting smtpd that
takes qpsmtpd plugins and supports a PENDING return code tonight -- or I might
not -- cross your fingers



David Nicol

Reply via email to