maria-developers team mailing list archive
-
maria-developers team
-
Mailing list archive
-
Message #12376
Re: On bb-10.6-monty work
Hi!
Sorry for the delay, have been very busy with working on bug fixes and
internal discussions.
On Fri, Sep 11, 2020 at 7:50 AM Nikita Malyavin
<nikitamalyavin@xxxxxxxxx> wrote:
>
> Hello, Monty!
>
> I've been asked to review your recent work regarding memory footprint optimizations.
<cut>
> > --- a/sql/item.h
> > +++ b/sql/item.h
> > @@ -4236,6 +4239,23 @@ class Item_bool :public Item_int
> > };
> >
> >
> > +class Item_bool_static :public Item_bool
> > +{
> > +public:
> > + Item_bool_static(const char *str_arg, longlong i):
> > + Item_bool(NULL, str_arg, i) {};
> > +
> > + /* Create dummy functions for things that may change the static item */
> > + void fix_length_and_charset(uint32 max_char_length_arg, CHARSET_INFO *cs)
> > + {}
> > + void fix_char_length(size_t max_char_length_arg)
> > + {}
> > + void set_join_tab_idx(uint join_tab_idx_arg)
> > + { DBUG_ASSERT(0); }
> > +};
> > +
> > +extern const Item_bool_static Item_false, Item_true;
> > +
> > class Item_uint :public Item_int
> > {
> > public:
>
>
>
> Do we really need an additional class for static Item_bool's?
> I know that we have constructors hidden for Item, so maybe just
> unhide it in Item_bool, and that's it.
I need the constructor to ensure that no one calls set_join_tab_idx()
(which can be called for any item)
and possible other methods.
The two other methods are a safeguard as it's not obvious when they
could be called.
> Besides, I see fix_char_length is not virtual at all, so reimplementing it has no efect.
Yes, I missed that. I have now deleted that one.
> And why can't we do all that in Item_bool itself?
We can't fix join_tab_idx().
> Note that adding new class increases a virtual method table, and it's huge already, for Item hierarchy.
Adding a new class should not increase the size of the virtual table
for items. That only contains virtual functions.
Add a new item with virtual methods does create a new virtual table,
but it's not that huge (but it's not that small either). It's around
1654 bytes for Item's in 10.6
> We could also add some other frequently used Items, like 0, 1, '', NULL, to a static memory.
We create very few item's with fixed value on the fly.
Another problem with static item's is that we have functions that
change them, with _set_join_tab_idx() and marker() for example, which
means most items can't be static.
We only use the new Item_true and Item_false to replace top level
items, which are not marked. Other places are not safe. This makes it
hard to use other constants like 0, 1 and NULL as static items.
> > commit 6ca3ab6c2c18cdbf614984cb9d5312d58e718372
><cut>
> > +
> > +
> > +/* Make operations in item_base_t and item_with_t work like 'int' */
> > +static inline item_base_t operator&(const item_base_t a, const item_base_t b)
> > +{
> > + return (item_base_t) (((item_flags_t) a) & ((item_flags_t) b));
> > +}
> > +
> > +static inline item_base_t & operator&=(item_base_t &a, item_base_t b)
> > +{
> > + a= (item_base_t) (((item_flags_t) a) & (item_flags_t) b);
> > + return a;
> > +}
> > +
> > +static inline item_base_t operator|(const item_base_t a, const item_base_t b)
> > +{
> > + return (item_base_t) (((item_flags_t) a) | ((item_flags_t) b));
> > +}
> > +
> > +static inline item_base_t & operator|=(item_base_t &a, item_base_t b)
> > +{
> > + a= (item_base_t) (((item_flags_t) a) | (item_flags_t) b);
> > + return a;
> > +}
> > +
> > +static inline item_base_t operator~(const item_base_t a)
> > +{
> > + return (item_base_t) ~(item_flags_t) a;
> > +}
> > +
> > +static inline item_with_t operator&(const item_with_t a, const item_with_t b)
> > +{
> > + return (item_with_t) (((item_flags_t) a) & ((item_flags_t) b));
> > +}
> > +
> > +static inline item_with_t & operator&=(item_with_t &a, item_with_t b)
> > +{
> > + a= (item_with_t) (((item_flags_t) a) & (item_flags_t) b);
> > + return a;
> > +}
> > +
> > +static inline item_with_t operator|(const item_with_t a, const item_with_t b)
> > +{
> > + return (item_with_t) (((item_flags_t) a) | ((item_flags_t) b));
> > +}
> > +
> > +static inline item_with_t & operator|=(item_with_t &a, item_with_t b)
> > +{
> > + a= (item_with_t) (((item_flags_t) a) | (item_flags_t) b);
> > + return a;
> > +}
> > +
> > +static inline item_with_t operator~(const item_with_t a)
> > +{
> > + return (item_with_t) ~(item_flags_t) a;
> > +}
<cut>
> Nice experimentation! I wanted to suggest using constexprs inside Item, but
> this is even better, because you cant freely add a bit that not in the enum.
>
> Though I think it is too bloaty to specify all the operators each time,
> so I'd prefer to see duplications metaprogrammed out somehow.
When I wrote the above I was considering doing the above with a template, but
as it was only needed for two item's I decided it was not yet time to
do that. Doing it for
2 instances and 5 functions would in the end make the code longer.
If we would ever need to add a third flag, the yes we should
definitely try to automate
this.
> There is no sane way in C++ (even in modern one) to specify traits, which extend
> the class functionality (see Golang's traits), so I'd suggest to use good old
> preprocessor way, like following:
>
> #define T item_base_t
> #include "setup_bitwise_operators.inc"
>
> #define T item_with_t
> #include "setup_bitwise_operators.inc"
>
> and then in setup_bitwise_operators.inc:
> static inline T operator&(const T a, const T b)
> {
> return (T) (((item_flags_t) a) & ((item_flags_t) b));
> }
>
> And so on.
I agree that this is a good way forward, if we ever need to add more flags or
we want to use the same method elsewhere.
> Another variant I've just googled is to make a template operator for all types,
> but restrict its applicatory type set with std::enable_if<T>:
> https://www.justsoftwaresolutions.co.uk/cplusplus/using-enum-classes-as-bitfields.html
I looked at this. It's an interesting solution, but I didn't like the
way the code looks.
It's not obvious for a C programmer and one it's not clear how to use
or debug it.
Isn't there a way to instantiate templates for just the 5 functions
that I added?
(In other words, create resulting code that is in effect exact like
what I wrote, and
no other versions)?
<cut>
> Up to you whic way to use, but I think it should be done, since we have many other flag sets,
> which are likely to be prettified with the same style.
Agree that we need a good simple way to define bit fields in the future.
However I will for now leave this until we have to add a new bitfield.
Regards,
Monty
References