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

Re: [PATCH v4 10/19] unpack-trees: add basic support for parallel checkout

From
Christian Couder <christian.couder@gmail.com>
Date
Dec 6, 2020, 11:36 UTC
Message-ID
<CAP8UFD2+6DYpqM5d1-OCMr4hnGksng4R3e23hcQErT4-ff77=Q@mail.gmail.com>
In-Reply-To
<bc8447cd9c106055a715305ab506adc6abae7713.1604521275.git.matheus.bernardino@usp.br>

On Wed, Nov 4, 2020 at 9:34 PM Matheus Tavares <matheus.bernardino@usp.br> wrote:

Show 8 quoted lines
>
> This new interface allows us to enqueue some of the entries being
> checked out to later call write_entry() for them in parallel. For now,
> the parallel checkout machinery is enabled by default and there is no
> user configuration, but run_parallel_checkout() just writes the queued
> entries in sequence (without spawning additional workers). The next
> patch will actually implement the parallelism and, later, we will make
> it configurable.

I would think that it might be more logical to first add a configuration that does nothing, then add writing the queued entries in sequence without parallelism, and then add actual parallelism.

> When there are path collisions among the entries being written (which
> can happen e.g. with case-sensitive files in case-insensitive file
> systems), the parallel checkout code detects the problem and marks the
> item with PC_ITEM_COLLIDED.

Is this needed in this step that only writes the queued entries in sequence without parallelism, or could this be added later, before the step that adds actual parallelism?

Show 7 quoted lines
> Later, these items are sequentially fed to
> checkout_entry() again. This is similar to the way the sequential code
> deals with collisions, overwriting the previously checked out entries
> with the subsequent ones. The only difference is that, when we start
> writing the entries in parallel, we won't be able to determine which of
> the colliding entries will survive on disk (for the sequential
> algorithm, it is always the last one).

So I guess that PC_ITEM_COLLIDED will then be used to decide which entries will not be checked out in parallel?

> I also experimented with the idea of not overwriting colliding entries,
> and it seemed to work well in my simple tests.

There are a number of co-author of this patch, so it's not very clear who "I" is. Maybe:

"The idea of not overwriting colliding entries seemed to work well in simple tests, however ..."

Show 21 quoted lines
> However, because just one
> entry of each colliding group would be actually written, the others
> would have null lstat() fields on the index. This might not be a problem
> by itself, but it could cause performance penalties for subsequent
> commands that need to refresh the index: when the st_size value cached
> is 0, read-cache.c:ie_modified() will go to the filesystem to see if the
> contents match. As mentioned in the function:
>
>     * Immediately after read-tree or update-index --cacheinfo,
>     * the length field is zero, as we have never even read the
>     * lstat(2) information once, and we cannot trust DATA_CHANGED
>     * returned by ie_match_stat() which in turn was returned by
>     * ce_match_stat_basic() to signal that the filesize of the
>     * blob changed.  We have to actually go to the filesystem to
>     * see if the contents match, and if so, should answer "unchanged".
>
> So, if we have N entries in a colliding group and we decide to write and
> lstat() only one of them, every subsequent git-status will have to read,
> convert, and hash the written file N - 1 times, to check that the N - 1
> unwritten entries are dirty. By checking out all colliding entries (like
> the sequential code does), we only pay the overhead once.
Ok.
>  5 files changed, 410 insertions(+), 3 deletions(-)

It looks like a lot of new code in one patch/commit, which is why it might be interesting to split it.

Show 20 quoted lines
> @@ -7,6 +7,7 @@
>  #include "progress.h"
>  #include "fsmonitor.h"
>  #include "entry.h"
> +#include "parallel-checkout.h"
>
>  static void create_directories(const char *path, int path_len,
>                                const struct checkout *state)
> @@ -426,8 +427,17 @@ static void mark_colliding_entries(const struct checkout *state,
>         for (i = 0; i < state->istate->cache_nr; i++) {
>                 struct cache_entry *dup = state->istate->cache[i];
>
> -               if (dup == ce)
> -                       break;
> +               if (dup == ce) {
> +                       /*
> +                        * Parallel checkout creates the files in no particular
> +                        * order. So the other side of the collision may appear
> +                        * after the given cache_entry in the array.
> +                        */

Is it really the case right now that the code creates files in no particular order or will that be the case later when actual parallelism is implemented?

Show 5 quoted lines
> +                       if (parallel_checkout_status() == PC_RUNNING)
> +                               continue;
> +                       else
> +                               break;
> +               }
Show 7 quoted lines
> +struct parallel_checkout_item {
> +       /* pointer to a istate->cache[] entry. Not owned by us. */
> +       struct cache_entry *ce;
> +       struct conv_attrs ca;
> +       struct stat st;
> +       enum pc_item_status status;
> +};

"item" seems not very clear to me. If there is only one parallel_checkout_item for each cache_entry then it might be better to use "parallel_checkout_entry" instead of "parallel_checkout_item".

Show 8 quoted lines
> +enum pc_status {
> +       PC_UNINITIALIZED = 0,
> +       PC_ACCEPTING_ENTRIES,
> +       PC_RUNNING,
> +};
> +
> +enum pc_status parallel_checkout_status(void);
> +void init_parallel_checkout(void);

Maybe a comment to tell what the above function does could be helpful. If I had to guess, I would write something like:

/*
 * Put parallel checkout into the PC_ACCEPTING_ENTRIES state.
 * Should be used only when in the PC_UNINITIALIZED state.
 */
> +/*
> + * Return -1 if parallel checkout is currently not enabled

Is it "enabled" or "initialized" or "configured" here? Does it refer to `enum pc_status` or a config option or something else? Looking at the code, it is testing if the status PC_ACCEPTING_ENTRIES, so perhaps: s/not enabled/not accepting entries/

Show 5 quoted lines
> or if the entry is
> + * not eligible for parallel checkout. Otherwise, enqueue the entry for later
> + * write and return 0.
> + */
> +int enqueue_checkout(struct cache_entry *ce, struct conv_attrs *ca);
Previous: Matheus TavaresNext: Matheus Tavares Bernardino
Message 58 of 93 in “Parallel Checkout (part I)”
  1. 00/19 Parallel Checkout (part I)Matheus Tavares, Oct 29, 2020
  2. 19/19 ci: run test round with parallel-checkout enabledMatheus Tavares, Oct 29, 2020
  3. 18/19 parallel-checkout: add tests related to .gitattributesMatheus Tavares, Oct 29, 2020
  4. 17/19 parallel-checkout: add tests related to clone collisionsMatheus Tavares, Oct 29, 2020
  5. 16/19 parallel-checkout: add tests for basic operationsMatheus Tavares, Oct 29, 2020
  6. 15/19 checkout-index: add parallel checkout supportMatheus Tavares, Oct 29, 2020
  7. 13/19 make_transient_cache_entry(): optionally alloc from mem_poolMatheus Tavares, Oct 29, 2020
  8. 14/19 builtin/checkout.c: complete parallel checkout supportMatheus Tavares, Oct 29, 2020
  9. 10/19 unpack-trees: add basic support for parallel checkoutMatheus Tavares, Oct 29, 2020
  10. Junio C HamanoNov 2, 2020
  11. Matheus Tavares BernardinoNov 3, 2020
  12. 09/19 entry: add checkout_entry_ca() which takes preloaded conv_attrsMatheus Tavares, Oct 29, 2020
  13. Junio C HamanoOct 30, 2020
  14. 11/19 parallel-checkout: make it truly parallelMatheus Tavares, Oct 29, 2020
  15. 12/19 parallel-checkout: support progress displayingMatheus Tavares, Oct 29, 2020
  16. 08/19 entry: move conv_attrs lookup up to checkout_entry()Matheus Tavares, Oct 29, 2020
  17. Junio C HamanoOct 30, 2020
  18. 05/19 entry: extract a header file for entry.c functionsMatheus Tavares, Oct 29, 2020
  19. Junio C HamanoOct 30, 2020
  20. 07/19 entry: extract cache_entry update from write_entry()Matheus Tavares, Oct 29, 2020
  21. 06/19 entry: make fstat_output() and read_blob_entry() publicMatheus Tavares, Oct 29, 2020
  22. 03/19 convert: add get_stream_filter_ca() variantMatheus Tavares, Oct 29, 2020
  23. Junio C HamanoOct 29, 2020
  24. 04/19 convert: add conv_attrs classificationMatheus Tavares, Oct 29, 2020
  25. Junio C HamanoOct 29, 2020
  26. 02/19 convert: add [async_]convert_to_working_tree_ca() variantsMatheus Tavares, Oct 29, 2020
  27. Junio C HamanoOct 29, 2020
  28. 01/19 convert: make convert_attrs() and convert structs publicMatheus Tavares, Oct 29, 2020
  29. Junio C HamanoOct 29, 2020
  30. Matheus Tavares BernardinoOct 30, 2020
  31. Junio C HamanoOct 30, 2020
  32. Junio C HamanoOct 29, 2020
  33. Jeff HostetlerOct 30, 2020
  34. 00/19 Parallel Checkout (part I)Matheus Tavares, Nov 4, 2020
  35. 01/19 convert: make convert_attrs() and convert structs publicMatheus Tavares, Nov 4, 2020
  36. Christian CouderDec 5, 2020
  37. Matheus Tavares BernardinoDec 5, 2020
  38. 02/19 convert: add [async_]convert_to_working_tree_ca() variantsMatheus Tavares, Nov 4, 2020
  39. Christian CouderDec 5, 2020
  40. Matheus Tavares BernardinoDec 5, 2020
  41. 03/19 convert: add get_stream_filter_ca() variantMatheus Tavares, Nov 4, 2020
  42. Christian CouderDec 5, 2020
  43. 04/19 convert: add conv_attrs classificationMatheus Tavares, Nov 4, 2020
  44. Christian CouderDec 5, 2020
  45. Matheus Tavares BernardinoDec 5, 2020
  46. 05/19 entry: extract a header file for entry.c functionsMatheus Tavares, Nov 4, 2020
  47. Christian CouderDec 6, 2020
  48. 06/19 entry: make fstat_output() and read_blob_entry() publicMatheus Tavares, Nov 4, 2020
  49. 07/19 entry: extract cache_entry update from write_entry()Matheus Tavares, Nov 4, 2020
  50. Christian CouderDec 6, 2020
  51. 08/19 entry: move conv_attrs lookup up to checkout_entry()Matheus Tavares, Nov 4, 2020
  52. Christian CouderDec 6, 2020
  53. Matheus Tavares BernardinoDec 7, 2020
  54. 09/19 entry: add checkout_entry_ca() which takes preloaded conv_attrsMatheus Tavares, Nov 4, 2020
  55. Christian CouderDec 6, 2020
  56. Matheus Tavares BernardinoDec 7, 2020
  57. 10/19 unpack-trees: add basic support for parallel checkoutMatheus Tavares, Nov 4, 2020
  58. Christian CouderDec 6, 2020
  59. Matheus Tavares BernardinoDec 7, 2020
  60. 11/19 parallel-checkout: make it truly parallelMatheus Tavares, Nov 4, 2020
  61. Emily ShafferDec 16, 2020
  62. Matheus Tavares BernardinoDec 17, 2020
  63. 12/19 parallel-checkout: support progress displayingMatheus Tavares, Nov 4, 2020
  64. 13/19 make_transient_cache_entry(): optionally alloc from mem_poolMatheus Tavares, Nov 4, 2020
  65. 15/19 checkout-index: add parallel checkout supportMatheus Tavares, Nov 4, 2020
  66. 17/19 parallel-checkout: add tests related to clone collisionsMatheus Tavares, Nov 4, 2020
  67. 18/19 parallel-checkout: add tests related to .gitattributesMatheus Tavares, Nov 4, 2020
  68. 19/19 ci: run test round with parallel-checkout enabledMatheus Tavares, Nov 4, 2020
  69. 16/19 parallel-checkout: add tests for basic operationsMatheus Tavares, Nov 4, 2020
  70. 14/19 builtin/checkout.c: complete parallel checkout supportMatheus Tavares, Nov 4, 2020
  71. 0/9 Parallel Checkout (part I)Matheus Tavares, Dec 16, 2020
  72. 1/9 convert: make convert_attrs() and convert structs publicMatheus Tavares, Dec 16, 2020
  73. 2/9 convert: add [async_]convert_to_working_tree_ca() variantsMatheus Tavares, Dec 16, 2020
  74. 3/9 convert: add get_stream_filter_ca() variantMatheus Tavares, Dec 16, 2020
  75. 5/9 entry: extract a header file for entry.c functionsMatheus Tavares, Dec 16, 2020
  76. 6/9 entry: make fstat_output() and read_blob_entry() publicMatheus Tavares, Dec 16, 2020
  77. 4/9 convert: add classification for conv_attrs structMatheus Tavares, Dec 16, 2020
  78. 7/9 entry: extract update_ce_after_write() from write_entry()Matheus Tavares, Dec 16, 2020
  79. 9/9 entry: add checkout_entry_ca() taking preloaded conv_attrsMatheus Tavares, Dec 16, 2020
  80. 8/9 entry: move conv_attrs lookup up to checkout_entry()Matheus Tavares, Dec 16, 2020
  81. Christian CouderDec 16, 2020
  82. Junio C HamanoDec 17, 2020
  83. 0/9 Parallel Checkout (part 1)Matheus Tavares, Mar 23, 2021
  84. 1/9 convert: make convert_attrs() and convert structs publicMatheus Tavares, Mar 23, 2021
  85. 2/9 convert: add [async_]convert_to_working_tree_ca() variantsMatheus Tavares, Mar 23, 2021
  86. 4/9 convert: add classification for conv_attrs structMatheus Tavares, Mar 23, 2021
  87. 3/9 convert: add get_stream_filter_ca() variantMatheus Tavares, Mar 23, 2021
  88. 6/9 entry: make fstat_output() and read_blob_entry() publicMatheus Tavares, Mar 23, 2021
  89. 8/9 entry: move conv_attrs lookup up to checkout_entry()Matheus Tavares, Mar 23, 2021
  90. 5/9 entry: extract a header file for entry.c functionsMatheus Tavares, Mar 23, 2021
  91. 9/9 entry: add checkout_entry_ca() taking preloaded conv_attrsMatheus Tavares, Mar 23, 2021
  92. 7/9 entry: extract update_ce_after_write() from write_entry()Matheus Tavares, Mar 23, 2021
  93. Junio C HamanoMar 23, 2021

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.