Re: [PATCH] bug 3081: comm layer cleanups for TCP acceptor

2011-01-25 Thread Alex Rousskov
On 01/22/2011 06:46 AM, Amos Jeffries wrote:

 However we cannot drop the CommCbFunPtrCallT and AsyncCallT copy
 constructors. Notice how they explicitly call AsyncCall(a,b,c) instead
 of the AsyncCall copy contructor. Without this we loose the call
 debugs() and the ID creation.

 Adding the assignment operator (undefined) and destructor (no-op) to
 match our big-three requirements.
 
 New version attached. This clears up all the points we have been talking
 about. As well as several duplicate calls to switchTimeoutToData() in FTP.


Thank you for polishing this! I do not see any more problems.


This is minor, but you do not need to use the inline keyword for
methods that are immediately inlined, such as CommCbFunPtrCallT copy
constructor.

Cheers,

Alex.


Re: [PATCH] bug 3081: comm layer cleanups for TCP acceptor

2011-01-25 Thread Amos Jeffries
On Tue, 25 Jan 2011 17:42:03 -0700, Alex Rousskov
rouss...@measurement-factory.com wrote:
 On 01/22/2011 06:46 AM, Amos Jeffries wrote:
 
 However we cannot drop the CommCbFunPtrCallT and AsyncCallT copy
 constructors. Notice how they explicitly call AsyncCall(a,b,c) instead
 of the AsyncCall copy contructor. Without this we loose the call
 debugs() and the ID creation.

 Adding the assignment operator (undefined) and destructor (no-op) to
 match our big-three requirements.
 
 New version attached. This clears up all the points we have been
talking
 about. As well as several duplicate calls to switchTimeoutToData() in
 FTP.
 
 
 Thank you for polishing this! I do not see any more problems.
 
 
 This is minor, but you do not need to use the inline keyword for
 methods that are immediately inlined, such as CommCbFunPtrCallT copy
 constructor.
 
 Cheers,
 
 Alex.

Wonderful. Thank you so much for the time you have been putting into the
audits.

Will fix that inline and commit in a few hours.

Amos


Re: [PATCH] bug 3081: comm layer cleanups for TCP acceptor

2011-01-21 Thread Amos Jeffries

On 20/01/11 11:50, Alex Rousskov wrote:

On 01/17/2011 10:03 PM, Amos Jeffries wrote:

On 18/01/11 10:08, Alex Rousskov wrote:

On 01/14/2011 09:11 PM, Amos Jeffries wrote:

On 10/01/11 14:02, Amos Jeffries wrote:

Attached patch contains the cleanup-comm branch changes to
ListenStateData which make it an AsyncJob (called Comm::TcpAcceptor)
using Subscriptions to generate calls.

This fixes the call re-use problem of bug 3081 and a related FTP data
connection bug.

Alex:
please test that this does not break with SMP support. I've run it with
2 workers on a non-SMP machine, but have not checked for anything more
complex.



Have you had any time to double-check me on this Alex?

I don't want to rely on the silence clause for merging this one.


Sorry I could not review this earlier.



NP: attached updated version against trunk r11159.



+CommAcceptCbPtrFun(const CommAcceptCbPtrFuno);


Are you sure this is needed? It seems like its implementation is what
the default copy constructor does. If there is a reason to add it, you
should add a destructor as well, but I think everything should work
without these additional explicit members.


Since we have AsyncCall blocking the default constructor from allowing
null calls to be passed around we need to add an explicit constructor in
the particular children which subscription requires copying for.



This does not compute for me. A default (parameter-less) constructor,
blocked or not, should not affect copy constructors. Can you rephrase
what you are trying to avoid or achieve? Or perhaps quote the errors you
get when the above explicit copy constructor is removed.



I was thinking AsyncCall(const AsyncCall ); with no definition blocked 
the children default constructors too. Due to the parent not having one 
available to call from the default child constructor.


Doing a test build now to verify. If it passes will drop.




   inline CommCbFunPtrCallT(int debugSection, int debugLevel,
const char *callName, const
DialeraDialer);

+inline CommCbFunPtrCallT(const Pointerp) :


This additions seems wrong on two counts:

a) You should not add a conversion from a pointer to CommCbFunPtrCallT
to CommCbFunPtrCallT itself.

b) You could add an explicit copy constructor, but the default copy
constructor should work for copying CommCbFunPtrCallT objects already,
no?


Without them ... this:

   // setup the subscriptions such that new connections accepted by
listenConn are handled by HTTP
   typedef CommCbFunPtrCallTCommAcceptCbPtrFun  AcceptCall;
   RefCountAcceptCall  subCall = commCbCall(5, 5, httpAccept,
CommAcceptCbPtrFun(httpAccept, s));
   Subscription::Pointer sub = new CallSubscriptionAcceptCall(subCall);


Generates this:

In file included from ../../trunk/src/comm/TcpAcceptor.h:6,
  from ../../trunk/src/client_side.cc:103:
../../trunk/src/base/Subscription.h: In member function
‘RefCountAsyncCall  CallSubscriptionCall_::callback() const [with
Call_ = CommCbFunPtrCallTCommAcceptCbPtrFun]’:
../../trunk/src/client_side.cc:4092:   instantiated from here
../../trunk/src/base/Subscription.h:45: error: no matching function for
call to ‘CommCbFunPtrCallTCommAcceptCbPtrFun::CommCbFunPtrCallT(const
RefCountCommCbFunPtrCallTCommAcceptCbPtrFun  )’
../../trunk/src/CommCalls.h:302: note: candidates are:
CommCbFunPtrCallTDialer::CommCbFunPtrCallT(int, int, const char*,
const Dialer) [with Dialer = CommAcceptCbPtrFun]
../../trunk/src/CommCalls.h:263: note:
CommCbFunPtrCallTCommAcceptCbPtrFun::CommCbFunPtrCallT(const
CommCbFunPtrCallTCommAcceptCbPtrFun)


If I parse this correctly, you are, essentially, passing a pointer-to-X
where reference-to-X is expected. The solution is _not_ to add a
conversion from pointer-to-X to X, but to pass the X object itself.

In your case, X is CommCbFunPtrCallTCommAcceptCbPtrFun.

Note that fixing this may expose other problems.



Hmmm, bug in Subscription then.

=== modified file 'src/base/Subscription.h'
--- src/base/Subscription.h 2010-10-07 07:53:45 + 


+++ src/base/Subscription.h 2011-01-21 14:42:52 +
@@ -42,7 +42,7 @@
 public:
 /// Must be passed an object. nil pointers are not permitted.
 explicit CallSubscription(const RefCountCall_ aCall) : 
call(aCall) { assert(aCall != NULL); }

-virtual AsyncCall::Pointer callback() const { return new Call_(call); }
+virtual AsyncCall::Pointer callback() const { return new 
Call_(call.getRaw()); }


 private:
 const RefCountCall_ call; /// gets copied to create callback calls


Build testing this now. With the two related constructor pointer-to 
changes. Should have a new patch for you tomorrow (mutual time).






+AsyncCall();
+AsyncCall(const AsyncCall);


I could not find the implementation for these two, but I probably just
missed it. I assume the default/generated constructors did not work.
Where do we use these two explicit ones?


We don't. These were what you asked me to add when we 

Re: [PATCH] bug 3081: comm layer cleanups for TCP acceptor

2011-01-21 Thread Alex Rousskov
On 01/21/2011 08:55 AM, Amos Jeffries wrote:
 Hmmm, bug in Subscription then.

 - virtual AsyncCall::Pointer callback() const { return new Call_(call); }
 + virtual AsyncCall::Pointer callback() const { return new 
 Call_(call.getRaw()); }
 
  private:
  const RefCountCall_ call; /// gets copied to create callback calls

Still does not look right. getRaw() returns a pointer to the call. You
do not want to copy a pointer. You want to copy the call itself:

virtual AsyncCall::Pointer callback() const { return new Call_(*call); }


And if Call_(call.getRaw()) actually compiles, there is another bug
somewhere, allowing a pointer-to-AsyncCall conversion to AsyncCall.

HTH,

Alex.


Re: [PATCH] bug 3081: comm layer cleanups for TCP acceptor

2011-01-21 Thread Alex Rousskov
On 01/21/2011 08:55 AM, Amos Jeffries wrote:
 Since we have AsyncCall blocking the default constructor from allowing
 null calls to be passed around we need to add an explicit constructor in
 the particular children which subscription requires copying for.


 This does not compute for me. A default (parameter-less) constructor,
 blocked or not, should not affect copy constructors. Can you rephrase
 what you are trying to avoid or achieve? Or perhaps quote the errors you
 get when the above explicit copy constructor is removed.

 
 I was thinking AsyncCall(const AsyncCall ); with no definition blocked
 the children default constructors too. Due to the parent not having one
 available to call from the default child constructor.

There are several problems here adding to my confusion:

* The lack of method definition (a.k.a. body or implementation) cannot
prevent anything at compile time -- the method definition might be in
some library. The compiler does not know this until it tries to link an
executable. Thus, definition is a red herring here, and you can ignore
it for the purpose of this discussion.

* Terminology:

- Default constructor for class C has no parameters: C().

- Copy constructor for class C has one specific parameter: C(const C).

- Implicit constructor is the one generated by the compiler if the class
declaration does not provide an explicit one. Compiler can generate
implicit default constructor, implicit copy constructor, implicit
assignment operator, and implicit destructor.


* All of these implicit members are always generated if not explicitly
provided, except for the default constructor: An implicit default
constructor is generated only if there are no explicit constructors of
any kind. This makes sense: if we said how to create an object of a
class, the compiler must not provide its own creation method as an
alternative!


* A parent copy constructor cannot block child's default constructor.
The two are totally independent: copying and creation are different things.

* Similarly, a parent default constructor cannot block child's copy
constructor.


HTH,

Alex.


Re: [PATCH] bug 3081: comm layer cleanups for TCP acceptor

2011-01-19 Thread Alex Rousskov
On 01/17/2011 10:03 PM, Amos Jeffries wrote:
 On 18/01/11 10:08, Alex Rousskov wrote:
 On 01/14/2011 09:11 PM, Amos Jeffries wrote:
 On 10/01/11 14:02, Amos Jeffries wrote:
 Attached patch contains the cleanup-comm branch changes to
 ListenStateData which make it an AsyncJob (called Comm::TcpAcceptor)
 using Subscriptions to generate calls.

 This fixes the call re-use problem of bug 3081 and a related FTP data
 connection bug.

 Alex:
 please test that this does not break with SMP support. I've run it with
 2 workers on a non-SMP machine, but have not checked for anything more
 complex.


 Have you had any time to double-check me on this Alex?

 I don't want to rely on the silence clause for merging this one.

 Sorry I could not review this earlier.


 NP: attached updated version against trunk r11159.

 +CommAcceptCbPtrFun(const CommAcceptCbPtrFuno);

 Are you sure this is needed? It seems like its implementation is what
 the default copy constructor does. If there is a reason to add it, you
 should add a destructor as well, but I think everything should work
 without these additional explicit members.
 
 Since we have AsyncCall blocking the default constructor from allowing
 null calls to be passed around we need to add an explicit constructor in
 the particular children which subscription requires copying for.


This does not compute for me. A default (parameter-less) constructor,
blocked or not, should not affect copy constructors. Can you rephrase
what you are trying to avoid or achieve? Or perhaps quote the errors you
get when the above explicit copy constructor is removed.


   inline CommCbFunPtrCallT(int debugSection, int debugLevel,
const char *callName, const
 DialeraDialer);

 +inline CommCbFunPtrCallT(const Pointerp) :

 This additions seems wrong on two counts:

 a) You should not add a conversion from a pointer to CommCbFunPtrCallT
 to CommCbFunPtrCallT itself.

 b) You could add an explicit copy constructor, but the default copy
 constructor should work for copying CommCbFunPtrCallT objects already,
 no?
 
 Without them ... this:
 
   // setup the subscriptions such that new connections accepted by
 listenConn are handled by HTTP
   typedef CommCbFunPtrCallTCommAcceptCbPtrFun AcceptCall;
   RefCountAcceptCall subCall = commCbCall(5, 5, httpAccept,
 CommAcceptCbPtrFun(httpAccept, s));
   Subscription::Pointer sub = new CallSubscriptionAcceptCall(subCall);
 
 
 Generates this:
 
 In file included from ../../trunk/src/comm/TcpAcceptor.h:6,
  from ../../trunk/src/client_side.cc:103:
 ../../trunk/src/base/Subscription.h: In member function
 ‘RefCountAsyncCall CallSubscriptionCall_::callback() const [with
 Call_ = CommCbFunPtrCallTCommAcceptCbPtrFun]’:
 ../../trunk/src/client_side.cc:4092:   instantiated from here
 ../../trunk/src/base/Subscription.h:45: error: no matching function for
 call to ‘CommCbFunPtrCallTCommAcceptCbPtrFun::CommCbFunPtrCallT(const
 RefCountCommCbFunPtrCallTCommAcceptCbPtrFun )’
 ../../trunk/src/CommCalls.h:302: note: candidates are:
 CommCbFunPtrCallTDialer::CommCbFunPtrCallT(int, int, const char*,
 const Dialer) [with Dialer = CommAcceptCbPtrFun]
 ../../trunk/src/CommCalls.h:263: note:
 CommCbFunPtrCallTCommAcceptCbPtrFun::CommCbFunPtrCallT(const
 CommCbFunPtrCallTCommAcceptCbPtrFun)

If I parse this correctly, you are, essentially, passing a pointer-to-X
where reference-to-X is expected. The solution is _not_ to add a
conversion from pointer-to-X to X, but to pass the X object itself.

In your case, X is CommCbFunPtrCallTCommAcceptCbPtrFun.

Note that fixing this may expose other problems.



 +AsyncCall();
 +AsyncCall(const AsyncCall);

 I could not find the implementation for these two, but I probably just
 missed it. I assume the default/generated constructors did not work.
 Where do we use these two explicit ones?
 
 We don't. These were what you asked me to add when we were creating
 Subscription, to prevent default constructors being (ab)used on any old
 call. This non-definition enforces the AsyncCall and children are not
 copied around and double-scheduled.


Ah, please move these two declarations to the private: section and add
a comment saying that they are not implemented to prevent nil calls from
being passed around and unknowingly scheduled, for now.


 +AsyncCallT(const RefCountAsyncCallTDialero):
 +AsyncCall(o-debugSection, o-debugLevel, o-name),
 +dialer(o-dialer) {}
 +

 Similar to the earlier comments, it seems wrong to provide a
 pointer-to-T to T conversion, especially an implicit one where the
 default copy constructor should work fine.
 
 Parallel of CommCbFunPtrCallT(const Pointerp). This is required for the
 matching case in FTP which uses AsyncCallT for a generic Uniary member
 callback.

Same comment. A different solution is needed here unless I am missing
something. We should not add pointer-to-T to T conversions.


   if (flag != COMM_OK) 

Re: [PATCH] bug 3081: comm layer cleanups for TCP acceptor

2011-01-17 Thread Alex Rousskov
On 01/14/2011 09:11 PM, Amos Jeffries wrote:
 On 10/01/11 14:02, Amos Jeffries wrote:
 Attached patch contains the cleanup-comm branch changes to
 ListenStateData which make it an AsyncJob (called Comm::TcpAcceptor)
 using Subscriptions to generate calls.

 This fixes the call re-use problem of bug 3081 and a related FTP data
 connection bug.

 Alex:
 please test that this does not break with SMP support. I've run it with
 2 workers on a non-SMP machine, but have not checked for anything more
 complex.

 
 Have you had any time to double-check me on this Alex?
 
 I don't want to rely on the silence clause for merging this one.

Sorry I could not review this earlier.


 NP: attached updated version against trunk r11159.

 +CommAcceptCbPtrFun(const CommAcceptCbPtrFun o);

Are you sure this is needed? It seems like its implementation is what
the default copy constructor does. If there is a reason to add it, you
should add a destructor as well, but I think everything should work
without these additional explicit members.


  inline CommCbFunPtrCallT(int debugSection, int debugLevel,
   const char *callName, const Dialer aDialer);
  
 +inline CommCbFunPtrCallT(const Pointer p) :

This additions seems wrong on two counts:

a) You should not add a conversion from a pointer to CommCbFunPtrCallT
to CommCbFunPtrCallT itself.

b) You could add an explicit copy constructor, but the default copy
constructor should work for copying CommCbFunPtrCallT objects already, no?

 +AsyncCall();
 +AsyncCall(const AsyncCall );

I could not find the implementation for these two, but I probably just
missed it. I assume the default/generated constructors did not work.
Where do we use these two explicit ones?


 +AsyncCallT(const RefCountAsyncCallTDialer  o):
 +AsyncCall(o-debugSection, o-debugLevel, o-name),
 +dialer(o-dialer) {}
 +

Similar to the earlier comments, it seems wrong to provide a
pointer-to-T to T conversion, especially an implicit one where the
default copy constructor should work fine.

  if (flag != COMM_OK) {
 -debugs(33, 1, httpAccept: FD   sock  : accept failure:   
 xstrerr(xerrno));
 +// This should not occur with TcpAcceptor.
 +// However its possible the call was still queued when the client 
 disconnected
 +debugs(33, 1, httpAccept: FD   s-listenFd  : accept failure: 
   xstrerr(xerrno));

This new comment confuses me. Is it possible or not? Sounds like it is
possible and is not a bug. Why complain at level 1 then? Overall,
httpAccept() and httpsAccept() changes seem either unnecessary or out of
the patch scope.


 +debugs(5, 5, HERE  FD   fd  ,   local_addr   AsyncCall 
 Subscription:   aSub);

Consider moving the part after HERE to TcpAcceptor::status() method so
that you do not have to repeat it. It will be used whenever the acceptor
is called asynchronously (and you can add explicit debugs calls too, of
course).

 +} catch(const TextException e) {
 +fatalf(FATAL: error while accepting new client connection: %s\n, 
 e.message);

It is better to catch std::expression and print its message using
e.what(). This way, you will catch and report details of both standard
exceptions and our TextExceptions because TextException is a child of
std::exception.

 +comm_err_t status = oldAccept(newConnDetails);

Avoid status because AsyncJob has a virtual method called status().
Consider err or result.

Make it const unless we do change it.


 +/// temporary holder for newely accepted client FD
 +int newFd_;
...
 +// drop the temporary recent accepted socket FD details.
 +// this prevents information crossover on calls.
 +newFd_ = -1;

Why not keep it as a local variable and pass it to notify(), like the
old code did? That feels like a simpler/safer approach to me than
storing this temporary information in a data member.


 +/** Subscribe a handler to receive calls back about new connections.
 + * Replaces any existing subscribed handler.
 + */
 +void subscribe(const Subscription::Pointer aSub);

Consider s/Replaces/Unsubscribes/ to indirectly document that pending
calls remain scheduled.


 + * Pending calls will remain scheduled.

Consider Already scheduled callbacks remain scheduled.

 +private:
 +friend class AcceptLimiter;

This looks weird because friends cannot access private members. They can
only access protected ones and you do not have any protected members.
Either this friendship is not needed at all or you can move some public
members to become protected.


 +Comm::TcpAcceptor *tmp = new Comm::TcpAcceptor(fd, data.local, 
 data.flags, note, sub);
 +
 +// Ensure we have a copy of the FD opened for listening and a close 
 handler on it.
 +assert(data.fd == -1 || data.fd == tmp-fd);
 +data.fd = -1;
 +data.opened(tmp-fd, dataCloser());
 +
 +AsyncJob::Start(tmp);

This sequence is leak-prone. Either check everything