[IMP] core: use cache for mro in setup_models
With a lot of module installed setup_models can be quite slow. One of the reason for that are the call to resolve_mro. This operation is fast, but called for a lot of models/fields this become an important part of get_depends and setup_base. - This is call once for each models in setup_base - This is call more than once for each computed_field in get_depends. The use of a cache shows significative performance improvements. During the install of a database with all modules, the install times is reduced by ~3 minutes over ~14 Part-of: odoo/odoo#78898 Co-authored-by: Raphael Collet <rco@odoo.com>
This commit is contained in:
committed by
Raphael Collet
co-authored by
Raphael Collet
parent
f40abdce92
commit
d4539c188a
+8
-9
@@ -58,14 +58,13 @@ def resolve_mro(model, name, predicate):
|
||||
classes are ignored.
|
||||
"""
|
||||
result = []
|
||||
for cls in type(model).mro():
|
||||
if not is_registry_class(cls):
|
||||
value = cls.__dict__.get(name, Default)
|
||||
if value is Default:
|
||||
continue
|
||||
if not predicate(value):
|
||||
break
|
||||
result.append(value)
|
||||
for cls in model._model_classes:
|
||||
value = cls.__dict__.get(name, Default)
|
||||
if value is Default:
|
||||
continue
|
||||
if not predicate(value):
|
||||
break
|
||||
result.append(value)
|
||||
return result
|
||||
|
||||
|
||||
@@ -4100,6 +4099,6 @@ def apply_required(model, field_name):
|
||||
# pylint: disable=wrong-import-position
|
||||
from .exceptions import AccessError, MissingError, UserError
|
||||
from .models import (
|
||||
check_pg_name, expand_ids, is_definition_class, is_registry_class,
|
||||
check_pg_name, expand_ids, is_definition_class,
|
||||
BaseModel, IdType, NewId, PREFETCH_MAX,
|
||||
)
|
||||
|
||||
+9
-2
@@ -2986,6 +2986,12 @@ class BaseModel(metaclass=MetaModel):
|
||||
if cls._setup_done:
|
||||
return
|
||||
|
||||
# the classes that define this model, i.e., the ones that are not
|
||||
# registry classes; the purpose of this attribute is to behave as a
|
||||
# cache of [c for c in cls.mro() if not is_registry_class(c))], which
|
||||
# is heavily used in function fields.resolve_mro()
|
||||
cls._model_classes = tuple(c for c in cls.mro() if getattr(c, 'pool', None) is None)
|
||||
|
||||
# 1. determine the proper fields of the model: the fields defined on the
|
||||
# class and magic fields, not the inherited or custom ones
|
||||
|
||||
@@ -2997,8 +3003,9 @@ class BaseModel(metaclass=MetaModel):
|
||||
|
||||
# collect the definitions of each field (base definition + overrides)
|
||||
definitions = defaultdict(list)
|
||||
for klass in reversed(cls.mro()):
|
||||
if is_definition_class(klass):
|
||||
for klass in reversed(cls._model_classes):
|
||||
# this condition is an optimization of is_definition_class(klass)
|
||||
if isinstance(klass, MetaModel):
|
||||
for field in klass._field_definitions:
|
||||
definitions[field.name].append(field)
|
||||
for name, fields_ in definitions.items():
|
||||
|
||||
Reference in New Issue
Block a user