[MERGE] Stacked knits
Robert Collins
robertc at robertcollins.net
Tue Jul 1 01:48:06 BST 2008
On Fri, 2008-06-27 at 20:51 +1000, Ian Clatworthy wrote:
Feedback on the queries - I have elided simple to-take actions.
> > for key in keys:
> > + if key in nonlocal_keys:
> > + # already handled
> > + continue
>
> I'm not convinced yet that this if test is the best one. Isn't it possible
> (though unlikely) that an entry in nonlocal_keys won't be found in the
> fallbacks? It would be safer to do 'if key in final_content'. Or I guess
> you could check that missing_keys is indeed empty on exiting the for loop.
if its nonlocal, and not in the fallbacks, its absent altogether and
caught prior to this.
> > + # no need to plan further back
> > + components.append((cursor, None, None, None))
>
> I'm yet to understand why these 2 lines have been added. Can you explain
> it please?
The logic in this loop builds a stack (called components) of things to
delta against to build an output.
Intermediate outputs are cached in a dict.
These two lines allow an externally sourced component to truncate the
build path at a cached component rather than going further.
> > + def _get_parent_map(self, keys):
> > + """Get a map of the parents of keys.
> > +
> > + :param keys: The keys to look up parents for.
> > + :return: A tuple. The first element is a mapping from keys to parents.
> > + Absent keys are absent from the mapping. The second element is a
> > + list with the locations each key was found in. The first element
> > + is the in-this-knit parents, the second the first fallback source,
> > + and so on.
> > + """
>
> I'd prefer this method to be called _get_parent_map_with_sources, say.
Uhm, sure.
> > # missing basis component
> > - result = False
> > + needed_from_fallback.add(chain[-1])
> > + result = True
> > break
> > for chain_key in chain[:-1]:
> > checked_keys[chain_key] = result
> > if not result:
> > - absent_keys.add(key)
> > + needed_from_fallback.add(key)
>
> The changing from 'result = False' to 'result = True' looks like a logic change
> separate to the handling of fallbacks? In particular, checked_keys will contain
> True for some items that previously had False. I need to spend some more time
> understanding this block of code - I'm honestly not sure whether your change
> here is right or wrong. Any hints? :-)
Its not as clearly expressed as perhaps we can make it. We're
essentially delegating the component lookup to the fallback vfs in this
case.
> > + for key in present_keys:
> > + for parent_map in parent_maps:
> > + if key in parent_map:
> > + key_source = parent_map
> > + break
> > + if current_source is not key_source:
> > + source_keys.append((key_source, []))
> > + current_source = key_source
> > + source_keys[-1][1].append(key)
>
> This looks right. The nested for loops scare me wrt performance though I can't
> see how else to write that code.
For 10K keys with 1 fallback repository its:
10K outerloops
2 inner loops
or 20K total steps.
Shouldn't be an issue unless/until someone has hundreds of different
fallback repos - and then it simply reflects reality.
> > + total = len(keys)
> > # we don't care about inclusions, the caller cares.
> > # but we need to setup a list of records to visit.
> > # we need key, position, length
> > key_records = []
> > build_details = self._index.get_build_details(keys)
> > - for key in keys:
> > - key_records.append((key, build_details[key][0]))
> > - total = len(key_records)
> > + for key, details in build_details.iteritems():
> > + if key in keys:
> > + key_records.append((key, details[0]))
> > + keys.remove(key)
>
> I'm ok with changing how the total is calculated as you've done
> but it highlights the fact that progress-bar handling in this
> routine is now only half done. You might want to tweak it a bit, e.g.
> pass it down into the nested call below ...
Pasing it down into the child bars will result in confusing output.
> test_knit.py feedback now ...
>
> > + # lines added to the test that reference across the stack do a
> > + # fulltext.
> > + basis.add_lines(key_basis, (), ['foo\n'])
> > + basis.calls = []
> > + test.add_lines(key_cross_border, (key_basis,), ['foo\n'])
> > + self.assertEqual('fulltext', test._index.get_method(key_cross_border))
> > + self.assertEqual([("get_parent_map", set([key_basis]))], basis.calls)
> > + basis.calls = []
> > + # Subsequent adds do delta.
>
> I think those last two lines should be swapped order wise.
?
> > + raise KnownFailure("Annotation on stacked knits currently fails.")
> > + details = test.annotate(key_basis)
> > + self.assertEqual([(key_basis, 'foo\n'), (key_basis, 'bar\n')], details)
> > + self.assertEqual([("annotate", key_basis)], basis.calls)
>
> I'd like to see those last 3 lines (after the raise) commented out.
Why? This is what we document as 'The right way' to write a known
failure - do a test you want to pass, find where it fails, and raise a
KnownFailure at that point, leaving the rest of the test intact.
-Rob
--
GPG key available at: <http://www.robertcollins.net/keys.txt>.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part
Url : https://lists.ubuntu.com/archives/bazaar/attachments/20080701/2dc8b131/attachment.pgp
More information about the bazaar
mailing list