[IMP] fields: use a "lazy" cursor to compute attribute digits
Borrowing a cursor each time you access `field.digits` may be costly, because of the connection reset. Moreover, in most cases, the cursor is not used at all, since the decimal precision are kept in cache. For the installation of module `product` with its demo data, the number of cursor allocations was reduced from ~1500 to about 50!
This commit is contained in:
+3
-2
@@ -30,6 +30,7 @@ import logging
|
||||
import pytz
|
||||
import xmlrpclib
|
||||
|
||||
from openerp.sql_db import LazyCursor
|
||||
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
|
||||
@@ -1070,7 +1071,7 @@ class Float(Field):
|
||||
@property
|
||||
def digits(self):
|
||||
if callable(self._digits):
|
||||
with fields._get_cursor() as cr:
|
||||
with LazyCursor() as cr:
|
||||
return self._digits(cr)
|
||||
else:
|
||||
return self._digits
|
||||
@@ -1882,7 +1883,7 @@ class Id(Field):
|
||||
raise TypeError("field 'id' cannot be assigned")
|
||||
|
||||
# imported here to avoid dependency cycle issues
|
||||
from openerp import SUPERUSER_ID, registry
|
||||
from openerp import SUPERUSER_ID
|
||||
from .exceptions import Warning, AccessError, MissingError
|
||||
from .models import BaseModel, MAGIC_COLUMNS
|
||||
from .osv import fields
|
||||
|
||||
@@ -43,21 +43,18 @@ import pytz
|
||||
import re
|
||||
import xmlrpclib
|
||||
from operator import itemgetter
|
||||
from contextlib import contextmanager
|
||||
from psycopg2 import Binary
|
||||
|
||||
import openerp
|
||||
import openerp.tools as tools
|
||||
from openerp.sql_db import LazyCursor
|
||||
from openerp.tools.translate import _
|
||||
from openerp.tools import float_repr, float_round, frozendict, html_sanitize
|
||||
import simplejson
|
||||
from openerp import SUPERUSER_ID, registry
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
@contextmanager
|
||||
def _get_cursor():
|
||||
# yield a valid cursor from any environment or create a new one if none found
|
||||
with registry().cursor() as cr:
|
||||
yield cr
|
||||
# deprecated; kept for backward compatibility only
|
||||
_get_cursor = LazyCursor
|
||||
|
||||
EMPTY_DICT = frozendict()
|
||||
|
||||
@@ -396,7 +393,7 @@ class float(_column):
|
||||
@property
|
||||
def digits(self):
|
||||
if self._digits_compute:
|
||||
with _get_cursor() as cr:
|
||||
with LazyCursor() as cr:
|
||||
return self._digits_compute(cr)
|
||||
else:
|
||||
return self._digits
|
||||
@@ -1323,7 +1320,7 @@ class function(_column):
|
||||
@property
|
||||
def digits(self):
|
||||
if self._digits_compute:
|
||||
with _get_cursor() as cr:
|
||||
with LazyCursor() as cr:
|
||||
return self._digits_compute(cr)
|
||||
else:
|
||||
return self._digits
|
||||
|
||||
@@ -443,6 +443,40 @@ class TestCursor(Cursor):
|
||||
self.execute("ROLLBACK TO SAVEPOINT test_cursor")
|
||||
self.execute("SAVEPOINT test_cursor")
|
||||
|
||||
class LazyCursor(object):
|
||||
""" A proxy object to a cursor. The cursor itself is allocated only if it is
|
||||
needed. This class is useful for cached methods, that use the cursor
|
||||
only in the case of a cache miss.
|
||||
"""
|
||||
def __init__(self, dbname=None):
|
||||
self._dbname = dbname
|
||||
self._cursor = None
|
||||
self._depth = 0
|
||||
|
||||
@property
|
||||
def dbname(self):
|
||||
return self._dbname or threading.currentThread().dbname
|
||||
|
||||
def __getattr__(self, name):
|
||||
cr = self._cursor
|
||||
if cr is None:
|
||||
from openerp import registry
|
||||
cr = self._cursor = registry(self.dbname).cursor()
|
||||
for _ in xrange(self._depth):
|
||||
cr.__enter__()
|
||||
return getattr(cr, name)
|
||||
|
||||
def __enter__(self):
|
||||
self._depth += 1
|
||||
if self._cursor is not None:
|
||||
self._cursor.__enter__()
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self._depth -= 1
|
||||
if self._cursor is not None:
|
||||
self._cursor.__exit__(exc_type, exc_value, traceback)
|
||||
|
||||
class PsycoConnection(psycopg2.extensions.connection):
|
||||
pass
|
||||
|
||||
|
||||
Reference in New Issue
Block a user