changeset eab80eaced1d in modules/stock:default
details: https://hg.tryton.org/modules/stock?cmd=changeset;node=eab80eaced1d
description:
        Run multiple lock queries for large number of locations

        Also reduce the assign_try method size by externalise the lock 
mechanism, this
        will also allow to customize it.

        issue9326
        review307581002
diffstat:

 move.py |  82 ++++++++++++++++++++++++++++++++++++++--------------------------
 1 files changed, 49 insertions(+), 33 deletions(-)

diffs (113 lines):

diff -r 0450247ff6fb -r eab80eaced1d move.py
--- a/move.py   Tue May 19 18:43:47 2020 +0200
+++ b/move.py   Tue May 19 18:45:29 2020 +0200
@@ -15,7 +15,7 @@
 from trytond.model import Workflow, Model, ModelView, ModelSQL, fields, Check
 from trytond.model.exceptions import AccessError
 from trytond.pyson import Eval, If, Bool
-from trytond.tools import reduce_ids
+from trytond.tools import reduce_ids, grouped_slice
 from trytond.transaction import Transaction
 from trytond.pool import Pool
 
@@ -785,10 +785,6 @@
         Uom = pool.get('product.uom')
         Date = pool.get('ir.date')
         Location = pool.get('stock.location')
-        Period = pool.get('stock.period')
-        transaction = Transaction()
-        database = transaction.database
-        connection = transaction.connection
 
         if not moves:
             return True
@@ -805,34 +801,9 @@
         companies = {m.company for m in moves}
         stock_date_end = Date.today()
 
-        if database.has_select_for():
-            for company in companies:
-                table = cls.__table__()
-                query = table.select(Literal(1),
-                    where=(table.to_location.in_(location_ids)
-                        | table.from_location.in_(location_ids))
-                    & table.product.in_(product_ids)
-                    & (table.company == company.id),
-                    for_=For('UPDATE', nowait=True))
-
-                PeriodCache = Period.get_cache(grouping)
-                if PeriodCache:
-                    periods = Period.search([
-                            ('date', '<', stock_date_end),
-                            ('company', '=', company.id),
-                            ('state', '=', 'closed'),
-                            ], order=[('date', 'DESC')], limit=1)
-                    if periods:
-                        period, = periods
-                        query.where &= Coalesce(
-                            table.effective_date,
-                            table.planned_date,
-                            datetime.date.max) > period.date
-
-                with connection.cursor() as cursor:
-                    cursor.execute(*query)
-        else:
-            database.lock(connection, cls._table)
+        cls._assign_try_lock(
+            product_ids, location_ids, [c.id for c in companies],
+            stock_date_end, grouping)
 
         pblc = {}
         for company in companies:
@@ -931,6 +902,51 @@
         return success
 
     @classmethod
+    def _assign_try_lock(
+            cls, product_ids, location_ids, company_ids, date, grouping):
+        """Lock the database to prevent concurrent assignation"""
+        pool = Pool()
+        Period = pool.get('stock.period')
+        transaction = Transaction()
+        database = transaction.database
+        connection = transaction.connection
+
+        if database.has_select_for():
+            count = database.IN_MAX // 2
+            PeriodCache = Period.get_cache(grouping)
+            with connection.cursor() as cursor:
+                for company_id in company_ids:
+                    period = None
+                    if PeriodCache:
+                        periods = Period.search([
+                                ('date', '<', date),
+                                ('company', '=', company_id),
+                                ('state', '=', 'closed'),
+                                ], order=[('date', 'DESC')], limit=1)
+                        if periods:
+                            period, = periods
+                    for sub_location_ids in grouped_slice(location_ids, count):
+                        sub_location_ids = list(sub_location_ids)
+                        table = cls.__table__()
+                        query = table.select(Literal(1),
+                            where=(reduce_ids(
+                                    table.to_location, sub_location_ids)
+                                | reduce_ids(
+                                    table.from_location, sub_location_ids))
+                            & table.product.in_(product_ids)
+                            & (table.company == company_id),
+                            for_=For('UPDATE', nowait=True))
+
+                        if period:
+                            query.where &= Coalesce(
+                                table.effective_date,
+                                table.planned_date,
+                                datetime.date.max) > period.date
+                        cursor.execute(*query)
+        else:
+            database.lock(connection, cls._table)
+
+    @classmethod
     def compute_quantities_query(cls, location_ids, with_childs=False,
             grouping=('product',), grouping_filter=None):
         """

Reply via email to