optimize variable stinfo:
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Wed, 24 Mar 2010 18:05:19 +0100
changeset 519 9661f74aed0d
parent 518 ce3274a74fba
child 523 7f40b201b020
optimize variable stinfo: * uidrels/typerels sets become uidrel/typerel, and raise error if the rql use multiple uid/type restriction for a variable (wasn't properly handled anyway, should use IN) * blocsimplification / optrelations / attrvars set are created only when necessary -> up to 5 less set per variable killed, should improve rql cache memory foot print and somewhat speed-up annotation
__init__.py
nodes.py
stcheck.py
--- a/__init__.py	Wed Mar 24 18:05:18 2010 +0100
+++ b/__init__.py	Wed Mar 24 18:05:19 2010 +0100
@@ -131,9 +131,8 @@
         rewritten = False
         for var in select.defined_vars.values():
             stinfo = var.stinfo
-            if stinfo['constnode'] and not stinfo['blocsimplification']:
-                #assert len(stinfo['uidrels']) == 1, var
-                uidrel = stinfo['uidrels'].pop()
+            if stinfo['constnode'] and not stinfo.get('blocsimplification'):
+                uidrel = stinfo['uidrel']
                 var = uidrel.children[0].variable
                 vconsts = []
                 rhs = uidrel.children[1].children[0]
@@ -167,16 +166,13 @@
                         # drop this relation
                         rel.parent.remove(rel)
                     elif rel.is_types_restriction():
-                        stinfo['typerels'].remove(rel)
-                        rel.parent.remove(rel)
-                    elif rel in stinfo['uidrels']:
-                        # XXX check equivalence not necessary else we wouldn't be here right?
-                        stinfo['uidrels'].remove(rel)
+                        stinfo['typerel'] = None
                         rel.parent.remove(rel)
                     else:
                         rhs = copy_uid_node(select, rhs, vconsts)
                         vref.parent.replace(vref, rhs)
                 del select.defined_vars[var.name]
+                stinfo['uidrel'] = None
                 rewritten = True
                 if vconsts:
                     select.stinfo['rewritten'][var.name] = vconsts
--- a/nodes.py	Wed Mar 24 18:05:18 2010 +0100
+++ b/nodes.py	Wed Mar 24 18:05:19 2010 +0100
@@ -836,33 +836,32 @@
             # relations where this variable is used on the lhs/rhs
             'relations': set(),
             'rhsrelations': set(),
-            'optrelations': set(),
-            # empty if this variable may be simplified (eg not used in optional
-            # relations and no final relations where this variable is used on
-            # the lhs)
-            'blocsimplification': set(),
-            # type relations (e.g. "is") where this variable is used on the lhs
-            'typerels': set(),
-            # uid relations (e.g. "eid") where this variable is used on the lhs
-            'uidrels': set(),
             # selection indexes if any
             'selected': set(),
-            # if this variable is an attribute variable (ie final entity),
-            # link to the (prefered) attribute owner variable
+            # type restriction (e.g. "is" / "is_instance_of") where this
+            # variable is used on the lhs
+            'typerel': None,
+            # uid relations (e.g. "eid") where this variable is used on the lhs
+            'uidrel': None,
+            # if this variable is an attribute variable (ie final entity), link
+            # to the (prefered) attribute owner variable
             'attrvar': None,
-            # set of couple (lhs variable name, relation name) where this
-            # attribute variable is used
-            'attrvars': set(),
             # constant node linked to an uid variable if any
             'constnode': None,
             })
 
+    def add_optional_relation(self, relation):
+        try:
+            self.stinfo['optrelations'].add(relation)
+        except KeyError:
+            self.stinfo['optrelations'] = set((relation,))
+
     def get_type(self, solution=None, kwargs=None):
         """return entity type of this object, 'Any' if not found"""
         if solution:
             return solution[self.name]
-        for rel in self.stinfo['typerels']:
-            return str(rel.children[1].children[0].value)
+        if self.stinfo['typerel']:
+            return str(self.stinfo['typerel'].children[1].children[0].value)
         schema = self.schema
         if schema is not None:
             for rel in self.stinfo['rhsrelations']:
--- a/stcheck.py	Wed Mar 24 18:05:18 2010 +0100
+++ b/stcheck.py	Wed Mar 24 18:05:19 2010 +0100
@@ -24,6 +24,12 @@
     except KeyError:
         return subvarname + str(id(select))
 
+def bloc_simplification(variable, term):
+    try:
+        variable.stinfo['blocsimplification'].add(term)
+    except KeyError:
+        variable.stinfo['blocsimplification'] = set((term,))
+
 
 class GoTo(Exception):
     """Exception used to control the visit of the tree."""
@@ -407,7 +413,6 @@
         pass
 
 
-
 class RQLSTAnnotator(object):
     """Annotate RQL syntax tree to ease further code generation from it.
 
@@ -459,7 +464,7 @@
             # if there is a having clause, bloc simplification of variables used in GROUPBY
             for term in node.groupby:
                 for vref in term.get_nodes(VariableRef):
-                    vref.variable.stinfo['blocsimplification'].add(term)
+                    bloc_simplification(vref.variable, term)
 
     def rewrite_shared_optional(self, exists, var):
         """if variable is shared across multiple scopes, need some tree
@@ -474,29 +479,42 @@
                 vref.unregister_reference()
                 newvref = VariableRef(newvar)
                 vref.parent.replace(vref, newvref)
+                stinfo = var.stinfo
                 # update stinfo structure which may have already been
                 # partially processed
-                if rel in var.stinfo['rhsrelations']:
+                if rel in stinfo['rhsrelations']:
                     lhs, rhs = rel.get_parts()
                     if vref is rhs.children[0] and \
                            self.schema.rschema(rel.r_type).final:
                         update_attrvars(newvar, rel, lhs)
                         lhsvar = getattr(lhs, 'variable', None)
-                        var.stinfo['attrvars'].remove( (lhsvar, rel.r_type) )
-                        if var.stinfo['attrvar'] is lhsvar:
-                            if var.stinfo['attrvars']:
-                                var.stinfo['attrvar'] = iter(var.stinfo['attrvars']).next()
+                        stinfo['attrvars'].remove( (lhsvar, rel.r_type) )
+                        if stinfo['attrvar'] is lhsvar:
+                            if stinfo['attrvars']:
+                                stinfo['attrvar'] = iter(stinfo['attrvars']).next()
                             else:
-                                var.stinfo['attrvar'] = None
-                    var.stinfo['rhsrelations'].remove(rel)
+                                stinfo['attrvar'] = None
+                    stinfo['rhsrelations'].remove(rel)
                     newvar.stinfo['rhsrelations'].add(rel)
-                for stinfokey in ('blocsimplification','typerels', 'uidrels',
-                                  'relations', 'optrelations'):
-                    try:
-                        var.stinfo[stinfokey].remove(rel)
-                        newvar.stinfo[stinfokey].add(rel)
-                    except KeyError:
-                        continue
+                try:
+                    stinfo['relations'].remove(rel)
+                    newvar.stinfo['relations'].add(rel)
+                except KeyError:
+                    pass
+                try:
+                    stinfo['optrelations'].remove(rel)
+                    newvar.add_optional_relation(rel)
+                except KeyError:
+                    pass
+                try:
+                    stinfo['blocsimplification'].remove(rel)
+                    bloc_simplification(newvar, rel)
+                except KeyError:
+                    pass
+                if stinfo['uidrel'] is rel:
+                    newvar.stinfo['uidrel'] = rel
+                if stinfo['typerel'] is rel:
+                    newvar.stinfo['typerel'] = rel
         # shared references
         newvar.stinfo['constnode'] = var.stinfo['constnode']
         if newvar.stmt.solutions: # solutions already computed
@@ -527,10 +545,8 @@
         # may be a constant once rqlst has been simplified
         lhsvar = getattr(lhs, 'variable', None)
         if relation.is_types_restriction():
-            #assert rhs.operator == '='
-            #assert not relation.optional
             if lhsvar is not None:
-                lhsvar.stinfo['typerels'].add(relation)
+                lhsvar.stinfo['typerel'] = relation
             return
         if relation.optional is not None:
             exists = relation.scope
@@ -539,20 +555,20 @@
             if lhsvar is not None:
                 if exists is not None and lhsvar.scope is lhsvar.stmt:
                     lhsvar = self.rewrite_shared_optional(exists, lhsvar)
-                lhsvar.stinfo['blocsimplification'].add(relation)
+                bloc_simplification(lhsvar, relation)
                 if relation.optional == 'both':
-                    lhsvar.stinfo['optrelations'].add(relation)
+                    lhsvar.add_optional_relation(relation)
                 elif relation.optional == 'left':
-                    lhsvar.stinfo['optrelations'].add(relation)
+                    lhsvar.add_optional_relation(relation)
             try:
                 rhsvar = rhs.children[0].variable
                 if exists is not None and rhsvar.scope is rhsvar.stmt:
                     rhsvar = self.rewrite_shared_optional(exists, rhsvar)
-                rhsvar.stinfo['blocsimplification'].add(relation)
+                bloc_simplification(rhsvar, relation)
                 if relation.optional == 'right':
-                    rhsvar.stinfo['optrelations'].add(relation)
+                    rhsvar.add_optional_relation(relation)
                 elif relation.optional == 'both':
-                    rhsvar.stinfo['optrelations'].add(relation)
+                    rhsvar.add_optional_relation(relation)
             except AttributeError:
                 # may have been rewritten as well
                 pass
@@ -570,11 +586,11 @@
                             isinstance(relation.parent, Not)):
                         if isinstance(constnode, Constant):
                             lhsvar.stinfo['constnode'] = constnode
-                        lhsvar.stinfo.setdefault(key, set()).add(relation)
+                        lhsvar.stinfo['uidrel'] = relation
                 else:
                     lhsvar.stinfo.setdefault(key, set()).add(relation)
             elif rschema.final or rschema.inlined:
-                lhsvar.stinfo['blocsimplification'].add(relation)
+                bloc_simplification(lhsvar, relation)
         for vref in rhs.get_nodes(VariableRef):
             var = vref.variable
             var.set_scope(scope)
@@ -586,8 +602,13 @@
 
 
 def update_attrvars(var, relation, lhs):
+    # stinfo['attrvars'] is set of couple (lhs variable name, relation name)
+    # where the `var` attribute variable is used
     lhsvar = getattr(lhs, 'variable', None)
-    var.stinfo['attrvars'].add( (lhsvar, relation.r_type) )
+    try:
+        var.stinfo['attrvars'].add( (lhsvar, relation.r_type) )
+    except KeyError:
+        var.stinfo['attrvars'] = set([(lhsvar, relation.r_type)])
     # give priority to variable which is not in an EXISTS as
     # "main" attribute variable
     if var.stinfo['attrvar'] is None or not isinstance(relation.scope, Exists):