Re: Sbuf review at r9331

2009-02-24 Thread Kinkie
 - check that the function names in debugs() statements match their
 actual name (there's been quite a lot of shuffling)

 Please use debugs(..., HERE  blah) for that sort of thing at levels 1.
 I've also just added MYNAME for prettier but identical use on the top two
 levels.

Now done.

-- 
/kinkie


Re: Sbuf review at r9331

2009-02-23 Thread Kinkie
Further improvements:

 * SBufStore(const SBuf S);

 SBufStore must not know about SBuf.

Done. It's now a first-class citizen, without any SBuf knowledge. In
the process I've removed some methods and migrated others to
char*-based.

 * Why is Sbuf MemPooled?! We are not supposed to allocate SBuf dynamically,
 right? Did you mean to pool SbufStore instead?

You're right. SBufStore and its smaller storage sizes should be pooled.

 * If you have introduced size_type, use it. Do not use size_t instead except
 for size_type typedef.

Ok. Used it everywhere.

 * I doubt clear() should free the storage by default. Usually, we clear to
 fill again. You even do that yourself in SBuf::assign(). Deallocating and
 allocating  would cost more than doing nothing. Let's not deallocate by
 default, for now.

I've commented the line releasing the storage. Worst-case, it will
just realloc lazily which is still ok.

 * remove dumpStats. Just give access to Stats object(s) that can dump.
Done. Now both SBuf and SBufStore have const getters instead.

 * Why is cow() public?

Now private, as discussed.

 And check other members for naming style. Use trailing underscores and
 mixedCase consistently, everywhere.
Done. I hope I didn't miss anything, will recheck.

 * Check that assignment operator sets everything. I think nreallocs was
 forgotten.
It was intentional as discussed, but I've now added also that to the
assignment operation.
It's an optimization anyways so its usefulness is debatable until we
get some hard numbers..

 * I do not understand why you cannot keep the experted message without
 duplicating it in the code below. Can you explain, please?

   msg=b.exportCopy();
   message=xstrdup(msg); //double-copy to avoid mismatching malloc and new
   delete msg;

Fixed. Even though I'll admit I don't like the innards of xstrndup
much so I had to basically reimplement it in client-code (there's a
strlen() too much in xstrndup).

 * No need to check for NULL before delete in
   if (mem != NULL) {
   delete mem; //might have been freed by unref
   mem=NULL;
   }

Done. Now it only performs a (then-unimplemented) isLiteral check.

 You are duplicating the code in the common case.

 * Declare when needed, for example inside for():
   size_type j;
   for (j=0;jlen_;j++) {

Do you mean that this should read
for (size_type j=0;jlen_;++j)
?

 * I think you should merge realloc and preAlloc. I believe there are already
 calls to realloc() where you should have used preAlloc().

Done. The merged call is now called grow().

 * Your append(std::string) reverses the arguments of
 std::string::append(string), which many developers would find extremely
 confusing, especially since those arguments have defaults. Please fix.
 Please double check other standard methods for similar problems.

I have now reduced the number of (constructor/assign/append) functions
by one by grouping the char*-based ones and using default arguments.
The whole thing now looks much more polished and consistent.

Next steps, mempooling SBufStore and its backing storage.


-- 
/kinkie


Re: Sbuf review at r9331

2009-02-23 Thread Alex Rousskov
On 02/23/2009 10:52 AM, Kinkie wrote:

 * Declare when needed, for example inside for():
   size_type j;
   for (j=0;jlen_;j++) {
 
 Do you mean that this should read
 for (size_type j=0;jlen_;++j)
 ?

Yes, I do. IIRC, there are many other examples where variables are
declared too early. This is a minor flaw, with no real effect in most
cases, but it is a good habit to develop and becomes important when you
deal with non-integral variables.

 Next steps, mempooling SBufStore and its backing storage.

MemPooling is needed but does not affect the design or most of the
implementation code. There is no serious rush to implement this, IMO.

It looks like all the big items in the previews review are closed. Do
you want me to do another review soon or should I wait for some other
milestone/event?


Thank you,

Alex.


Re: Sbuf review at r9331

2009-02-23 Thread Kinkie
On Mon, Feb 23, 2009 at 11:58 PM, Alex Rousskov
rouss...@measurement-factory.com wrote:
 On 02/23/2009 10:52 AM, Kinkie wrote:

 * Declare when needed, for example inside for():
   size_type j;
   for (j=0;jlen_;j++) {

 Do you mean that this should read
 for (size_type j=0;jlen_;++j)
 ?

 Yes, I do. IIRC, there are many other examples where variables are
 declared too early. This is a minor flaw, with no real effect in most
 cases, but it is a good habit to develop and becomes important when you
 deal with non-integral variables.

 Next steps, mempooling SBufStore and its backing storage.

 MemPooling is needed but does not affect the design or most of the
 implementation code. There is no serious rush to implement this, IMO.

Already done in rev 9366. Had to add a second bool flag to MemBlob,
but that's fine.

 It looks like all the big items in the previews review are closed. Do
 you want me to do another review soon or should I wait for some other
 milestone/event?

Any time you want and have the time to spare, I leave it to your judgement.
There's some pending cleanup: the current TODO list on top of my head is:
- rename SBufStore to MemBlob and give it its new home
- rename SBuf to Buffer (I don't remember if we had agreed on a
different name, there were quite a few that flew around) and rename
files accordingly
- rename testSBuf files and classes.
- check that the function names in debugs() statements match their
actual name (there's been quite a lot of shuffling)
- define a few more MemPool String sizes and match them with those in
estimateCapacity
- maybe shuffle function implementations around SBuf.cc(i) to match
their definition order in SBuf.h

Thanks,
-- 
/kinkie


Re: Sbuf review at r9331

2009-02-23 Thread Amos Jeffries
 On Mon, Feb 23, 2009 at 11:58 PM, Alex Rousskov
 rouss...@measurement-factory.com wrote:
 On 02/23/2009 10:52 AM, Kinkie wrote:

 * Declare when needed, for example inside for():
 Â  size_type j;
 Â  for (j=0;jlen_;j++) {

 Do you mean that this should read
 for (size_type j=0;jlen_;++j)
 ?

 Yes, I do. IIRC, there are many other examples where variables are
 declared too early. This is a minor flaw, with no real effect in most
 cases, but it is a good habit to develop and becomes important when you
 deal with non-integral variables.

 Next steps, mempooling SBufStore and its backing storage.

 MemPooling is needed but does not affect the design or most of the
 implementation code. There is no serious rush to implement this, IMO.

 Already done in rev 9366. Had to add a second bool flag to MemBlob,
 but that's fine.

 It looks like all the big items in the previews review are closed. Do
 you want me to do another review soon or should I wait for some other
 milestone/event?

 Any time you want and have the time to spare, I leave it to your
 judgement.
 There's some pending cleanup: the current TODO list on top of my head is:
 - rename SBufStore to MemBlob and give it its new home
 - rename SBuf to Buffer (I don't remember if we had agreed on a
 different name, there were quite a few that flew around) and rename
 files accordingly
 - rename testSBuf files and classes.
 - check that the function names in debugs() statements match their
 actual name (there's been quite a lot of shuffling)

Please use debugs(..., HERE  blah) for that sort of thing at levels 1.
I've also just added MYNAME for prettier but identical use on the top two
levels.

They can save a lot of tracing confusion.

 - define a few more MemPool String sizes and match them with those in
 estimateCapacity
 - maybe shuffle function implementations around SBuf.cc(i) to match
 their definition order in SBuf.h


Amos



Re: Sbuf review at r9331

2009-02-20 Thread Kinkie
On Fri, Feb 20, 2009 at 5:56 PM, Alex Rousskov
rouss...@measurement-factory.com wrote:
 On 02/20/2009 05:16 AM, Kinkie wrote:
 On Sun, Feb 1, 2009 at 9:08 PM, Alex Rousskov
 rouss...@measurement-factory.com wrote:
   Here are a few Buffer comments based on r9331 of lp:~kinkie/squid/stringng

 Executive summary: Many problems fixed, thank you. We are making
 progress. Three known big issues remain:

 1) SBufStore should be a stand-alone class (see the first two related
 bullets below).

 2) Confusion regarding pooling of SBuf objects is suspected (discussed
 in a few bullets below).

Given your explanation it is now a certainty.
On the other hand, SBufStore objects would probably benefit from it,
wouldn't they?

 3) Lack of detailed low-level review -- waiting for the resolution of
 the above issues.

 If you really hate doing changes related to (1) and (2), I can take over
 once the other fixes are implemented. I am not excited about fixing
 this, but I would rather do extra work than see you depressed. If this
 happens, you can still be responsible for testing, integrating, and
 polishing the result, but you might be happier finding my bugs than
 listening to my complaints about yours :-)

Now this is what I call a positive attitude! ;-)
Seriously: the code looks in a much better shape now than it did.
Thanks for prodding me.

 Details below.

 * Move SbufStore outside of SBuf. You are not buying any extra security or
 protection by embedding it, but making the code more complex and less
 reusable.

 This can be addressed in three ways that I can think of:
 1- leaving as-is
 2- bringing that out, with private constructors and friendship to
 select who can instantiate what.
 3- bringing that out with big red signs in the class declaration not
 to (ab)use it.

 would 2. be acceptable to you?

 4. Bring it out as a regular class.

 There is no good reason to try to hide the store class or try to make
 its use by others more difficult. Make the class reusable instead of
 making it ugly and prohibiting its reuse. You are not making SBuf any
 better by keeping SBufStore inside either. You are making it worse! Just
 treat SBufStore as a regular class, with a specific purpose -- providing
 refcountable and growable continues memory storage.

You have convinced me.
I just ask you for the future, whenever you have objections about
something I design, please show me a code mock-up. My resistance to
change is almost often motivated by me not seeing a different way to
do things. OTOH, I think I have demonstrated a reasonable willingness
to change my mind.

 Whether there will be other users for SBufStore is unknown and
 unimportant for now.

 We should probably call the storage class MemBlob to emphasize its
 purpose and disassociate it from one specific user (SBuf).

Sure, no problem.

 BTW, I am not sure the current set of SBufStore methods is correct. I
 have a feeling the store is much smarter than it should be, duplicating
 some of the SBuf functionality. Such problems are typical when two
 classes are too tightly coupled -- they tend to lose their clear
 identity and purpose. I will revisit this later, after MemBlob is isolated.

It is smarter than needed, mostly for convenience. And yes, they are
tightly coupled.. MemBlob is a glorified struct, meant to serve the
Buffer...

 * SBufStore(const SBuf S);

 SBufStore must not know about SBuf.

 It knowing about SBuf is a serious design help wrt SBuf::consume()
 If it didn't, we'd have to take a trip through char*.
 If it can't be accepted, I'll do so, but if it's possible at all I'd
 like to keep it.

 Just like with store issue above, I fundamentally disagree here. The
 only information stored in SBuf and not in SBufStore is offset and
 length. You can pass that information to the constructor and other
 members, as needed.

Ok.

 Whether trips through char* are a bad thing in this context is
 debatable, BTW. You can pass SBufStore instead of char* but you would
 still need very similar methods where raw char* is passed. I am fine
 with two copies of methods, one char*-based and one SBufStore-based, but
 I would not be surprised if keeping it simple with just char* would be a
 better solution overall.

Simplest way to know is to just try it. It's not something that can't
be done in one or two hours probably.

* \throw TextException always

 I've tried to be more specific, all more-specific exceptions inherit
 from TextException.
 I'd like to understand what's the benefit in having only one exception kind.

 I do not think the above bullet was my review comment. I think it was a
 part of your source code, copy-pasted to provide context for the How
 about simply not implementing the not-to-be-used methods? comment.

Ok.

 I do not object to specific exceptions.

 * Why is Sbuf MemPooled?! We are not supposed to allocate SBuf dynamically,
 right? Did you mean to pool SbufStore instead?

 SBuf is a fixed-size object. MemPooling avoids heap fragmentation, doesn't 
 

Sbuf review at r9331

2009-02-01 Thread Alex Rousskov

Hi Kinkie,

   Here are a few Buffer comments based on r9331 of 
lp:~kinkie/squid/stringng
The review is incomplete as there is too much in the way to do a full 
high-level and low-level review.  Some of the comments below will help 
to clean up the way for a full review. The common theme is:


- Simplify to the bare minimum. We will optimize and add bells and 
whistles later.

- Mimic standard interfaces and double check that you mimic them correctly.

Specific comments:

* Sbuf.h does not use *Exception classes. Most Buffer users would not 
use them either. Move them and their prerequisites to 
SbufExceptions.{cc,h} or something like that. As you know, I doubt most 
of those exception classes are really needed/useful.


* class SBufStats {
   friend class SBuf;
   protected:

Make members public, remove friendship.


* Remove all *Stats::get() methods. C++ classes have copy constructors.


* The following comment about registration is a lie.
SBufStats(); ///constructor. Also registers with CacheManager

Note that it would probably be a bad idea to register with CacheManager 
from the default constructor.


* Either all *Stats classes should have a constructor that initializes 
its members or none.


* Move SbufStore outside of SBuf. You are not buying any extra security 
or protection by embedding it, but making the code more complex and less 
reusable.


* s/memalloc/memAlloc/  s/memblock/memBlock/ etc.

No need to add a third (fourth?) naming scheme. It is bad enough that we 
have to mix size_type and canGrow styles.



* SBufStore(const SBuf S);

SBufStore must not know about SBuf.

* SBufStore copy constructor and assignment operator are still not 
declared correctly. Please please please review your code for const 
correctness, once and for all.


* How about simply not implementing the not-to-be-used methods?
* copy-contstructor. Not to be used.
* \throw TextException always

If there is no implementation, the compiler and not the end-user will 
complain if the method is actually used.



* Why is Sbuf MemPooled?! We are not supposed to allocate SBuf 
dynamically, right? Did you mean to pool SbufStore instead?


* isNull is still public

* If you have introduced size_type, use it. Do not use size_t instead 
except for size_type typedef.


* I doubt clear() should free the storage by default. Usually, we clear 
to fill again. You even do that yourself in SBuf::assign(). Deallocating 
and allocating  would cost more than doing nothing. Let's not deallocate 
by default, for now.


* Once again, please remove all exception specifications (I think you 
have only empty throw()s left). For rationale, see my earlier reviews or 
Item 13 A pragmatic look at exception specifications in Sutter's 
Exceptional C++ Style. Most if it should also be available at 
http://www.gotw.ca/publications/mill22.htm


* See my earlier StringNg comments regarding truncateSelf, chopSelf, 
import*, export*, substrSelf, and headUntil* naming and existence. Trim 
them down to basics, use standard names, and remove Self.


* remove dumpStats. Just give access to Stats object(s) that can dump.

* Why is cow() public?

* s/preAlloc/reserve/

* s/memhandle/store_/
And check other members for naming style. Use trailing underscores and 
mixedCase consistently, everywhere.


* s/alloc_strategy/calcCapacity/ or similar. The method does not 
allocate, change, or return any strategy.


* Initialize Sbuf members in the constructor consistently. For example, 
nreallocs is  _sometimes_ initialized inside the constructor body. If 
there are no performance concerns, initialize before the body and set 
later if needed.


* Check that assignment operator sets everything. I think nreallocs was 
forgotten.


* Parameter should be a const reference:
SBuf SBuf::append(const SBuf S)

* There are too many similar-but-different append() implementations. 
Can't you have one or two and have others call it with the right parameters?


* The following affects operator semantics and, hence, should be illegal 
based on our last agreement regarding isNull:


   if (isNull() || S.isNull()) {
   debugs(SBUF_DEBUGSECTION,9,\tone null);
   stats.qget++;
   return false;
   }

Not to mention that it feels wrong because it is asymmetric.

* Please change your substr() semantics (as implemented) to match that 
of std::string when from is too big.


* I do not understand why you cannot keep the experted message without 
duplicating it in the code below. Can you explain, please?


   msg=b.exportCopy();
   message=xstrdup(msg); //double-copy to avoid mismatching malloc and new
   delete msg;

* No need to check for NULL before delete in
   if (mem != NULL) {
   delete mem; //might have been freed by unref
   mem=NULL;
   }

You are duplicating the code in the common case.

* Declare when needed, for example inside for():
   size_type j;
   for (j=0;jlen_;j++) {

* I think you should merge realloc and preAlloc. I believe there are 
already