Jan Cholasta wrote:
Dne 15.11.2011 20:10, Rob Crittenden napsal(a):
Jan Cholasta wrote:
Dne 9.11.2011 11:59, Alexander Bokovoy napsal(a):
On Wed, 09 Nov 2011, Jan Cholasta wrote:
would't suffer from a facelift - currently it is messy, hard to read
code, with bits nobody ever used or uses anymore, some of the
docstrings and comments aren't correct, etc.)
A review of API class is a good idea. However, I think it is
enough what is in proposed patch as it gets you 2-3x speed increase

I've already started experimenting with the API class, hopefully it
will result in something useful :)

This is something I'd like to keep as it has great value for all
end-users and it requires loading all Python files in ipalib/plugins
(and in ipaserver/plugins for server side).

I'm not suggesting we should skip importing the modules. The plugin
initialization process consists of these 3 steps:

1. import plugin modules
2. create plugin instances
3. finalize plugin instances

What I'm suggesting is that we do steps 2 and 3 on-demand. We can't
do step 1 on-demand, because we have no way of knowing what plugins
are available without importing the modules. (Both your and my patch
does only step 3 on-demand, but I think we can do better than that.)

Anyway, if we decide to go with your solution, please make sure
*all* the plugins that are used are finalized (because of the
locking) and add a new api.env attribute which controls the lazy
finalization, so that the behavior can be overriden (actually I have
already done that - see attached patch - just use
"api.env.plugins_on_demand" instead of "api.env.context == 'cli'").

+ if not self.__dict__['_Plugin__finalized']:
+ self.finalize()

This doesn't seem right, coding style-wise. If you want to access
the property from outside the Plugin class, why did you name-mangle
it in the first place?
It is supposed to be internal detail of a Plugin. I agree it stinks a
bit here. :)

def finalize(self):
+ if not self.__finalized:
+ self.__finalized = True
+ else:
+ return
if not is_production_mode(self):

Finalize is supposed to be called just once, so IMO it would be
better not to do the check and let it throw the exception.
On contrary, I think sequential finalize() calls should do nothing.
This is at least what I expect from a finalized object -- no-op.

In my patch, finalize() throws an exception if called more than once,
but ensure_finalized() does nothing for plugins that are already
finalized. So there are both kinds of behavior available.

+ for i in ('Object', 'Property', 'Backend'):
+ if i in self:
+ namespaces.append(self[i])

AFAIK the framework is supposed to be generally usable for other
projects in the future. With that in mind, I think we can't afford
to hard-code things like this.
That's true. As you managed to get around without hardcoding, we can
drop this part.

Anyway, I've made a patch that uses data descriptors for the trap
objects (which is IMHO more elegant than what you do). I've also
managed to add on-demand finalization to Object and Attribute
subclasses by moving the set-up code from set_api() to finalize()
(it doesn't add much performance, though). See attachment.
I read through the code and I like it! Did you get the whole test
suite running with it? There are some parts of tests that expect
non-finalized objects to have None properties while they are now not

I always run the test suite ;-)

All the unit tests succeed (they do when run with my patch 54 applied,
which fixes failures of some unrelated unit tests).

If so, preliminary ACK for your patch from reading it if you would
make sure on_finalize() allows multiple calls and would make a better
commit message. ;)

on_finalize() shouldn't be called directly (perhaps I should rename it
to _on_finalize to emphasize that...?)

I'll work on the commit message. As usual, it is the hardest part of the
patch for me.

I'll try to arrange testing myself today/tomorrow.

The numbers from my VM:

master abbra jcholast
$ time ipa
real 0m1.288s 0m0.619s 0m0.601s
user 0m1.103s 0m0.478s 0m0.451s
sys 0m0.161s 0m0.126s 0m0.133s

$ time ipa user-find
real 0m1.897s 0m1.253s 0m1.235s
user 0m1.119s 0m0.486s 0m0.488s
sys 0m0.160s 0m0.160s 0m0.136s

$ time ipa help
real 0m1.299s 0m0.629s 0m0.600s
user 0m1.094s 0m0.477s 0m0.446s
sys 0m0.183s 0m0.136s 0m0.140s
Looks good (your VM is supposedly at the same farm as mine so numbers
are comparable). There is anyway great variation in execution times in
VMs so 600ms vs 629ms is roughly the same.


Thanks a lot! I think it is great advance over the original approach.

Thanks for the kind words :-)


Just a couple of questions/clarifications:

1. I think more documentation is needed for on_finalize(). The name
isn't particularly descriptive. If I read it properly you are providing
an alternate way to override finalize(), right?

Yes. I have split finalize() to finalize() (the method to be called to
finalize the plugin) and on_finalize() (the method to be overridden by
plugin developer to implement custom finalization), so that I can guard
the finalizing code from recursively calling itself (which happens when
you try to read an unfinalized finalize_attr attribute from within a
finalize() call).

2. Changing to a partition in Attribute is not equivalent to the regular
expression previously used. Why loosen the requirements?

Well, I didn't think it through. I have reverted the change.

3. I think you should document in-line where you have block calls to
finalize_attr() so that future developers know to add the stub.


4. What is the purpose of the read-lock in finalize?

I guess it is the usual - to prevent modifying the object after the API
is finalized. The commit that introduced it is
the commit that made it conditional is

It generally looks good and provides impressive performance improvements.


Updated patch attached.


ACK, pushed to master.


Freeipa-devel mailing list

Reply via email to