[IMP] core: save memory of empty dicts
Use `frozendict` for dicts that often remain empty on models, like _inherits and _depends, and also make `frozendict` more compact in memory. On a registry with 296 modules, this saves 635 kilobytes of memory, which is about 6% of the registry's memory footprint. closes odoo/odoo#70402 Related: odoo/enterprise#18142 Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
This commit is contained in:
+13
-7
@@ -472,7 +472,7 @@ class BaseModel(metaclass=MetaModel):
|
||||
* If :attr:`._name` is set, name(s) of parent models to inherit from
|
||||
* If :attr:`._name` is unset, name of a single model to extend in-place
|
||||
"""
|
||||
_inherits = {}
|
||||
_inherits = frozendict()
|
||||
"""dictionary {'parent_model': 'm2o_field'} mapping the _name of the parent business
|
||||
objects to the names of the corresponding foreign key fields to use::
|
||||
|
||||
@@ -519,7 +519,7 @@ class BaseModel(metaclass=MetaModel):
|
||||
as attribute.
|
||||
"""
|
||||
|
||||
_depends = {}
|
||||
_depends = frozendict()
|
||||
"""dependencies of models backed up by SQL views
|
||||
``{model_name: field_names}``, where ``field_names`` is an iterable.
|
||||
This is only used to determine the changes to flush to database before
|
||||
@@ -699,8 +699,8 @@ class BaseModel(metaclass=MetaModel):
|
||||
cls._table = cls._name.replace('.', '_')
|
||||
cls._sequence = None
|
||||
cls._log_access = cls._auto
|
||||
cls._inherits = {}
|
||||
cls._depends = {}
|
||||
inherits = {}
|
||||
depends = {}
|
||||
cls._sql_constraints = {}
|
||||
|
||||
for base in reversed(cls.__base_classes):
|
||||
@@ -713,10 +713,10 @@ class BaseModel(metaclass=MetaModel):
|
||||
cls._sequence = base._sequence or cls._sequence
|
||||
cls._log_access = getattr(base, '_log_access', cls._log_access)
|
||||
|
||||
cls._inherits.update(base._inherits)
|
||||
inherits.update(base._inherits)
|
||||
|
||||
for mname, fnames in base._depends.items():
|
||||
cls._depends.setdefault(mname, []).extend(fnames)
|
||||
depends.setdefault(mname, []).extend(fnames)
|
||||
|
||||
for cons in base._sql_constraints:
|
||||
cls._sql_constraints[cons[0]] = cons
|
||||
@@ -724,6 +724,12 @@ class BaseModel(metaclass=MetaModel):
|
||||
cls._sequence = cls._sequence or (cls._table + '_id_seq')
|
||||
cls._sql_constraints = list(cls._sql_constraints.values())
|
||||
|
||||
# avoid assigning an empty dict to save memory
|
||||
if inherits:
|
||||
cls._inherits = inherits
|
||||
if depends:
|
||||
cls._depends = depends
|
||||
|
||||
# update _inherits_children of parent models
|
||||
for parent_name in cls._inherits:
|
||||
pool[parent_name]._inherits_children.add(cls._name)
|
||||
@@ -2841,7 +2847,7 @@ class BaseModel(metaclass=MetaModel):
|
||||
field.required = True
|
||||
if field.ondelete.lower() not in ('cascade', 'restrict'):
|
||||
field.ondelete = 'cascade'
|
||||
self._inherits[field.comodel_name] = field.name
|
||||
type(self)._inherits = {**self._inherits, field.comodel_name: field.name}
|
||||
self.pool[field.comodel_name]._inherits_children.add(self._name)
|
||||
|
||||
@api.model
|
||||
|
||||
@@ -940,22 +940,32 @@ def clean_context(context):
|
||||
""" This function take a dictionary and remove each entry with its key starting with 'default_' """
|
||||
return {k: v for k, v in context.items() if not k.startswith('default_')}
|
||||
|
||||
|
||||
class frozendict(dict):
|
||||
""" An implementation of an immutable dictionary. """
|
||||
__slots__ = ()
|
||||
|
||||
def __delitem__(self, key):
|
||||
raise NotImplementedError("'__delitem__' not supported on frozendict")
|
||||
|
||||
def __setitem__(self, key, val):
|
||||
raise NotImplementedError("'__setitem__' not supported on frozendict")
|
||||
|
||||
def clear(self):
|
||||
raise NotImplementedError("'clear' not supported on frozendict")
|
||||
|
||||
def pop(self, key, default=None):
|
||||
raise NotImplementedError("'pop' not supported on frozendict")
|
||||
|
||||
def popitem(self):
|
||||
raise NotImplementedError("'popitem' not supported on frozendict")
|
||||
|
||||
def setdefault(self, key, default=None):
|
||||
raise NotImplementedError("'setdefault' not supported on frozendict")
|
||||
|
||||
def update(self, *args, **kwargs):
|
||||
raise NotImplementedError("'update' not supported on frozendict")
|
||||
|
||||
def __hash__(self):
|
||||
return hash(frozenset((key, freehash(val)) for key, val in self.items()))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user