Skip to content

Commit

Permalink
[10.0] Remove RowExclusiveLock on exception_rule
Browse files Browse the repository at this point in the history
The goal of the modified method is to create or remove the relationship
(in the M2m relation tabel) between the tested model (such as
sale_order) and the exception rules. When the ORM writes on
ExceptionRule.sale_ids (using the example of sale_exception), it will
first proceeds with these updates:

* an UPDATE on exception_rule to set the write_date
* INSERT or DELETE on the relation table
* but then, as "write" is called on the exception rule, the ORM will
  trigger the api.depends to recompute all the "main_exception_ids"
  of the records (sales, ...) related to it, leading to an UPDATE
  for each sale order

We end up with RowExclusiveLock on such records:

* All the records of the relation table added / deleted for the current
sale order
* All the records of exception_rule matching the current sale order
* All the records of sale_order related to the exception rules matching
the current sale order

The first one is expected, the next 2 are not. We can remove the lock on
the exception_rule table by removing `_log_access`, however in any case,
the main_exception_ids computed field will continue to lock many sale
orders, effectively preventing 2 sales orders with the same exception
to be confirmed at the same time.

Reversing the write by writing on SaleOrder instead of ExceptionRule
fixes the 2 unexpected locks. It should not result in more queries: the
"to remove" part generates a DELETE on the relation table for the rule
to remove and the "to add" part generates an INSERT for the rule to add,
both will be exactly the same in both cases.

Related to #1642
Replaces #1638
  • Loading branch information
guewen committed Aug 14, 2019
1 parent 639bb47 commit cf3234d
Showing 1 changed file with 13 additions and 3 deletions.
16 changes: 13 additions & 3 deletions base_exception/models/base_exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,18 +103,28 @@ def detect_exceptions(self):
rules = self.env['exception.rule'].sudo().search(
self._rule_domain())
all_exception_ids = []
rules_to_remove = {}
rules_to_add = {}
for rule in rules:
records_with_exception = self._detect_exceptions(rule)
reverse_field = self._reverse_field()
main_records = self._get_main_records()
commons = main_records & rule[reverse_field]
to_remove = commons - records_with_exception
to_add = records_with_exception - commons
to_remove_list = [(3, x.id, _) for x in to_remove]
to_add_list = [(4, x.id, _) for x in to_add]
rule.write({reverse_field: to_remove_list + to_add_list})
# we expect to always work on the same model type
rules_to_remove.setdefault(
rule.id, main_records.browse()
).update(to_remove)
rules_to_add.setdefault(
rule.id, main_records.browse()
).update(to_add)
if records_with_exception:
all_exception_ids.append(rule.id)
for rule_id, records in rules_to_remove.iteritems():
records.write({'exception_ids': [(3, rule_id,)]})
for rule_id, records in rules_to_add.iteritems():
records.write(({'exception_ids': [(4, rule_id,)]}))
return all_exception_ids

@api.model
Expand Down

0 comments on commit cf3234d

Please sign in to comment.