[FIX] orm.browse_record: access error due to prefetch of indirectly referenced records (OPW #596679)

The browse_record prefetching algorithm attempts to
load data for all known records from the requested
model (i.e. all IDs present in the browse cache),
regardless of how indirectly/remotely they were
referenced. An indirect parent record may therefore
be prefetched along with its directly browsed children,
possibly crossing company boundaries involuntarily.

This patch implements a fallback mechanism when
the prefetching failed due to what looks like an
ACL restriction. This being a fuzzy concept at the
moment, it does its best to only catch a restricted
set of exceptions, and retry loading the data for
the directly requested ID only.

This may cause a small performance penalty in case
of real errors (with some spurious logging too),
but should only be triggered in very few cases.

The downside when this happens is that the prefetching for that
model gets effectively disabled, requiring multiple
SQL queries for further access to the data of
the other directly browsed records.

This EAFP approach seems safer and faster than
a LBYL technique where we would have to filter
all indirect m2o references according to ACLs
before allowing them to enter the cache.

lp bug: https://launchpad.net/bugs/1238042 fixed
lp bug: https://launchpad.net/bugs/1212429 fixed

bzr revid: odo@openerp.com-20131120100627-031fljyf4ckprc9b
This commit is contained in:
Olivier Dony 2013-11-20 11:06:27 +01:00
parent da00eab39a
commit b7865502e4
1 changed files with 9 additions and 1 deletions

View File

@ -398,7 +398,15 @@ class browse_record(object):
ids = filter(lambda id: name not in self._data[id], self._data.keys())
# read the results
field_names = map(lambda x: x[0], fields_to_fetch)
field_values = self._table.read(self._cr, self._uid, ids, field_names, context=self._context, load="_classic_write")
try:
field_values = self._table.read(self._cr, self._uid, ids, field_names, context=self._context, load="_classic_write")
except (openerp.exceptions.AccessError, except_orm):
if len(ids) == 1:
raise
# prefetching attempt failed, perhaps we're violating ACL restrictions involuntarily
_logger.info('Prefetching attempt for fields %s on %s failed for ids %s, re-trying just for id %s', field_names, self._model._name, ids, self._id)
ids = [self._id]
field_values = self._table.read(self._cr, self._uid, ids, field_names, context=self._context, load="_classic_write")
# TODO: improve this, very slow for reports
if self._fields_process: