[schema] Avoid parsing RQL expressions twice on schema loading
authorPhilippe Pepiot <philippe.pepiot@logilab.fr>
Tue, 07 Jun 2016 12:04:21 +0200
changeset 11343 892e4c12f03f
parent 11342 62a7100d774b
child 11344 847ab4bdd985
[schema] Avoid parsing RQL expressions twice on schema loading Kill full_rql (unnecessary) Use snippet_rql rather than rqlst when possible Don't access to rqlst cachedproperty from __init__ Deserializing schema is ~40% faster with a lot (> 4000) expressions like those generated by cubicweb-container.
cubicweb/schema.py
--- a/cubicweb/schema.py	Wed Jun 22 10:22:37 2016 +0200
+++ b/cubicweb/schema.py	Tue Jun 07 12:04:21 2016 +0200
@@ -201,9 +201,7 @@
     # only defining here to prevent pylint from complaining
     info = warning = error = critical = exception = debug = lambda msg,*a,**kw: None
     # to be defined in concrete classes
-    rqlst = None
     predefined_variables = None
-    full_rql = None
 
     def __init__(self, expression, mainvars, eid):
         """
@@ -221,30 +219,24 @@
         self.mainvars = mainvars
         self.expression = normalize_expression(expression)
         try:
-            self.full_rql = self.rqlst.as_string()
+            # syntax tree used by read security (inserted in queries when necessary)
+            self.snippet_rqlst = parse(self.minimal_rql, print_errors=False).children[0]
         except RQLSyntaxError:
             raise RQLSyntaxError(expression)
         for mainvar in mainvars:
-            # if variable is predefined, an extra reference is inserted
-            # automatically (`VAR eid %(v)s`)
-            if mainvar in self.predefined_variables:
-                min_refs = 3
-            else:
-                min_refs = 2
-            if len(self.rqlst.defined_vars[mainvar].references()) < min_refs:
+            if len(self.snippet_rqlst.defined_vars[mainvar].references()) < 2:
                 _LOGGER.warn('You did not use the %s variable in your RQL '
                              'expression %s', mainvar, self)
-        # syntax tree used by read security (inserted in queries when necessary)
-        self.snippet_rqlst = parse(self.minimal_rql, print_errors=False).children[0]
         # graph of links between variables, used by rql rewriter
-        self.vargraph = vargraph(self.rqlst)
+        self.vargraph = vargraph(self.snippet_rqlst)
         # useful for some instrumentation, e.g. localperms permcheck command
         self.package = ybo.PACKAGE
 
     def __str__(self):
-        return self.full_rql
+        return self.rqlst.as_string()
+
     def __repr__(self):
-        return '%s(%s)' % (self.__class__.__name__, self.full_rql)
+        return '%s(%s)' % (self.__class__.__name__, self.expression)
 
     def __lt__(self, other):
         if hasattr(other, 'expression'):
@@ -339,7 +331,7 @@
                 pass
         rql, has_perm_defs, keyarg = self.transform_has_permission()
         # when creating an entity, expression related to X satisfied
-        if creating and 'X' in self.rqlst.defined_vars:
+        if creating and 'X' in self.snippet_rqlst.defined_vars:
             return True
         if keyarg is None:
             kwargs.setdefault('u', _cw.user.eid)
@@ -404,7 +396,7 @@
         RQLExpression.__init__(self, expression, mainvars or 'X', eid)
 
     def check(self, _cw, eid=None, creating=False, **kwargs):
-        if 'X' in self.rqlst.defined_vars:
+        if 'X' in self.snippet_rqlst.defined_vars:
             if eid is None:
                 if creating:
                     return self._check(_cw, creating=True, **kwargs)
@@ -479,11 +471,11 @@
 
     def check(self, _cw, fromeid=None, toeid=None):
         kwargs = {}
-        if 'S' in self.rqlst.defined_vars:
+        if 'S' in self.snippet_rqlst.defined_vars:
             if fromeid is None:
                 return False
             kwargs['s'] = fromeid
-        if 'O' in self.rqlst.defined_vars:
+        if 'O' in self.snippet_rqlst.defined_vars:
             if toeid is None:
                 return False
             kwargs['o'] = toeid
@@ -1251,7 +1243,7 @@
         else:
             expression = 'S eid %(s)s, O eid %(o)s, ' + self.expression
             args = {'s': eidfrom, 'o': eidto}
-        if 'U' in self.rqlst.defined_vars:
+        if 'U' in self.snippet_rqlst.defined_vars:
             expression = 'U eid %(u)s, ' + expression
             args['u'] = _cw.user.eid
         rql = 'Any %s WHERE %s' % (','.join(sorted(self.mainvars)), expression)