# HG changeset patch # User Sylvain Thénault <sylvain.thenault@logilab.fr> # Date 1269450319 -3600 # Wed Mar 24 18:05:19 2010 +0100 # Node ID 9661f74aed0daf5669ea51469814ccb508e355ff # Parent ce3274a74fbafebbdf24bee46fac77a5b91195b5 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 diff --git a/__init__.py b/__init__.py --- a/__init__.py +++ b/__init__.py @@ -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 diff --git a/nodes.py b/nodes.py --- a/nodes.py +++ b/nodes.py @@ -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']: diff --git a/stcheck.py b/stcheck.py --- a/stcheck.py +++ b/stcheck.py @@ -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):