git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH 7/7] Accelerate rename_dst setup

From
Elijah Newren <newren@gmail.com>
Date
Dec 10, 2020, 00:57 UTC
Message-ID
<CABPp-BEhVK9mMsqS-6Yg2ad5nG0=Pm5by80d9nrHKFp2hrMSBw@mail.gmail.com>
In-Reply-To
<X9FXPHUZJAZKSset@nand.local>
On Wed, Dec 9, 2020 at 3:01 PM Taylor Blau <me@ttaylorr.com> wrote:
Show 16 quoted lines
>
> On Sun, Dec 06, 2020 at 02:54:36AM +0000, Elijah Newren via GitGitGadget wrote:
> > diff --git a/diffcore-rename.c b/diffcore-rename.c
> > index 816d2fbac44..fb3c2817c6b 100644
> > --- a/diffcore-rename.c
> > +++ b/diffcore-rename.c
> > @@ -5,67 +5,64 @@
> >  #include "cache.h"
> >  #include "diff.h"
> >  #include "diffcore.h"
> > -#include "object-store.h"
> >  #include "hashmap.h"
> > +#include "object-store.h"
>
> Shuffling around this object-store.h include looks like noise to me, but
> maybe there's a good reason for doing it.

Um, well...I guess I couldn't help myself from alphabetizing the #include list (at least the portion after the initial "cache.h" or "git-compat-util.h" must come first). ;-)

I probably should have done it in a separate patch.
Show 137 quoted lines
> >  #include "progress.h"
> >  #include "promisor-remote.h"
> > +#include "strmap.h"
> >
> >  /* Table of rename/copy destinations */
> >
> >  static struct diff_rename_dst {
> > -     struct diff_filespec *two;
> > -     struct diff_filepair *pair;
> > +     struct diff_filepair *p;
> > +     struct diff_filespec *filespec_to_free;
> > +     int is_rename; /* false -> just a create; true -> rename or copy */
> >  } *rename_dst;
> >  static int rename_dst_nr, rename_dst_alloc;
> > +/* Mapping from break source pathname to break destination index */
> > +static struct strintmap *break_idx = NULL;
> >
> > -static int find_rename_dst(struct diff_filespec *two)
> > -{
> > -     int first, last;
> > -
> > -     first = 0;
> > -     last = rename_dst_nr;
> > -     while (last > first) {
> > -             int next = first + ((last - first) >> 1);
> > -             struct diff_rename_dst *dst = &(rename_dst[next]);
> > -             int cmp = strcmp(two->path, dst->two->path);
> > -             if (!cmp)
> > -                     return next;
> > -             if (cmp < 0) {
> > -                     last = next;
> > -                     continue;
> > -             }
> > -             first = next+1;
> > -     }
> > -     return -first - 1;
> > -}
> > -
> > -static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two)
> > +static struct diff_rename_dst *locate_rename_dst(struct diff_filepair *p)
> >  {
> > -     int ofs = find_rename_dst(two);
> > -     return ofs < 0 ? NULL : &rename_dst[ofs];
> > +     /* Lookup by p->ONE->path */
> > +     int idx = break_idx ? strintmap_get(break_idx, p->one->path) : -1;
>
> I had to lookup the behavior of strintmap_get() to realize that it
> returns the map's "default value" to figure out why this double
> ternary was necessary, but I think that it is.
>
> Ideally, if break_idx is non-NULL, then we ought to be able to immediately
> return NULL, but it's possible that break_idx is non-NULL and simply
> doesn't contain p->one->path, in which case we also want to return NULL.
>
> So, I think this is as clear as it can be.
>
> > +     return (idx == -1) ? NULL : &rename_dst[idx];
> >  }
> >
> >  /*
> >   * Returns 0 on success, -1 if we found a duplicate.
> >   */
> > -static int add_rename_dst(struct diff_filespec *two)
> > +static int add_rename_dst(struct diff_filepair *p)
> >  {
> > -     int first = find_rename_dst(two);
> > -
> > -     if (first >= 0)
> > +     /*
> > +      * See t4058; trees might have duplicate entries.  I think
> > +      * trees with duplicate entries should be ignored and we
> > +      * should just leave rename detection on; while the results
> > +      * may be slightly harder to understand, that's merely a
> > +      * result of the underlying tree making no sense.  But I
> > +      * believe everything still works fine, the results do still
> > +      * make sense, and the extra overhead of doing this checking
> > +      * for a few historical weird trees from long ago seems like
> > +      * the dog wagging the tail to me.
> > +      *
> > +      * However: I don't feel like fighting that battle right now.
> > +      * For now, to keep the regression test passing, we have to
> > +      * detect it.  Since the diff machinery passes these to us in
> > +      * adjacent pairs, we just need to check to see if our name
> > +      * matches the previous one.
> > +      *
> > +      * TODO: Dispense with this test, rip out the test in t4058, and
> > +      * lobby folks for the change.
> > +      */
> > +     if (rename_dst_nr > 0 &&
> > +         !strcmp(rename_dst[rename_dst_nr-1].p->two->path, p->two->path))
> >               return -1;
> > -     first = -first - 1;
> >
> > -     /* insert to make it at "first" */
> >       ALLOC_GROW(rename_dst, rename_dst_nr + 1, rename_dst_alloc);
> > +     rename_dst[rename_dst_nr].p = p;
> > +     rename_dst[rename_dst_nr].filespec_to_free = NULL;
> > +     rename_dst[rename_dst_nr].is_rename = 0;
> >       rename_dst_nr++;
> > -     if (first < rename_dst_nr)
> > -             MOVE_ARRAY(rename_dst + first + 1, rename_dst + first,
> > -                        rename_dst_nr - first - 1);
> > -     rename_dst[first].two = alloc_filespec(two->path);
> > -     fill_filespec(rename_dst[first].two, &two->oid, two->oid_valid,
> > -                   two->mode);
> > -     rename_dst[first].pair = NULL;
> >       return 0;
>
> Very nice, this is much simpler than what was here before.
>
> > @@ -78,6 +75,14 @@ static int rename_src_nr, rename_src_alloc;
> >
> >  static void register_rename_src(struct diff_filepair *p)
> >  {
> > +     if (p->broken_pair) {
> > +             if (!break_idx) {
> > +                     break_idx = xmalloc(sizeof(*break_idx));
> > +                     strintmap_init(break_idx, -1);
> > +             }
> > +             strintmap_set(break_idx, p->one->path, rename_dst_nr);
> > +     }
> > +
>
> Makes sense.
>
> > @@ -664,8 +653,9 @@ void diffcore_rename(struct diff_options *options)
> >                        */
> >                       if (DIFF_PAIR_BROKEN(p)) {
> >                               /* broken delete */
> > -                             struct diff_rename_dst *dst = locate_rename_dst(p->one);
> > -                             if (dst && dst->pair)
> > +                             struct diff_rename_dst *dst = locate_rename_dst(p);
> > +                             assert(dst);
>
> You're not hurting anything, but I'm not convinced that this assert() is
> buying you anything that the line immediately below it isn't already
> doing.

It's identical for runtime correctness, yes. But the primary point isn't what happens at runtime, but what happens when future code readers come along. If I only keep the "if (dst->is_rename)" line that comes after without the assert, then someone in the future will come along (maybe even myself) and think "the original author wasn't being careful here; they should change this to a check on (dst && dst->is_rename)" (because honestly, it is the kind of mistake I'm prone to make). However, if they were to do so, and some bug gets introduced so that locate_rename_dst() returns a NULL for a pair of interest, then they've masked a bug in the algorithm and made it fail in harder-to-detect-and-track-down ways. I wanted it to be clear that dst == NULL is unacceptable. I guess I could have marked it with BUG(), but between an assertion and a NULL-pointer indirection, I figured that code aborting under that condition was pretty well covered. :-)

> The rest of the patch looks good to me.
>
> Thanks,
> Taylor
Previous: Taylor BlauNext: Junio C Hamano
Message 13 of 55 in “diffcore-rename improvements”
  1. 0/7 diffcore-rename improvementsElijah Newren via GitGitGadget, Dec 6, 2020
  2. 4/7 diffcore-rename: change a few comments to use 'add' instead of 'create'Elijah Newren via GitGitGadget, Dec 6, 2020
  3. Junio C HamanoDec 10, 2020
  4. 2/7 diffcore-rename: remove unnecessary if-clauseElijah Newren via GitGitGadget, Dec 6, 2020
  5. Taylor BlauDec 9, 2020
  6. Elijah NewrenDec 10, 2020
  7. Junio C HamanoDec 10, 2020
  8. Elijah NewrenDec 10, 2020
  9. Junio C HamanoDec 10, 2020
  10. Elijah NewrenDec 6, 2020
  11. 7/7 Accelerate rename_dst setupElijah Newren via GitGitGadget, Dec 6, 2020
  12. Taylor BlauDec 9, 2020
  13. Elijah NewrenDec 10, 2020
  14. Junio C HamanoDec 10, 2020
  15. 6/7 diffcore-rename: simplify and accelerate register_rename_src()Elijah Newren via GitGitGadget, Dec 6, 2020
  16. Taylor BlauDec 9, 2020
  17. Elijah NewrenDec 10, 2020
  18. Taylor BlauDec 10, 2020
  19. Junio C HamanoDec 10, 2020
  20. 5/7 diffcore-rename: reduce jumpiness in progress countersElijah Newren via GitGitGadget, Dec 6, 2020
  21. Taylor BlauDec 9, 2020
  22. Junio C HamanoDec 10, 2020
  23. 3/7 diffcore-rename: rename num_create to num_targetsElijah Newren via GitGitGadget, Dec 6, 2020
  24. Junio C HamanoDec 10, 2020
  25. Elijah NewrenDec 10, 2020
  26. 1/7 diffcore-rename: avoid usage of global in too_many_rename_candidates()Elijah Newren via GitGitGadget, Dec 6, 2020
  27. Taylor BlauDec 9, 2020
  28. 0/9 diffcore-rename improvementsElijah Newren via GitGitGadget, Dec 11, 2020
  29. 1/9 diffcore-rename: rename num_create to num_destinationsElijah Newren via GitGitGadget, Dec 11, 2020
  30. 2/9 diffcore-rename: avoid usage of global in too_many_rename_candidates()Elijah Newren via GitGitGadget, Dec 11, 2020
  31. 3/9 diffcore-rename: simplify limit checkElijah Newren via GitGitGadget, Dec 11, 2020
  32. 8/9 diffcore-rename: accelerate rename_dst setupElijah Newren via GitGitGadget, Dec 11, 2020
  33. 7/9 diffcore-rename: simplify and accelerate register_rename_src()Elijah Newren via GitGitGadget, Dec 11, 2020
  34. 4/9 diffcore-rename: reduce jumpiness in progress countersElijah Newren via GitGitGadget, Dec 11, 2020
  35. 9/9 diffcore-rename: remove unneccessary duplicate entry checksElijah Newren via GitGitGadget, Dec 11, 2020
  36. Christian CouderDec 29, 2020
  37. Elijah NewrenDec 29, 2020
  38. 5/9 t4058: add more tests and documentation for duplicate tree entry handlingElijah Newren via GitGitGadget, Dec 11, 2020
  39. 6/9 t4058: explore duplicate tree entry handling in a bit more detailElijah Newren via GitGitGadget, Dec 11, 2020
  40. Ævar Arnfjörð BjarmasonApr 21, 2021
  41. Elijah NewrenApr 21, 2021
  42. 0/9 diffcore-rename improvementsElijah Newren via GitGitGadget, Dec 29, 2020
  43. 1/9 diffcore-rename: rename num_create to num_destinationsElijah Newren via GitGitGadget, Dec 29, 2020
  44. 8/9 diffcore-rename: accelerate rename_dst setupElijah Newren via GitGitGadget, Dec 29, 2020
  45. 7/9 diffcore-rename: simplify and accelerate register_rename_src()Elijah Newren via GitGitGadget, Dec 29, 2020
  46. 2/9 diffcore-rename: avoid usage of global in too_many_rename_candidates()Elijah Newren via GitGitGadget, Dec 29, 2020
  47. 3/9 diffcore-rename: simplify limit checkElijah Newren via GitGitGadget, Dec 29, 2020
  48. Başar UğurNov 9, 2021
  49. Elijah NewrenNov 10, 2021
  50. Başar UğurNov 11, 2021
  51. Elijah NewrenNov 11, 2021
  52. 4/9 diffcore-rename: reduce jumpiness in progress countersElijah Newren via GitGitGadget, Dec 29, 2020
  53. 9/9 diffcore-rename: remove unnecessary duplicate entry checksElijah Newren via GitGitGadget, Dec 29, 2020
  54. 6/9 t4058: explore duplicate tree entry handling in a bit more detailElijah Newren via GitGitGadget, Dec 29, 2020
  55. 5/9 t4058: add more tests and documentation for duplicate tree entry handlingElijah Newren via GitGitGadget, Dec 29, 2020

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.