Re: [PREVIEW] Comm::Connection async jobs

From: Amos Jeffries <squid3_at_treenet.co.nz>
Date: Tue, 07 Sep 2010 01:08:16 +1200

On 06/09/10 07:01, Alex Rousskov wrote:
> On 09/05/2010 05:12 AM, Amos Jeffries wrote:
>> To get around some layering violations between client and server side
>> I've found it easier to continue the rollout of Comm::Connection through
>> client-side that to work up a working hack.
>>
>> The attached patch contains only the src/comm/ API pieces for review so
>> we can ensure they are done properly before much more testing and work
>> is done to make use of them.
>>
>>
>> Comm::Connection - data object. stores the FD, local IP+port, remote
>> IP+port, and comm flags relevant to the socket connection.
>>
>> Comm::ConnAcceptor - was ListenStateData, but now converted to AsyncJob.
>> Takes a connection to listen on and emits active Comm::Connection
>> objects for new client connections.
>>
>> Comm::ConnConnector - take a closed template Comm::Connection and make
>> it an active connection.
>
>
> * s/ConnAcceptor::subscribe(call)/ConnAcceptor::callWhenReady(call)/ or
> similar to emphasize that this is not a subscription mechanism but a
> one-time arrangement. However, the subscription suggestion below makes
> this change unnecessary.

Yes, it will die as soon as I can get the subscribe accepting pre-made
AsyncCall objects.

>
> * I understand what you are doing with ConnAcceptor::subscribe() but I
> think we should generalize subscription-friendly callbacks rather than
> dissecting AsyncCall and trying to reconstruct it in ConnAcceptor (and,
> later, in other classes). It is not going to be much more complex than
> what you do now, but it will be reusable.
>
> Specifically, I suggest adding base/Subscription.h with the following
> API declaration (add refcounted Pointer type, and we can add more bells
> and whistles later):
>
>> /// allows to call back the subscriber many times
>> class Subscription: public RefCountable {
>> public:
>> /// returns a call object to be used for the next call back
>> virtual AsyncCall::Pointer callback() const = 0;
>> };
>
> And the following template to create actual subscription objects from
> Dialers.
>
>> /// implements Subscription API using Call's copy constructor
>> template <class Call>
>> class SubscriptionViaCopyT: public Subscription {
>> public:
>> CallSubscriptionT(const Call::Pointer &aCall): call(aCall) {}
>> virtual AsyncCall::Pointer callback() const { return new Call(call); }
>>
>> private:
>> Call::Pointer call; ///< gets copied to create callback calls
>> };
>
> The above will probably need some polishing to get it to work, but the
> idea should be clear.
>
> You will need to disable copying of AsyncCall objects (via the usual
> undefined and private copy constructor trick -- I should have done that
> long time ago) and then add copy constructors to a couple of AsyncCall
> kids that are already used for subscriptions in your patch.
>
> Your ConnAcceptor will have a single
>
> void ConnAcceptor::subscribe(const Subscription::Pointer &aSub)
>
> method used for all subscriptions. ConnAcceptor will use sub->callback()
> to get a call object for the next notification.
>

Nice. Will do.

>
> * You have several Musts in Comm::ConnAcceptor. If any of them throws,
> the job will quit but Squid will keep running. Same for any indirect
> exceptions the acceptor code might trigger. Are you sure no other job or
> module needs to be notified of the fact that there is no acceptor any
> more? Usually, the initiator cares if its initiatee dies...

Hmm, yes. What should we do if squid has a massive failure on a
listening http_port?

For now I'm wrapping the accept() sequence in a try-catch which calls
fatal() if anything throws. Any better ideas welcome.

The initiators using ConnAcceptor in the current 3.HEAD are
http_port_list, http_port_list and FTP. I can see icp_port/htcp_port
being converted to use it the same way as http_port.

FTP used to d its listening a bit strange with several hacks. I'm in
process of simplifying that.

>
> * We cannnot simply dereference raw pointers to jobs because a job may
> quit and free the job object. Consider using AsyncJob::Pointer instead
> and do check that the code does not dereference potentially invalid
> pointers. Any public job member (data or method) is a suspect.
>
> For example, how does Comm::AcceptLimiter::kick() know that
> deferred.shift() does not point to a dead job? A Vector<> of
> ConnAcceptor pointers is one example but there may be others.

Understood. These two have a rather special relationship.
ConnAcceptor registers itself into AcceptLimiter at which point its
isLimited gets incremented, once for every limiting record.

I've added the missing bits for ConnAcceptor::swanSong to safely and
quickly clear any entries it had remaining in the limiter.

>
> * Please make ConnAcceptor::notify() protected if possible.

Noted. Unfortunately there is a bit of abuse still to be cleaned up.

>
> * Consider adding a "const char *reason" parameter to unsubscribe, for
> debugging.
>

Okay I'll consider.

Amos

-- 
Please be using
   Current Stable Squid 2.7.STABLE9 or 3.1.8
   Beta testers wanted for 3.2.0.2
Received on Mon Sep 06 2010 - 13:09:00 MDT

This archive was generated by hypermail 2.2.0 : Mon Sep 06 2010 - 12:00:04 MDT