|
2 | 2 | # Copyright 2023 Camptocamp SA (http://www.camptocamp.com) |
3 | 3 | # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
4 | 4 | import hashlib |
| 5 | +import logging |
5 | 6 | import struct |
| 7 | +import time |
| 8 | +from functools import partial |
6 | 9 |
|
7 | 10 | from odoo.tools import str2bool |
8 | 11 |
|
9 | 12 | from odoo.addons.component.core import Component |
10 | 13 |
|
| 14 | +_logger = logging.getLogger(__name__) |
| 15 | + |
11 | 16 |
|
12 | 17 | class LockAction(Component): |
13 | 18 | """Provide methods to create database locks""" |
@@ -50,15 +55,46 @@ def for_update(self, records, log_exceptions=False, skip_locked=False): |
50 | 55 | .sudo() |
51 | 56 | .get_param("shopfloor.lock.for_update.no_wait") |
52 | 57 | ) |
| 58 | + |
53 | 59 | for_update_str = " FOR NO KEY UPDATE " if no_key else " FOR UPDATE " |
54 | 60 | query = "SELECT id FROM %s WHERE ID IN %%s " + for_update_str |
| 61 | + |
| 62 | + suffix = "" |
55 | 63 | if skip_locked: |
56 | | - query += " SKIP LOCKED" |
| 64 | + suffix = " SKIP LOCKED" |
57 | 65 | elif no_wait: |
58 | | - query += " NOWAIT" |
| 66 | + suffix = " NOWAIT" |
| 67 | + query += suffix |
| 68 | + |
59 | 69 | sql = query % records._table |
| 70 | + |
| 71 | + with_suffix_str = f" with suffix{suffix}" if suffix else "" |
| 72 | + _logger.debug( |
| 73 | + f"Trying to acquire {for_update_str} lock{with_suffix_str} on " |
| 74 | + f"{records._table} for IDs {sorted(records.ids)}" |
| 75 | + ) |
| 76 | + |
| 77 | + start_time = time.perf_counter() |
| 78 | + |
60 | 79 | self.env.cr.execute(sql, (tuple(records.ids),), log_exceptions=log_exceptions) |
| 80 | + |
| 81 | + end_time = time.perf_counter() |
| 82 | + execute_time = end_time - start_time |
| 83 | + |
| 84 | + rows = self.env.cr.fetchall() |
| 85 | + _logger.debug( |
| 86 | + f"Lock was acquired on {records._table} for IDs " |
| 87 | + f"{sorted([row[0] for row in rows])} in {execute_time:0.4f} seconds" |
| 88 | + ) |
| 89 | + |
| 90 | + self.env.cr.postcommit.add(partial(self._log_lock_release, records)) |
| 91 | + self.env.cr.postrollback.add(partial(self._log_lock_release, records)) |
| 92 | + |
61 | 93 | if skip_locked: |
62 | | - rows = self.env.cr.fetchall() |
63 | 94 | return len(rows) == len(records) |
64 | 95 | return True |
| 96 | + |
| 97 | + def _log_lock_release(self, records): |
| 98 | + _logger.debug( |
| 99 | + f"Lock was released on {records._table} for IDs {sorted(records.ids)}" |
| 100 | + ) |
0 commit comments