From cd122933867c096f61fae945f11e842ea84d06b8 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Wed, 31 Mar 2021 14:43:57 +0000 Subject: [PATCH] [IMP] core: speed up loading of registry The base classes of models in the registry are modified when models are extended by inheritance. But modifying cls.__bases__ is a costly operation, so we manage to do it once per model when loading a registry. Our benchmark consists in loading a registry with 296 modules. The net time to load the registry is 25% smaller. In other words, the registry loads 25% faster. Note that the time does not include the time to load modules themselves, which does not change. --- odoo/addons/test_new_api/tests/test_new_fields.py | 2 +- odoo/models.py | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/odoo/addons/test_new_api/tests/test_new_fields.py b/odoo/addons/test_new_api/tests/test_new_fields.py index 313dcd7d94b..1f67fb805e2 100644 --- a/odoo/addons/test_new_api/tests/test_new_fields.py +++ b/odoo/addons/test_new_api/tests/test_new_fields.py @@ -3086,7 +3086,7 @@ class TestSelectionOndeleteAdvanced(common.TransactionCase): # necessary cleanup for resetting changes in the registry for model_name in (self.MODEL_BASE, self.MODEL_REQUIRED): Model = self.registry[model_name] - self.addCleanup(setattr, Model, '__bases__', Model.__bases__) + self.addCleanup(setattr, Model, '_BaseModel__base_classes', Model._BaseModel__base_classes) def test_ondelete_unexisting_policy(self): class Foo(models.Model): diff --git a/odoo/models.py b/odoo/models.py index 7c032a9e0ba..a07d4cccdc3 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -618,7 +618,7 @@ class BaseModel(metaclass=MetaModel): ModelClass._build_model_check_base(cls) check_parent = ModelClass._build_model_check_parent else: - ModelClass = type(name, (BaseModel,), { + ModelClass = type(name, (cls,), { '_name': name, '_register': False, '_original_module': cls._module, @@ -636,7 +636,7 @@ class BaseModel(metaclass=MetaModel): raise TypeError("Model %r inherits from non-existing model %r." % (name, parent)) parent_class = pool[parent] if parent == name: - for base in parent_class.__bases__: + for base in parent_class.__base_classes: bases.add(base) else: check_parent(cls, parent_class) @@ -644,7 +644,9 @@ class BaseModel(metaclass=MetaModel): ModelClass._inherit_module[parent] = cls._module parent_class._inherit_children.add(name) - ModelClass.__bases__ = tuple(bases) + # ModelClass.__bases__ must be assigned those classes; however, this + # operation is quite slow, so we do it once in method _prepare_setup() + ModelClass.__base_classes = tuple(bases) # determine the attributes of the model's class ModelClass._build_model_attributes(pool) @@ -701,7 +703,7 @@ class BaseModel(metaclass=MetaModel): cls._depends = {} cls._sql_constraints = {} - for base in reversed(cls.__bases__): + for base in reversed(cls.__base_classes): if is_definition_class(base): # the following attributes are not taken from registry classes if cls._name not in base._inherit and not base._description: @@ -2839,6 +2841,10 @@ class BaseModel(metaclass=MetaModel): cls = type(self) cls._setup_done = False + # changing base classes is costly, do it only when necessary + if cls.__bases__ != cls.__base_classes: + cls.__bases__ = cls.__base_classes + # reset those attributes on the model's class for _setup_fields() below for attr in ('_rec_name', '_active_name'): discardattr(cls, attr)