On 09/26/2011 02:17 PM, Kinkie wrote:

>   12 days have passed, no further discussion. Does that mean Ok to merge?

I may have found a bug in the latest patch. Sent a review separately. I
think it answers your question below. Sorry it took so long.


Cheers,

Alex.



> In the meantime I've implemented full getters/setters for all valued
> headers, with explicitly defined "unset" values.
> Using bools to implement the other flags would probably be
> counterproductive as it'd baloon the code size even more.
> 
> Two open points:
> - As I've mentioned, I've implemented a small const char*/lenght class
> to use as key in a map. Should it be extracted to be used also
> elsewhere? Any candidates for a name?
> - cleaning up the for-review changes.
> 
> Thanks for any comments.
> 
> 
> On Wed, Sep 14, 2011 at 8:30 PM, Kinkie <gkin...@gmail.com> wrote:
>> On Tue, Sep 13, 2011 at 6:11 PM, Alex Rousskov
>> <rouss...@measurement-factory.com> wrote:
>>> On 09/12/2011 05:38 PM, Kinkie wrote:
>>>> Hi,
>>>>   the attached bundle refactors the HttpHdrCc into a c++ class,
>>>> attempting also to clean the code up. Main changes:
>>>> - 6 less global functions in protos.h
>>>> - 1 less struct in structs.h
>>>> - proper c++ construction/destruction semantics, standard MemPool 
>>>> integration
>>>
>>>> - name->id header parsing now done via std::map instead of iterating
>>>> over list: complexity should go from O(n) to O(log n) with STL-derived
>>>> libs.
>>>
>>> On the other hand, you now deallocate and allocate a new SquidString for
>>> every CC directive just to find that directive ID so the total cost may
>>> be not be lower. I think we can do much better, and even if we cannot or
>>> will not, I do not think we should commit the "optimization" part of
>>> this change until proper performance regression testing.
>>
>> Point taken. I've implemented a small helper class (basically a const
>> char*+length) to support the lookup in a very cheap way. I'd like to
>> get your feedback on it before trying to extend its use (it's
>> currently an in-cc-file definition).
>>
>>> And if you want to mix optimization with cleanup, here is one place
>>> where you can save quite a few cycles for many messages by not ignoring
>>> the return value of getList():
>>>
>>>>      getList(HDR_CACHE_CONTROL, &s);
>>>>
>>>> -    cc = httpHdrCcParseCreate(&s);
>>>> +    cc=new HttpHdrCc();
>>>> +    if (!cc->parseInit(s)) {
>>>> +        delete cc;
>>>> +        cc = NULL;
>>>> +    }
>>
>> Done.
>>
>>>> +/** Http Cache-control header representation
>>>> + *
>>>> + * Store, parse and output the Cache-control HTTP header.
>>>
>>> In comments, please capitalize HTTP Cache-Control the way RFC 2616 does.
>>
>> Done.
>>
>>
>>>> + * Store, parse and output the Cache-control HTTP header.
>>>
>>> I do not think your HttpHdrCc class deals with the output. On the other
>>> hand, please consider converting httpHdrCcPackInto() and
>>> httpHdrCcUpdateStats() as well.
>>
>> I've so far chosen not to do it as it doesn't look strictly necessary
>> and it increases coupling.
>>
>>>> -HttpHeaderFieldInfo *CcFieldsInfo = NULL;
>>>> +/// Map an header name to its type, to expedite parsing
>>>> +typedef std::map<String,http_hdr_cc_type> HdrCcNameToIdMap_t;
>>>> +static HdrCcNameToIdMap_t HdrCcNameToIdMap;
>>>
>>> HdrCcNameToIdMap should be constant so that we do not accidentally
>>> modify it. You can make it a pointer and use similar-to-current
>>> initialization code or try to initialize statically.
>>
>> Are you sure we run such a risk? I've now changed it so that it is a
>> static data member with const key. Do you think it could be enough?
>>
>>>> +        HdrCcNameToIdMap_t::iterator i;
>>>
>>> The above variable can be marked as const.
>>
>> Done.
>>
>>>> +static HdrCcNameToIdMap_t HdrCcNameToIdMap;
>>>
>>> Consider dropping the "Hdr" prefix since you are inside a HdrCc file
>>> already. This will also make it consistent with CcAttrs name.
>>
>> Done.
>>
>>>> void
>>>> +HttpHdrCc::clear()
>>>> +{
>>>> +    mask=0;
>>>> +    max_age=-1;
>>>> +    mask=0;
>>>> +    max_age=-1;
>>>> +    s_maxage=-1;
>>>> +    max_stale=-1;
>>>> +    stale_if_error=0;
>>>> +    min_fresh=-1;
>>>> +    other.clean();
>>>> +}
>>>
>>> This duplicates the default constructor. Mask and max_age are cleared
>>> twice. Consider this implementation instead (which can be inlined):
>>>
>>>    *this = HttpHdrCc();
>>
>> Done. Clever.
>>
>>>> +    int32_t i;
>>>> +    /* build lookup and accounting structures */
>>>> +    for (i=0;i<CC_ENUM_END;i++) {
>>>
>>> The "i" variable should be local to the loop. Please consider adding
>>> spaces around operators.
>>
>> Done.
>>
>>>> +        assert(i==CcAttrs[i].id); /* verify assumption: the id is the key 
>>>> into the array */
>>>> +        HdrCcNameToIdMap[CcAttrs[i].name]=CcAttrs[i].id;
>>>
>>> Consider computing CcAttrs[i] once instead of three times and storing it
>>> as a local const reference.
>>
>> Done.
>>
>>>> +        assert(i==CcAttrs[i].id); /* verify assumption: the id is the key 
>>>> into the array */
>>>
>>> Where do we actually use that assumption?
>>
>> HttpHeaderCcFields is not const. Its stat field member can be updated
>> (look for ++CcAttrs[type].stat.repCount). In other words, it doubles
>> as an array-type data-store, indexed on the header type numeric value.
>> This assertion validates that.
>>
>>>> -        if (EBIT_TEST(cc->mask, type)) {
>>>> +        if (EBIT_TEST(mask, type)) {
>>>> -            EBIT_SET(cc->mask, type);
>>>> +            EBIT_SET(mask, type);
>>>> -            if (!p || !httpHeaderParseInt(p, &cc->max_age)) {
>>>> +            if (!p || !httpHeaderParseInt(p, &max_age)) {
>>>> -                cc->max_age = -1;
>>>> -                EBIT_CLR(cc->mask, type);
>>>> +                max_age = -1;
>>>> +                EBIT_CLR(mask, type);
>>>> -            if (!p || !httpHeaderParseInt(p, &cc->s_maxage)) {
>>>> +            if (!p || !httpHeaderParseInt(p, &s_maxage)) {
>>>
>>> All of the above (and more) are essentially non-changes. Please consider
>>> making "cc" equal to "this" to avoid them for the purpose of the review,
>>> so that we can pinpoint the real changes. That hack should be removed
>>> before the final commit, of course.
>>
>> Ok.
>>
>>>> + *  Created on: Sep 2, 2011
>>>> + *      Author: Francesco Chemolli
>>>
>>> I would recommend removing that because there are many authors for that
>>> code. You have my permission to remove my Author tag in src/HttpHdrCc.cc
>>> as well.
>>
>> Done.
>>
>>>> +class HttpHdrCc
>>>> +{
>>>> +
>>>> +public:
>>>> +    int32_t mask;
>>>> +    int32_t max_age;
>>>> +    int32_t s_maxage;
>>>> +    int32_t max_stale;
>>>> +    int32_t stale_if_error;
>>>> +    int32_t min_fresh;
>>>> +    String other;
>>>> +
>>>> +    HttpHdrCc(int32_t max_age_=-1, int32_t s_maxage_=-1,
>>>
>>> Please move public data member after public methods. It would be nice to
>>> document them too, especially those that do not correspond to CC
>>> directives. Also, check whether we really need all of the above,
>>> especially mask, as public fields (more on that later below).
>>
>> Done. Documented "mask" and "other", the others should be straightforward.
>> public mask could be avoided if we do full getters/setters, but doing
>> that elegantly would be scope-balooning.
>>
>>>> +    HttpHdrCc(int32_t max_age_=-1, int32_t s_maxage_=-1,
>>>> +            int32_t max_stale_=-1, int32_t min_fresh_=-1) :
>>>
>>> Do we really all five of these constructors, including the one that
>>> allows for implicit conversion from int32_t to HttpHdrCc? I do not think
>>> so. Please leave just what we need and use "explicit" to prevent
>>> implicit conversions as needed.
>>
>> Overengineering. Changed to only the default contstructor (we need it
>> to set various fields to "-1" by default).
>> Ok for explicit.
>>
>>> As far as I can see, we just need the default constructor, but my quick
>>> check may be missing some cases:
>>>
>>>> $ fgrep -RI httpHdrCcCreate src
>>>> src/HttpHdrCc.cc:httpHdrCcCreate(void)
>>>> src/HttpHdrCc.cc:    HttpHdrCc *cc = httpHdrCcCreate();
>>>> src/HttpHdrCc.cc:    dup = httpHdrCcCreate();
>>>> src/http.cc:            cc = httpHdrCcCreate();
>>>> src/protos.h:SQUIDCEXTERN HttpHdrCc *httpHdrCcCreate(void);
>>>> src/mime.cc:    reply->cache_control = httpHdrCcCreate();
>>
>> Yes.
>>
>>>> +    /** reset the structure to a clear state.
>>>> +     *
>>>> +     */
>>>> +    void clear();
>>>
>>> The "clear state" is an undefined concept. Consider a more specific
>>> description such as:
>>> /// reset to the after-default-construction state
>>>
>>> (and there is probably a more elegant way of saying that).
>>
>> How about "reset all data members to default state"? Otherwise I'll
>> use your suggestion.
>>
>>>> +     * \note: internal structures are not cleaned-up beforehand.
>>>> +     *        caller must explicitly clear() beforehand if he wants that
>>>> +     */
>>>> +    bool parseInit(const String &s);
>>>
>>> It is wrong that *Init() does not initialize. If this is not your fault
>>> and you do not want to fix it, then mark with XXX.
>>
>> That's a direct derivative of the name it has now.
>> I'll rename it to parse.
>>
>>>> +    /** set the max_age value
>>>> +     *
>>>> +     * \param max_age the new max age. Values <0 clear it.
>>>> +     */
>>>> +    void setMaxAge(int32_t max_age);
>>>> +
>>>> +    /** set the s-maxage
>>>> +     *
>>>> +     * \param s_maxage the new max age. Values <0 clear it.
>>>> +     */
>>>> +    void setSMaxAge(int32_t s_maxage);
>>>
>>>
>>> It feels wrong to have many public fields and [only] these two methods.
>>> We should probably hide all fields and provide the corresponding name()
>>> and name(int32_t) accessors and setters to those fields that need them.
>>
>> Direct refactoring artifact.
>> However, setSMaxAge is not used anywhere, so I'll remove it. Are you
>> sure it's needed to set up a full getter/setter structure for what is
>> in essence a glorified struct? It really feels like over-engineering.
>>
>>>> === modified file 'src/HttpHeader.h'
>>>> --- src/HttpHeader.h  2011-06-23 08:31:56 +0000
>>>> +++ src/HttpHeader.h  2011-09-12 22:54:38 +0000
>>>> @@ -37,6 +37,7 @@
>>>>  #include "HttpHeaderRange.h"
>>>>  /* HttpHeader holds a HttpHeaderMask */
>>>>  #include "HttpHeaderMask.h"
>>>> +#include "HttpHdrCc.h"
>>>>
>>>>
>>>
>>> Is this addition needed? Please use "class HttpHdrCc;" pre-declaration
>>> instead if possible.
>>
>> Removed the include. Class forward declaration was already in place.
>> This unveiled a few other needed include-places which were indirectly
>> included.
>>
>> Attached is iteration 2 of the patch, build- and run-tested (not ready
>> for merge, but for a second validation round).
>>
>> Thanks
>>
>>
>> --
>>     /kinkie
>>
> 
> 
> 

Reply via email to