Tag caching, at last

Greg Ward greg-hg at gerg.ca
Sun Jul 12 16:12:46 CDT 2009


On Sat, Jul 11, 2009 at 1:06 PM, Dan Villiom Podlaski
Christiansen<danchr at gmail.com> wrote:
> On 10/07/2009, at 17.34, Greg Ward wrote:
>
>>       # Optimization #1: if the first head == current tip, there have
>>       # been new changesets since the cache was written.  All we need
>>       # to do is read .hgtags from each head, and that's up to our
>>       # caller (localrepo._findglobaltags()).
>>       if goodheads and goodheads[0] == repo.changelog.tip():
>>           #ui.debug("tag cache: tip not changed, so cache is
>> up-to-date\n")
>>           return (goodheads, cachefnode)
>
>
> I don't quite understand why this check is sufficient. If I understand the
> code and comment correctly, the logic goes something like this: Whenever tip
> is equal to our cached tip, our cache is correct.

You understand correctly so far.  There are various things that can
cause tip to change:
  * normal linear commit
  * merge commit
  * pull
  * push

...but they are all basically the same: 1 (2) existing head(s) is
(are) replaced by 1 new head.  No tag info is destroyed, merely
augmented: reading .hgtags from the new head and ignoring it on the
replaced head(s) is the right thing to do.

> It would seem to me that
> the assumption doesn't hold. Both ‘rollback’ and ‘strip’ can break this,\

You're right that rollback and strip are tricky.  They both can
destroy tag info, and may or may not expose older heads.  (If you pull
in a branch rooted off an old changeset, that adds tag info.  Rollback
the pull or strip the branch, though, and the head count simply drops
by one.  The tag cache must handle this case.)

There is a subtle difference: rollback is guaranteed to change tip (it
always destroys the changeset(s) that appeared in the last
transaction), whereas strip *can* change tip.  (Hmmm: strip is
guaranteed to change the rev num of tip, though.  And I *think* that
my tag cache is OK with that.)

Now, this all sounds complicated and error prone.  And it is, if we
try to cache the content of .hgtags across all heads.  So I gave up on
doing that.  By caching only the head->.hgtags filenode mapping,
handling strip and rollback becomes easy: ignore heads that are in the
cache but no longer in the repo.  In fact, we *have* to ignore them,
or we'll get a LookupError when we try to read .hgtags from that head.
 And that's exactly what my tag cache does.  (Since we're no longer
caching .hgtags content, we have to read it from all relevant heads.)

> especially if you combine them with the pushing and pulling of changesets.
>
> Imagine two layouts like this:
>
>     r1: A
>      / \
>   r2: B \
>          \
>        r3: C
>
>   r1: A
>    / \
>   / r2: D
>  /
> r3: C

Not sure what you're trying to convey here.  Was that supposed to be
two states of the same repo that could trip up tag caching?  Please,
take your best shot and try to trip it up... but I don't understand
this example.

Greg



More information about the Mercurial-devel mailing list