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

Re: [PATCH 2/3] prune: fix pruning with multiple worktrees and split index

From
Thomas Gummerer <t.gummerer@gmail.com>
Date
Dec 11, 2017, 21:39 UTC
Message-ID
<20171211213948.GC25616@hank>
In-Reply-To
<20171211190946.GB177995@google.com>
On 12/11, Brandon Williams wrote:
Show 25 quoted lines
> On 12/10, Thomas Gummerer wrote:
> > be489d02d2 ("revision.c: --indexed-objects add objects from all
> > worktrees", 2017-08-23) made sure that pruning takes objects from all
> > worktrees into account.
> > 
> > It did that by reading the index of every worktree and adding the
> > necessary index objects to the set of pending objects.  The index is
> > read by read_index_from.  As mentioned in the previous commit,
> > read_index_from depends on the CWD for the location of the split index,
> > and add_index_objects_to_pending doesn't set that before using
> > read_index_from.
> > 
> > Instead of using read_index_from, use repo_read_index, which is aware of
> > the proper paths for the worktree.
> > 
> > This fixes t5304-prune when ran with GIT_TEST_SPLIT_INDEX set.
> > 
> 
> I'm on the fence about this change.  I understand that this will ensure
> that the proper objects aren't pruned when using a split index in the
> presence of worktrees but I think the solution needs to be thought
> through a bit more.
> 
> My big concern right now is the interaction of 'struct worktree's and
> 'struct repository'.  I'll try to highlight my concerns below.
Thanks for the review!  My thoughts on the concerns are below.
Show 47 quoted lines
> > Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
> > ---
> > 
> > This also fixes t7009 when ran with GIT_TEST_SPLIT_INDEX.  I'm not
> > quite sure why it is fixed by this.  Either way I tracked the failure
> > down to f767178a5a ("Merge branch 'jk/no-null-sha1-in-cache-tree'",
> > 2017-05-16).  Maybe Peff has an idea why this fixes that test?
> > 
> >  repository.c | 11 +++++++++++
> >  repository.h |  2 ++
> >  revision.c   | 13 ++++++++-----
> >  3 files changed, 21 insertions(+), 5 deletions(-)
> > 
> > diff --git a/repository.c b/repository.c
> > index 928b1f553d..3c9bfbd1b8 100644
> > --- a/repository.c
> > +++ b/repository.c
> > @@ -2,6 +2,7 @@
> >  #include "repository.h"
> >  #include "config.h"
> >  #include "submodule-config.h"
> > +#include "worktree.h"
> >  
> >  /* The main repository */
> >  static struct repository the_repo = {
> > @@ -146,6 +147,16 @@ int repo_init(struct repository *repo, const char *gitdir, const char *worktree)
> >  	return -1;
> >  }
> >  
> > +/*
> > + * Initialize 'repo' based on the provided worktree
> > + * Return 0 upon success and a non-zero value upon failure.
> > + */
> > +int repo_worktree_init(struct repository *repo, struct worktree *worktree)
> > +{
> > +	return repo_init(repo, get_worktree_git_dir(worktree),
> > +			 worktree->path);
> > +}
> 
> My first concern is the use of 'get_worktree_git_dir()'.  Under the hood
> it calls 'get_git_dir()', 'get_git_common_dir()', and
> 'git_common_path()' which rely on global state as stored in
> 'the_repository'.  So how does one initialize a repository struct (using
> this initializer) using a worktree from a repository other than the
> global 'the_repository' struct?  I'm not sure I have an answer right
> now, but its an issue that needs to be thought through before we head
> down this road.

The main reason for just using 'get_worktree_git_dir()' was because it exists and it does exactly what I needed. If we ever have the need to initialize a repository struct for a worktree from another repository struct, I would imagine we introduce a new function 'repo_get_worktree_git_dir()', which takes a struct repository as input and returns the worktree git dir based on that.

And then we'd have to add a different initializer 'repo_worktree_init_from_repo()' or something like that, where we could initialize a worktree from a repository struct different from 'the_repository'. But maybe there are some complications there that I didn't think about?

> Just thinking to myself, Does it make sense to have worktree's as a
> separate struct or to have them stored in 'struct repository' in some
> way?

I'm not sure I have a good answer for this. Looking at the libgit2 source, which has a repository struct for (I assume at least, I'm not very familiar with the libgit2 source :)), they have a repository struct for each worktree, with a flag specifying whether the struct is for a worktree, or a "normal" git repository/the main worktree.

Obviously that doesn't mean we should do it the same way, but it probably also doesn't hurt to look at prior art.

> Shouldn't a repository struct have a way to interact with all of
> its worktrees?

It could go either way I guess depending on how we want to design it. If we want the repository struct to interact with all worktrees, it seems to me like we would almost need some kind of 'struct super_repository', which then contains a list of 'struct repository's representing each worktree, probably including the main worktree.

But then again in normal operation we probably only want the repository struct for the current repository we're working with, not all of the worktrees. I suspect it's only in some special cases where we want to have all worktrees in memory at once (such as in the prune case).

Or how would you haven envisioned this?
> How would initializing a repository struct for every
> worktree work once we migrate the object store to be stored in 'struct
> repoisotry'?  Shouldn't every worktree share the same object store
> in-memory like they do on-disk?

I haven't thought this far. They probably want to share the same object store, if they all want the object store to be loaded. But we can do that either way, whether we have one 'struct repository' that has links to the worktrees, or we have multiple 'struct repository's, which each have a ref-counted pointer to the object store or something like that.

Show 46 quoted lines
> > +
> >  /*
> >   * Initialize 'submodule' as the submodule given by 'path' in parent repository
> >   * 'superproject'.
> > diff --git a/repository.h b/repository.h
> > index 7f5e24a0a2..2adeb05bf4 100644
> > --- a/repository.h
> > +++ b/repository.h
> > @@ -4,6 +4,7 @@
> >  struct config_set;
> >  struct index_state;
> >  struct submodule_cache;
> > +struct worktree;
> >  
> >  struct repository {
> >  	/* Environment */
> > @@ -87,6 +88,7 @@ extern struct repository *the_repository;
> >  extern void repo_set_gitdir(struct repository *repo, const char *path);
> >  extern void repo_set_worktree(struct repository *repo, const char *path);
> >  extern int repo_init(struct repository *repo, const char *gitdir, const char *worktree);
> > +extern int repo_worktree_init(struct repository *repo, struct worktree *worktree);
> >  extern int repo_submodule_init(struct repository *submodule,
> >  			       struct repository *superproject,
> >  			       const char *path);
> > diff --git a/revision.c b/revision.c
> > index e2e691dd5a..9d8d9b96d1 100644
> > --- a/revision.c
> > +++ b/revision.c
> > @@ -22,6 +22,7 @@
> >  #include "packfile.h"
> >  #include "worktree.h"
> >  #include "argv-array.h"
> > +#include "repository.h"
> >  
> >  volatile show_early_output_fn_t show_early_output;
> >  
> > @@ -1346,15 +1347,17 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)
> >  	worktrees = get_worktrees(0);
> >  	for (p = worktrees; *p; p++) {
> >  		struct worktree *wt = *p;
> > -		struct index_state istate = { NULL };
> > +		struct repository *repo;
> >  
> > +		repo = xmalloc(sizeof(struct repository));
> 
> This was allocated but never freed, was that intentional?
No, that was an oversight, will fix, thanks!
Show 16 quoted lines
> >  		if (wt->is_current)
> >  			continue; /* current index already taken care of */
> > +		if (repo_worktree_init(repo, wt))
> > +			BUG("couldn't initialize repository object from worktree");
> >  
> > -		if (read_index_from(&istate,
> > -				    worktree_git_path(wt, "index")) > 0)
> > -			do_add_index_objects_to_pending(revs, &istate);
> > -		discard_index(&istate);
> > +		if (repo_read_index(repo) > 0)
> > +			do_add_index_objects_to_pending(revs, repo->index);
> > +		discard_index(repo->index);
> 
> One we have separate object stores per-repository how would we handle
> this since this pruning should only work on a single repository's object
> store?

That depends a lot on how we design the object store and how it's held by the repository struct. If we only have one in-memory representation of it, the answer is obvious. If we have multiple in-memory representations of it at the same time, things will get a bit more hairy. But until we have at least a design of how that would look like it's quite hard to tell I'd say.

Show 9 quoted lines
> >  	}
> >  	free_worktrees(worktrees);
> >  }
> > -- 
> > 2.15.1.504.g5279b80103
> > 
> 
> -- 
> Brandon Williams
Previous: Brandon WilliamsNext: Thomas Gummerer
Message 7 of 95 in “fixes for split index mode”
  1. 0/3 fixes for split index modeThomas Gummerer, Dec 10, 2017
  2. 1/3 repository: fix repo_read_index with submodulesThomas Gummerer, Dec 10, 2017
  3. Brandon WilliamsDec 11, 2017
  4. Thomas GummererDec 11, 2017
  5. 2/3 prune: fix pruning with multiple worktrees and split indexThomas Gummerer, Dec 10, 2017
  6. Brandon WilliamsDec 11, 2017
  7. Thomas GummererDec 11, 2017
  8. 3/3 travis: run tests with GIT_TEST_SPLIT_INDEXThomas Gummerer, Dec 10, 2017
  9. Eric SunshineDec 10, 2017
  10. SZEDER GáborDec 11, 2017
  11. Thomas GummererDec 11, 2017
  12. Lars SchneiderDec 12, 2017
  13. Junio C HamanoDec 12, 2017
  14. Thomas GummererDec 12, 2017
  15. Junio C HamanoDec 12, 2017
  16. Thomas GummererDec 13, 2017
  17. Lars SchneiderDec 13, 2017
  18. Junio C HamanoDec 13, 2017
  19. Lars SchneiderDec 13, 2017
  20. Thomas GummererDec 13, 2017
  21. 0/3 fixes for split index modeThomas Gummerer, Dec 17, 2017
  22. 2/3 prune: fix pruning with multiple worktrees and split indexThomas Gummerer, Dec 17, 2017
  23. Brandon WilliamsDec 18, 2017
  24. Thomas GummererJan 3, 2018
  25. Junio C HamanoJan 4, 2018
  26. 1/3 repository: fix repo_read_index with submodulesThomas Gummerer, Dec 17, 2017
  27. Brandon WilliamsDec 18, 2017
  28. Thomas GummererDec 18, 2017
  29. Brandon WilliamsDec 18, 2017
  30. 3/3 travis: run tests with GIT_TEST_SPLIT_INDEXThomas Gummerer, Dec 17, 2017
  31. Lars SchneiderDec 18, 2017
  32. Thomas GummererJan 4, 2018
  33. Lars SchneiderJan 5, 2018
  34. Thomas GummererJan 7, 2018
  35. 0/3 fixes for split index modeThomas Gummerer, Jan 7, 2018
  36. 1/3 read-cache: fix reading the shared index for other reposThomas Gummerer, Jan 7, 2018
  37. Duy NguyenJan 8, 2018
  38. Thomas GummererJan 8, 2018
  39. Thomas GummererJan 13, 2018
  40. Brandon WilliamsJan 8, 2018
  41. Duy NguyenJan 9, 2018
  42. Brandon WilliamsJan 16, 2018
  43. Duy NguyenJan 17, 2018
  44. Brandon WilliamsJan 17, 2018
  45. Jonathan NiederJan 17, 2018
  46. Duy NguyenJan 18, 2018
  47. Junio C HamanoJan 19, 2018
  48. Thomas GummererJan 20, 2018
  49. Junio C HamanoJan 22, 2018
  50. Thomas GummererJan 27, 2018
  51. Junio C HamanoFeb 7, 2018
  52. 2/3 split-index: don't write cache tree with null oid entriesThomas Gummerer, Jan 7, 2018
  53. 3/3 travis: run tests with GIT_TEST_SPLIT_INDEXThomas Gummerer, Jan 7, 2018
  54. 4/3 read-cache: don't try to write index if we can't write shared indexThomas Gummerer, Jan 13, 2018
  55. Duy NguyenJan 14, 2018
  56. 1/3 read-cache.c: change type of "temp" in write_shared_index()Nguyễn Thái Ngọc Duy, Jan 14, 2018
  57. 2/3 read-cache.c: move tempfile creation/cleanup out of write_shared_indexNguyễn Thái Ngọc Duy, Jan 14, 2018
  58. 3/3 read-cache: don't write index twice if we can't write shared indexNguyễn Thái Ngọc Duy, Jan 14, 2018
  59. SZEDER GáborJan 18, 2018
  60. Duy NguyenJan 18, 2018
  61. Jeff KingJan 18, 2018
  62. Duy NguyenJan 18, 2018
  63. Duy NguyenJan 18, 2018
  64. Jeff KingJan 18, 2018
  65. SZEDER GáborJan 18, 2018
  66. Duy NguyenJan 19, 2018
  67. 0/5 Travis CI: don't run the test suite as root in the 32 bit Linux buildSZEDER Gábor, Jan 22, 2018
  68. 2/5 travis-ci: use 'set -e' in the 32 bit Linux build jobSZEDER Gábor, Jan 22, 2018
  69. Jeff KingJan 23, 2018
  70. Jeff KingJan 23, 2018
  71. SZEDER GáborJan 24, 2018
  72. Jeff KingJan 24, 2018
  73. 5/5 travis-ci: don't fail if user already exists on 32 bit Linux build jobSZEDER Gábor, Jan 22, 2018
  74. Jeff KingJan 23, 2018
  75. Duy NguyenJan 24, 2018
  76. SZEDER GáborJan 24, 2018
  77. 1/5 travis-ci: use 'set -x' for the commands under 'su' in the 32 bit Linux buildSZEDER Gábor, Jan 22, 2018
  78. 3/5 travis-ci: don't repeat the path of the cache directorySZEDER Gábor, Jan 22, 2018
  79. Jeff KingJan 23, 2018
  80. SZEDER GáborJan 24, 2018
  81. 4/5 travis-ci: don't run the test suite as root in the 32 bit Linux buildSZEDER Gábor, Jan 22, 2018
  82. Jeff KingJan 23, 2018
  83. SZEDER GáborJan 24, 2018
  84. Jeff KingJan 24, 2018
  85. Jeff KingJan 24, 2018
  86. Jeff KingJan 24, 2018
  87. SZEDER GáborJan 22, 2018
  88. Eric SunshineJan 22, 2018
  89. SZEDER GáborJan 22, 2018
  90. Duy NguyenJan 24, 2018
  91. Lars SchneiderJan 26, 2018
  92. Thomas GummererJan 14, 2018
  93. Thomas GummererJan 18, 2018
  94. Junio C HamanoJan 19, 2018
  95. Thomas GummererJan 19, 2018

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.