[IMP] fields: speedup of `convert_to_cache` for x2many fields

The algorithm's complexity changed from O(n²) to O(n).
This commit is contained in:
Raphael Collet 2015-06-30 16:23:16 +02:00
parent 9e8d29c986
commit 0939738479
2 changed files with 28 additions and 18 deletions

View File

@ -30,7 +30,7 @@ import logging
import pytz
import xmlrpclib
from openerp.tools import float_round, frozendict, html_sanitize, ustr
from openerp.tools import float_round, frozendict, html_sanitize, ustr, OrderedSet
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as DATE_FORMAT
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT as DATETIME_FORMAT
@ -1606,34 +1606,33 @@ class _RelationalMulti(_Relational):
return value.with_env(record.env)
elif isinstance(value, list):
# value is a list of record ids or commands
if not record.id:
record = record.browse() # new record has no value
result = record[self.name]
# modify result with the commands;
# beware to not introduce duplicates in result
comodel = record.env[self.comodel_name]
ids = OrderedSet(record[self.name].ids)
# modify ids with the commands
for command in value:
if isinstance(command, (tuple, list)):
if command[0] == 0:
result += result.new(command[2])
ids.add(comodel.new(command[2]).id)
elif command[0] == 1:
result.browse(command[1]).update(command[2])
result += result.browse(command[1]) - result
comodel.browse(command[1]).update(command[2])
ids.add(command[1])
elif command[0] == 2:
# note: the record will be deleted by write()
result -= result.browse(command[1])
ids.discard(command[1])
elif command[0] == 3:
result -= result.browse(command[1])
ids.discard(command[1])
elif command[0] == 4:
result += result.browse(command[1]) - result
ids.add(command[1])
elif command[0] == 5:
result = result.browse()
ids.clear()
elif command[0] == 6:
result = result.browse(command[2])
ids = OrderedSet(command[2])
elif isinstance(command, dict):
result += result.new(command)
ids.add(comodel.new(command).id)
else:
result += result.browse(command) - result
return result
ids.add(command)
# return result as a recordset
return comodel.browse(list(ids))
elif not value:
return self.null(record.env)
raise ValueError("Wrong value for %s: %s" % (self, value))

View File

@ -37,7 +37,7 @@ import threading
import time
import werkzeug.utils
import zipfile
from collections import defaultdict, Mapping
from collections import defaultdict, Mapping, OrderedDict
from datetime import datetime
from itertools import islice, izip, groupby
from lxml import etree
@ -1271,6 +1271,17 @@ class frozendict(dict):
def update(self, *args, **kwargs):
raise NotImplementedError("'update' not supported on frozendict")
class OrderedSet(OrderedDict):
""" A simple collection that remembers the elements insertion order. """
def __init__(self, seq=()):
super(OrderedSet, self).__init__([(x, None) for x in seq])
def add(self, elem):
self[elem] = None
def discard(self, elem):
self.pop(elem, None)
@contextmanager
def ignore(*exc):
try: