From e54441409ed1edeb5947eb340805087f3b3d8114 Mon Sep 17 00:00:00 2001 From: Christophe Simonis <> Date: Fri, 14 May 2010 14:41:43 +0530 Subject: [PATCH] [IMP] orm: allow import and record creation to defer the computation of parent_left/right,[IMP] orm: do not update parent_left/right if the parent haven't been changed bzr revid: jvo@tinyerp.com-20100514091143-sl731yzxbw12c058 --- bin/osv/orm.py | 92 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 30 deletions(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index efa31fddc50..e21dd9f500d 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -49,6 +49,7 @@ import string import sys import time import traceback +import datetime import types import fields @@ -58,6 +59,7 @@ from tools.translate import _ import copy import sys +import operator try: from lxml import etree @@ -86,7 +88,6 @@ def last_day_of_current_month(): def intersect(la, lb): return filter(lambda x: x in lb, la) - class except_orm(Exception): def __init__(self, name, value): self.name = name @@ -997,6 +998,8 @@ class orm_template(object): data = pickle.load(file(config.get('import_partial'))) data[filename] = initial_size - len(datas) + original_value pickle.dump(data, file(config.get('import_partial'),'wb')) + if context.get('defer_parent_store_computation'): + self._parent_store_compute(cr) cr.commit() #except Exception, e: @@ -1010,6 +1013,8 @@ class orm_template(object): # # TODO: Send a request with the result and multi-thread ! # + if context.get('defer_parent_store_computation'): + self._parent_store_compute(cr) return (done, 0, 0, 0) def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'): @@ -2119,6 +2124,8 @@ class orm(orm_template): return (tables, where_clause) def _parent_store_compute(self, cr): + if not self._parent_store: + return logger = netsvc.Logger() logger.notifyChannel('orm', netsvc.LOG_INFO, 'Computing parent left and right for table %s...' % (self._table, )) def browse_rec(root, pos=0): @@ -2207,7 +2214,7 @@ class orm(orm_template): logger.notifyChannel('orm', netsvc.LOG_ERROR, 'create a column parent_left on object %s: fields.integer(\'Left Parent\', select=1)' % (self._table, )) if 'parent_right' not in self._columns: logger.notifyChannel('orm', netsvc.LOG_ERROR, 'create a column parent_right on object %s: fields.integer(\'Right Parent\', select=1)' % (self._table, )) - if self._columns[self._parent_name].ondelete<>'cascade': + if self._columns[self._parent_name].ondelete != 'cascade': logger.notifyChannel('orm', netsvc.LOG_ERROR, "The column %s on object %s must be set as ondelete='cascade'" % (self._parent_name, self._name)) cr.execute('ALTER TABLE "%s" ADD COLUMN "parent_left" INTEGER' % (self._table,)) cr.execute('ALTER TABLE "%s" ADD COLUMN "parent_right" INTEGER' % (self._table,)) @@ -3098,6 +3105,24 @@ class orm(orm_template): self.pool.get('ir.model.access').check(cr, user, self._name, 'write', context=context) + # No direct update of parent_left/right + vals.pop('parent_left', None) + vals.pop('parent_right', None) + + parents_changed = [] + if self._parent_store and (self._parent_name in vals): + # The parent_left/right computation may take up to + # 5 seconds. No need to recompute the values if the + # parent is the same. Get the current value of the parent + base_query = 'SELECT id FROM %s WHERE id IN %%s AND %s' % \ + (self._table, self._parent_name) + params = (tuple(ids),) + parent_val = vals[self._parent_name] + if parent_val: + cr.execute(base_query + " != %s", params + (parent_val,)) + else: + cr.execute(base_query + " IS NULL", params) + parents_changed = map(operator.itemgetter(0), cr.fetchall()) upd0 = [] upd1 = [] @@ -3187,41 +3212,48 @@ class orm(orm_template): self.pool.get(table).write(cr, user, nids, v, context) self._validate(cr, user, ids, context) -# TODO: use _order to set dest at the right position and not first node of parent - if self._parent_store and (self._parent_name in vals): + + # TODO: use _order to set dest at the right position and not first node of parent + # We can't defer parent_store computation because the stored function + # fields that are computer may refer (directly or indirectly) to + # parent_left/right (via a child_of domain) + if parents_changed: if self.pool._init: self.pool._init_parent[self._name]=True else: - for id in ids: - # Find Position of the element - if vals[self._parent_name]: - cr.execute('select parent_left,parent_right,id from '+self._table+' where '+self._parent_name+'=%s order by '+(self._parent_order or self._order), (vals[self._parent_name],)) - else: - cr.execute('select parent_left,parent_right,id from '+self._table+' where '+self._parent_name+' is null order by '+(self._parent_order or self._order)) - result_p = cr.fetchall() - position = None - for (pleft,pright,pid) in result_p: - if pid == id: - break - position = pright+1 + order = self._parent_order or self._order + parent_val = vals[self._parent_name] + if parent_val: + clause, params = '%s=%%s' % (self._parent_name,), (parent_val,) + else: + clause, params = '%s IS NULL' % (self._parent_name,), () + cr.execute('SELECT parent_right, id FROM %s WHERE %s ORDER BY %s' % (self._table, clause, order), params) + parents = cr.fetchall() - # It's the first node of the parent: position = parent_left+1 - if not position: - if not vals[self._parent_name]: - position = 1 - else: - cr.execute('select parent_left from '+self._table+' where id=%s', (vals[self._parent_name],)) - position = cr.fetchone()[0]+1 - - # We have the new position ! - cr.execute('select parent_left,parent_right from '+self._table+' where id=%s', (id,)) - pleft,pright = cr.fetchone() + for id in parents_changed: + cr.execute('SELECT parent_left, parent_right FROM %s WHERE id=%%s' % (self._table,), (id,)) + pleft, pright = cr.fetchone() distance = pright - pleft + 1 - if position>pleft and position<=pright: + # Find Position of the element + position = None + for (parent_pright, parent_id) in parents: + if parent_id == id: + break + position = parent_pright+1 + + # It's the first node of the parent + if not position: + if not parent_val: + position = 1 + else: + cr.execute('select parent_left from '+self._table+' where id=%s', (parent_val,)) + position = cr.fetchone()[0]+1 + + if pleft < position <= pright: raise except_orm(_('UserError'), _('Recursivity Detected.')) - if pleft=%s', (distance, position)) cr.execute('update '+self._table+' set parent_right=parent_right+%s where parent_right>=%s', (distance, position)) cr.execute('update '+self._table+' set parent_left=parent_left+%s, parent_right=parent_right+%s where parent_left>=%s and parent_left<%s', (position-pleft,position-pleft, pleft, pright)) @@ -3402,7 +3434,7 @@ class orm(orm_template): self.check_access_rule(cr, user, [id_new], 'create', context=context) upd_todo.sort(lambda x, y: self._columns[x].priority-self._columns[y].priority) - if self._parent_store: + if self._parent_store and not context.get('defer_parent_store_computation'): if self.pool._init: self.pool._init_parent[self._name]=True else: