From 4fb958d086e2bb5567bc4e3be846dafe9dbaba04 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Wed, 14 Apr 2021 08:55:59 +0000 Subject: [PATCH] [IMP] core: group all field_inverses dicts on registry This makes the union of many dicts into a single dict. On a registry with 296 modules, this saves 300 kilobytes of memory, which is about 3% of the registry's memory footprint. --- odoo/addons/base/models/ir_model.py | 2 +- odoo/fields.py | 30 ++++++++++++++--------------- odoo/models.py | 12 +++++------- odoo/modules/registry.py | 12 ++++++++---- 4 files changed, 29 insertions(+), 27 deletions(-) diff --git a/odoo/addons/base/models/ir_model.py b/odoo/addons/base/models/ir_model.py index 06117af7677..4a93426d780 100644 --- a/odoo/addons/base/models/ir_model.py +++ b/odoo/addons/base/models/ir_model.py @@ -756,7 +756,7 @@ class IrModelFields(models.Model): for dep in model._dependent_fields(field): if dep.manual: failed_dependencies.append((field, dep)) - for inverse in model._field_inverses.get(field, ()): + for inverse in model.pool.field_inverses[field]: if inverse.manual and inverse.type == 'one2many': failed_dependencies.append((field, inverse)) diff --git a/odoo/fields.py b/odoo/fields.py index 333536bad00..77c43d14b74 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -721,7 +721,7 @@ class Field(MetaField('DummyField', (object,), {})): yield tuple(field_seq) if field.type in ('one2many', 'many2many'): - for inv_field in Model._field_inverses[field]: + for inv_field in Model.pool.field_inverses[field]: yield tuple(field_seq) + (inv_field,) model_name = field.comodel_name @@ -2846,7 +2846,7 @@ class Many2one(_Relational): # align(id) returns a NewId if records are new, a real id otherwise align = (lambda id_: id_) if all(record_ids) else (lambda id_: id_ and NewId(id_)) - for invf in records._field_inverses[self]: + for invf in records.pool.field_inverses[self]: corecords = records.env[self.comodel_name].browse( align(id_) for id_ in cache.get_values(records, self) ) @@ -2862,7 +2862,7 @@ class Many2one(_Relational): return cache = records.env.cache corecord = self.convert_to_record(value, records) - for invf in records._field_inverses[self]: + for invf in records.pool.field_inverses[self]: valid_records = records.filtered_domain(invf.get_domain_list(corecord)) if not valid_records: continue @@ -2905,7 +2905,7 @@ class Many2oneReference(Integer): record_ids = set(records._ids) model_ids = self._record_ids_per_res_model(records) - for invf in records._field_inverses[self]: + for invf in records.pool.field_inverses[self]: records = records.browse(model_ids[invf.model_name]) if not records: continue @@ -2925,7 +2925,7 @@ class Many2oneReference(Integer): cache = records.env.cache model_ids = self._record_ids_per_res_model(records) - for invf in records._field_inverses[self]: + for invf in records.pool.field_inverses[self]: records = records.browse(model_ids[invf.model_name]) if not records: continue @@ -3198,7 +3198,7 @@ class _RelationalMulti(_Relational): return val._origin if isinstance(val, BaseModel) else val # make result with new and existing records - inv_names = {field.name for field in record._field_inverses[self]} + inv_names = {field.name for field in record.pool.field_inverses[self]} result = [Command.set([])] for record in value: origin = record._origin @@ -3332,8 +3332,8 @@ class One2many(_RelationalMulti): if isinstance(invf, (Many2one, Many2oneReference)): # setting one2many fields only invalidates many2one inverses; # integer inverses (res_model/res_id pairs) are not supported - model._field_inverses.add(self, invf) - comodel._field_inverses.add(invf, self) + model.pool.field_inverses.add(self, invf) + comodel.pool.field_inverses.add(invf, self) _description_relation_field = property(attrgetter('inverse_name')) @@ -3679,10 +3679,10 @@ class Many2many(_RelationalMulti): raise TypeError(msg % (self, field)) fields.append(self) - # retrieve inverse fields, and link them in _field_inverses + # retrieve inverse fields, and link them in field_inverses for field in m2m[(self.relation, self.column2, self.column1)]: - model._field_inverses.add(self, field) - model.env[field.model_name]._field_inverses.add(field, self) + model.pool.field_inverses.add(self, field) + model.pool.field_inverses.add(field, self) def update_db(self, model, columns): cr = model._cr @@ -3854,7 +3854,7 @@ class Many2many(_RelationalMulti): y_to_xs = defaultdict(set) for x, y in pairs: y_to_xs[y].add(x) - for invf in records._field_inverses[self]: + for invf in records.pool.field_inverses[self]: domain = invf.get_domain_list(comodel) valid_ids = set(records.filtered_domain(domain)._ids) if not valid_ids: @@ -3892,7 +3892,7 @@ class Many2many(_RelationalMulti): cr.execute(query, params) # update the cache of inverse fields - for invf in records._field_inverses[self]: + for invf in records.pool.field_inverses[self]: for y, xs in y_to_xs.items(): corecord = comodel.browse(y) try: @@ -3968,7 +3968,7 @@ class Many2many(_RelationalMulti): y_to_xs = defaultdict(set) for x, y in pairs: y_to_xs[y].add(x) - for invf in records._field_inverses[self]: + for invf in records.pool.field_inverses[self]: domain = invf.get_domain_list(comodel) valid_ids = set(records.filtered_domain(domain)._ids) if not valid_ids: @@ -3989,7 +3989,7 @@ class Many2many(_RelationalMulti): y_to_xs = defaultdict(set) for x, y in pairs: y_to_xs[y].add(x) - for invf in records._field_inverses[self]: + for invf in records.pool.field_inverses[self]: for y, xs in y_to_xs.items(): corecord = comodel.browse([y]) try: diff --git a/odoo/models.py b/odoo/models.py index b01c92b3075..68d14683446 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -2898,8 +2898,6 @@ class BaseModel(metaclass=MetaModel): self._add_inherited_fields() # 4. initialize more field metadata - cls._field_inverses = Collector() # inverse fields for related fields - cls._setup_done = True for field in cls._fields.values(): @@ -3690,7 +3688,7 @@ Fields: # DLE P150: `test_cancel_propagation`, `test_manufacturing_3_steps`, `test_manufacturing_flow` # TODO: check whether still necessary records_to_inverse[field] = self.filtered('id') - if field.relational or self._field_inverses[field]: + if field.relational or self.pool.field_inverses[field]: relational_names.append(fname) if field.inverse or (field.compute and not field.readonly): if field.store or field.type not in ('one2many', 'many2many'): @@ -4079,7 +4077,7 @@ Fields: else: cache_value = field.convert_to_cache(value, record) self.env.cache.set(record, field, cache_value) - if field.type in ('many2one', 'many2one_reference') and record._field_inverses[field]: + if field.type in ('many2one', 'many2one_reference') and self.pool.field_inverses[field]: inverses_update[(field, cache_value)].append(record.id) for (field, value), record_ids in inverses_update.items(): @@ -5230,7 +5228,7 @@ Fields: inv_recs = self[field.name].filtered(lambda r: not r.id) if not inv_recs: continue - for invf in self._field_inverses[field]: + for invf in self.pool.field_inverses[field]: # DLE P98: `test_40_new_fields` # /home/dle/src/odoo/master-nochange-fp/odoo/addons/test_new_api/tests/test_new_fields.py # Be careful to not break `test_onchange_taxes_1`, `test_onchange_taxes_2`, `test_onchange_taxes_3` @@ -5813,7 +5811,7 @@ Fields: # invalidate fields and inverse fields, too spec = [(f, ids) for f in fields] + \ - [(invf, None) for f in fields for invf in self._field_inverses[f]] + [(invf, None) for f in fields for invf in self.pool.field_inverses[f]] self.env.cache.invalidate(spec) def modified(self, fnames, create=False, before=False): @@ -5914,7 +5912,7 @@ Fields: else: # val is another tree of dependencies model = self.env[key.model_name] - for invf in model._field_inverses[key]: + for invf in model.pool.field_inverses[key]: # use an inverse of field without domain if not (invf.type in ('one2many', 'many2many') and invf.domain): if invf.type == 'many2one_reference': diff --git a/odoo/modules/registry.py b/odoo/modules/registry.py index 9f0c734f07c..e537e3f8a18 100644 --- a/odoo/modules/registry.py +++ b/odoo/modules/registry.py @@ -135,6 +135,7 @@ class Registry(Mapping): # field dependencies self.field_depends = Collector() self.field_depends_context = Collector() + self.field_inverses = Collector() # Inter-process signaling: # The `base_registry_signaling` sequence indicates the whole registry @@ -271,20 +272,23 @@ class Registry(Mapping): for model in models: model._prepare_setup() - # do the actual setup from a clean state - self._m2m = defaultdict(list) + self.field_depends.clear() + self.field_depends_context.clear() + self.field_inverses.clear() + + # do the actual setup for model in models: model._setup_base() + self._m2m = defaultdict(list) for model in models: model._setup_fields() + del self._m2m for model in models: model._setup_complete() # determine field_depends and field_depends_context - self.field_depends.clear() - self.field_depends_context.clear() for model in models: for field in model._fields.values(): depends, depends_context = field.get_depends(model)