# HG changeset patch # User Sylvain Thénault # Date 1302123159 -7200 # Node ID b2c45b7396fbcfd39b41d5a9b4968c0441388dd0 # Parent 287f2273917f6c8f96718b2ea2ccf45d780e0019 [ms planner] use an index to avoid doing the same step twice diff -r 287f2273917f -r b2c45b7396fb server/msplanner.py --- a/server/msplanner.py Wed Apr 06 16:00:56 2011 +0200 +++ b/server/msplanner.py Wed Apr 06 22:52:39 2011 +0200 @@ -1223,11 +1223,22 @@ def build_non_final_part(self, select, solindices, sources, insertedvars, table): """non final step, will have to store results in a temporary table""" + inputmapkey = tuple(sorted(solindices)) solutions = [self._solutions[i] for i in solindices] - rqlst = self.plan.finalize(select, solutions, insertedvars) - step = FetchStep(self.plan, rqlst, sources, table, False) + # XXX be smarter vs rql comparison + idx_key = (select.as_string(), inputmapkey, + tuple(sorted(sources)), tuple(sorted(insertedvars))) + try: + # if a similar step has already been process, simply backport its + # input map + step = self.plan.ms_steps_idx[idx_key] + except KeyError: + # processing needed + rqlst = self.plan.finalize(select, solutions, insertedvars) + step = FetchStep(self.plan, rqlst, sources, table, False) + self.plan.ms_steps_idx[idx_key] = step + self.plan.add_step(step) # update input map for following steps, according to processed solutions - inputmapkey = tuple(sorted(solindices)) inputmap = self._inputmaps.setdefault(inputmapkey, {}) for varname, mapping in step.outputmap.iteritems(): if varname in inputmap and not '.' in varname and \ @@ -1235,7 +1246,6 @@ self._schema.eschema(solutions[0][varname]).final): self._conflicts.append((varname, inputmap[varname])) inputmap.update(step.outputmap) - self.plan.add_step(step) class MSPlanner(SSPlanner): @@ -1259,6 +1269,7 @@ print 'PLANNING', rqlst ppis = [PartPlanInformation(plan, select, self.rqlhelper) for select in rqlst.children] + plan.ms_steps_idx = {} steps = self._union_plan(plan, ppis) if server.DEBUG & server.DBG_MS: from pprint import pprint diff -r 287f2273917f -r b2c45b7396fb server/test/unittest_msplanner.py --- a/server/test/unittest_msplanner.py Wed Apr 06 16:00:56 2011 +0200 +++ b/server/test/unittest_msplanner.py Wed Apr 06 22:52:39 2011 +0200 @@ -2383,6 +2383,56 @@ None, None, [self.system], {}, [])], {'x': 999999, 'u': 999998}) + def test_nonregr_similar_subquery(self): + repo._type_source_cache[999999] = ('Personne', 'system', 999999) + self._test('Any T,TD,U,T,UL WITH T,TD,U,UL BEING (' + '(Any T,TD,U,UL WHERE X eid %(x)s, T comments X, T content TD, T created_by U?, U login UL)' + ' UNION ' + '(Any T,TD,U,UL WHERE X eid %(x)s, X connait P, T comments P, T content TD, T created_by U?, U login UL))', + # XXX optimization: use a OneFetchStep with a UNION of both queries + [('FetchStep', [('Any U,UL WHERE U login UL, U is CWUser', + [{'U': 'CWUser', 'UL': 'String'}])], + [self.ldap, self.system], None, + {'U': 'table0.C0', 'U.login': 'table0.C1', 'UL': 'table0.C1'}, + []), + ('UnionFetchStep', + [('FetchStep', + [('Any T,TD,U,UL WHERE T comments 999999, T content TD, T created_by U?, U login UL, T is Comment, U is CWUser', + [{'T': 'Comment', 'TD': 'String', 'U': 'CWUser', 'UL': 'String'}])], + [self.system], + {'U': 'table0.C0', 'U.login': 'table0.C1', 'UL': 'table0.C1'}, + {'T': 'table1.C0', + 'T.content': 'table1.C1', + 'TD': 'table1.C1', + 'U': 'table1.C2', + 'U.login': 'table1.C3', + 'UL': 'table1.C3'}, + []), + ('FetchStep', + [('Any T,TD,U,UL WHERE 999999 connait P, T comments P, T content TD, T created_by U?, U login UL, P is Personne, T is Comment, U is CWUser', + [{'P': 'Personne', + 'T': 'Comment', + 'TD': 'String', + 'U': 'CWUser', + 'UL': 'String'}])], + [self.system], + {'U': 'table0.C0', 'U.login': 'table0.C1', 'UL': 'table0.C1'}, + {'T': 'table1.C0', + 'T.content': 'table1.C1', + 'TD': 'table1.C1', + 'U': 'table1.C2', + 'U.login': 'table1.C3', + 'UL': 'table1.C3'}, + [])]), + ('OneFetchStep', + [('Any T,TD,U,T,UL', + [{'T': 'Comment', 'TD': 'String', 'U': 'CWUser', 'UL': 'String'}])], + None, None, + [self.system], + {'T': 'table1.C0', 'TD': 'table1.C1', 'U': 'table1.C2', 'UL': 'table1.C3'}, + [])], + {'x': 999999}) + class MSPlannerTwoSameExternalSourcesTC(BasePlannerTC): """test planner related feature on a 3-sources repository: