summaryrefslogtreecommitdiff
path: root/odoo/addons
diff options
context:
space:
mode:
authorRaphael Collet <rco@odoo.com>2017-05-03 11:43:05 +0200
committerRaphael Collet <rco@odoo.com>2017-05-03 15:41:05 +0200
commitb59318ec12a1ce4e59de6d7bcde7146545b6c044 (patch)
treef1c23d20305c2dfae87e3f2ad27e6fa525c00f27 /odoo/addons
parent1458f1b3135d373dac0625c7d4bd4a7eea3eaf54 (diff)
[REF] registry: always perform registry/cache signaling at the end of request
Problem: the update of custom models/fields is not fully transactional, and may potentially lead to an inconsistent database. An other problem is creating two custom fields by writing on a model: if the second one fails, the first one has been committed without notice. Retrying the request will give an unexpected error (duplicate field name). Solution: never commit in the middle of a request. If the changes have an impact on the registry, then mark it as invalid (with a new flag), and signal registry invalidation after everything has been committed. If the request fails, reset the registry. Both registry and cache invalidation are handled the same way.
Diffstat (limited to 'odoo/addons')
-rw-r--r--odoo/addons/base/ir/ir_cron.py3
-rw-r--r--odoo/addons/base/ir/ir_model.py27
-rw-r--r--odoo/addons/base/res/res_font.py2
-rw-r--r--odoo/addons/base/tests/test_ir_actions.py17
4 files changed, 22 insertions, 27 deletions
diff --git a/odoo/addons/base/ir/ir_cron.py b/odoo/addons/base/ir/ir_cron.py
index 0c61f230813..5b0c6567ec7 100644
--- a/odoo/addons/base/ir/ir_cron.py
+++ b/odoo/addons/base/ir/ir_cron.py
@@ -95,8 +95,9 @@ class ir_cron(models.Model):
if start_time and _logger.isEnabledFor(logging.DEBUG):
end_time = time.time()
_logger.debug('%.3fs (cron %s, server action %d with uid %d)', end_time - start_time, cron_name, server_action_id, self.env.uid)
- self.pool.signal_caches_change()
+ self.pool.signal_changes()
except Exception as e:
+ self.pool.reset_changes()
self._handle_callback_exception(cron_name, server_action_id, job_id, e)
@classmethod
diff --git a/odoo/addons/base/ir/ir_model.py b/odoo/addons/base/ir/ir_model.py
index f2d41c46847..49989a2c7a8 100644
--- a/odoo/addons/base/ir/ir_model.py
+++ b/odoo/addons/base/ir/ir_model.py
@@ -180,10 +180,8 @@ class IrModel(models.Model):
# Reload registry for normal unlink only. For module uninstall, the
# reload is done independently in odoo.modules.loading.
if not self._context.get(MODULE_UNINSTALL_FLAG):
- self._cr.commit() # must be committed before reloading registry in new cursor
- api.Environment.reset()
- registry = Registry.new(self._cr.dbname)
- registry.signal_registry_change()
+ # setup models; this automatically removes model from registry
+ self.pool.setup_models(self._cr)
return res
@@ -211,7 +209,6 @@ class IrModel(models.Model):
self.pool.setup_models(self._cr)
# update database schema
self.pool.init_models(self._cr, [vals['model']], dict(self._context, update_custom_fields=True))
- self.pool.signal_registry_change()
return res
@api.model
@@ -275,6 +272,11 @@ class IrModel(models.Model):
def _add_manual_models(self):
""" Add extra models to the registry. """
+ # clean up registry first
+ for name, model_class in self.pool.items():
+ if model_class._custom:
+ del self.pool.models[name]
+ # add manual models
cr = self.env.cr
cr.execute('SELECT * FROM ir_model WHERE state=%s', ['manual'])
for model_data in cr.dictfetchall():
@@ -591,12 +593,11 @@ class IrModelFields(models.Model):
# The field we just deleted might be inherited, and the registry is
# inconsistent in this case; therefore we reload the registry.
if not self._context.get(MODULE_UNINSTALL_FLAG):
- self._cr.commit()
- api.Environment.reset()
- registry = Registry.new(self._cr.dbname)
- models = registry.descendants(model_names, '_inherits')
- registry.init_models(self._cr, models, dict(self._context, update_custom_fields=True))
- registry.signal_registry_change()
+ # setup models; this re-initializes models in registry
+ self.pool.setup_models(self._cr)
+ # update database schema of model and its descendant models
+ models = self.pool.descendants(model_names, '_inherits')
+ self.pool.init_models(self._cr, models, dict(self._context, update_custom_fields=True))
return res
@@ -628,7 +629,6 @@ class IrModelFields(models.Model):
# update database schema of model and its descendant models
models = self.pool.descendants([vals['model']], '_inherits')
self.pool.init_models(self._cr, models, dict(self._context, update_custom_fields=True))
- self.pool.signal_registry_change()
return res
@@ -698,9 +698,6 @@ class IrModelFields(models.Model):
models = self.pool.descendants(patched_models, '_inherits')
self.pool.init_models(self._cr, models, dict(self._context, update_custom_fields=True))
- if column_rename or patched_models:
- self.pool.signal_registry_change()
-
return res
@api.multi
diff --git a/odoo/addons/base/res/res_font.py b/odoo/addons/base/res/res_font.py
index 873bea5aa03..ab3ad251c6c 100644
--- a/odoo/addons/base/res/res_font.py
+++ b/odoo/addons/base/res/res_font.py
@@ -91,7 +91,7 @@ class ResFont(models.Model):
# Remove inexistent fonts
self.search([('name', 'not in', existing_font_names), ('path', '!=', '/dev/null')]).unlink()
- self.pool.signal_caches_change()
+ self.pool.cache_invalidated = True
return self._sync()
def _sync(self):
diff --git a/odoo/addons/base/tests/test_ir_actions.py b/odoo/addons/base/tests/test_ir_actions.py
index 344829c8181..4e0ee08d408 100644
--- a/odoo/addons/base/tests/test_ir_actions.py
+++ b/odoo/addons/base/tests/test_ir_actions.py
@@ -188,22 +188,19 @@ class TestCustomFields(common.TransactionCase):
MODEL = 'res.partner'
def setUp(self):
- # use a test cursor instead of a real cursor
+ # check that the registry is properly reset
registry = odoo.registry()
- registry.enter_test_mode()
fnames = set(registry[self.MODEL]._fields)
-
@self.addCleanup
- def callback():
- registry.leave_test_mode()
- # the tests may have modified the registry, reset it
- with registry.cursor() as cr:
- registry.clear_caches()
- registry.setup_models(cr)
- assert set(registry[self.MODEL]._fields) == fnames
+ def check_registry():
+ assert set(registry[self.MODEL]._fields) == fnames
super(TestCustomFields, self).setUp()
+ # use a test cursor instead of a real cursor
+ self.registry.enter_test_mode()
+ self.addCleanup(self.registry.leave_test_mode)
+
# do not reload the registry after removing a field
self.env = self.env(context={'_force_unlink': True})